mirror of
https://github.com/verilator/verilator.git
synced 2026-10-02 16:13:34 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4100f20a69 | ||
|
|
bedf946fb2 | ||
|
|
b9e67157c6 | ||
|
|
b30b2a183b | ||
|
|
9ab3bcdde3 | ||
|
|
5df3bbe188 | ||
|
|
8cf12416c0 | ||
|
|
b7c2c83c88 | ||
|
|
3b6da93331 | ||
|
|
b4642d3fd4 | ||
|
|
88a2b0b911 | ||
|
|
954e127f1d | ||
|
|
7654add5e5 | ||
|
|
85a37ea53f | ||
|
|
b337acebcc | ||
|
|
fb9ca54c95 | ||
|
|
1a15d41523 | ||
|
|
e378cc5791 | ||
|
|
748c189c79 | ||
|
|
b89be6c4b9 | ||
|
|
df207807b6 | ||
|
|
1f2b40cff1 | ||
|
|
734400fd37 | ||
|
|
f19979d928 | ||
|
|
19be7a53da | ||
|
|
e56af34fb0 | ||
|
|
7737aa20e8 | ||
|
|
ead046201c | ||
|
|
0aa7c3f659 | ||
|
|
4aa7222022 | ||
|
|
86e3c78776 | ||
|
|
40076287ea | ||
|
|
ca81db8edf | ||
|
|
ae68a80e98 | ||
|
|
beb7c58375 | ||
|
|
e080b9d565 | ||
|
|
ca2db37039 | ||
|
|
194825f78e | ||
|
|
55bd765ea0 | ||
|
|
b03d61e2cf | ||
|
|
6fc0e5167b | ||
|
|
0065be011f | ||
|
|
3f7cbce58c | ||
|
|
246b62e322 | ||
|
|
7c2fdd1ee9 | ||
|
|
f77aa2623c | ||
|
|
20847a3ff5 | ||
|
|
eb6d42acf9 | ||
|
|
094d676a8b | ||
|
|
71306ceb1d | ||
|
|
8bbfc7fc22 | ||
|
|
19baba12b1 | ||
|
|
15b8819136 | ||
|
|
3fae8ade05 | ||
|
|
f9bbf31d65 | ||
|
|
df1da3dda9 | ||
|
|
c83f2a4abd | ||
|
|
ad53833040 | ||
|
|
bc8c85668a | ||
|
|
d12a3dde45 | ||
|
|
301c878c0f | ||
|
|
bd55bfa071 | ||
|
|
6d2f09b579 | ||
|
|
4bfea7f54d | ||
|
|
55906486d8 | ||
|
|
d5478e6e08 | ||
|
|
d88d85c172 | ||
|
|
59c3c536c7 | ||
|
|
a007458cb8 | ||
|
|
d051912f21 | ||
|
|
a547158a50 | ||
|
|
95f2351aa0 | ||
|
|
698aaffb0b | ||
|
|
73eccecbf8 | ||
|
|
ae4a261463 | ||
|
|
c9f0d0cec2 | ||
|
|
4fa1e45d45 | ||
|
|
1b3d252bfe | ||
|
|
a9ba4a9fcd | ||
|
|
7f49619875 | ||
|
|
696660639a | ||
|
|
da4323062d | ||
|
|
a901e171b2 | ||
|
|
6e41d532fe | ||
|
|
4fc78ffb58 | ||
|
|
8137f41fc3 | ||
|
|
2e9471797d | ||
|
|
344248cea0 | ||
|
|
2789e3dba5 | ||
|
|
cca759a41e | ||
|
|
4f7b3d8882 | ||
|
|
2b330b78b7 | ||
|
|
d47ca1912b | ||
|
|
3fd2108b10 | ||
|
|
96e2a407f4 | ||
|
|
cdf18c96f4 | ||
|
|
53acaa05b8 | ||
|
|
fb85679068 | ||
|
|
9558e14479 | ||
|
|
4af0af93bf | ||
|
|
df4bc950fe | ||
|
|
250394f72b | ||
|
|
ca83fd6dc1 | ||
|
|
d5e9e7cd2b | ||
|
|
9a96f621ef | ||
|
|
5d7ce096c6 | ||
|
|
c9f8109c06 | ||
|
|
a20b4f2864 | ||
|
|
44a19d2a0a | ||
|
|
02f3beb8db | ||
|
|
3269cc3d90 | ||
|
|
fb70a1f4ab | ||
|
|
df0aa483ce | ||
|
|
c83f12a55c | ||
|
|
9704f59566 | ||
|
|
2923893d34 | ||
|
|
890dab0742 | ||
|
|
607e26b041 | ||
|
|
ea75290f65 | ||
|
|
a176054118 | ||
|
|
9a697dc5f5 | ||
|
|
cfdb852843 | ||
|
|
2e67a91982 | ||
|
|
074ca9330d | ||
|
|
f0d7cdcb20 |
@@ -24,6 +24,8 @@ src/Makefile_obj$
|
||||
include/verilated.mk$
|
||||
config.cache$
|
||||
config.status$
|
||||
verilator.log
|
||||
verilator.tex
|
||||
verilator_bin.*
|
||||
.vcsmx_rebuild$
|
||||
autom4te\.cache/
|
||||
|
||||
+36
-20
@@ -88,7 +88,10 @@ pkgdatadir = @pkgdatadir@
|
||||
datarootdir = @datarootdir@
|
||||
|
||||
# Compile options
|
||||
CFG_WITH_CCWARN = @CFG_WITH_CCWARN@
|
||||
CFG_WITH_DEFENV = @CFG_WITH_DEFENV@
|
||||
CFG_WITH_LONGTESTS = @CFG_WITH_LONGTESTS@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
|
||||
#### End of system configuration section. ####
|
||||
######################################################################
|
||||
@@ -101,8 +104,6 @@ INFOS = README internals.txt verilator.txt verilator.html verilator.1 verilator.
|
||||
|
||||
# Files that can be generated, but should be up to date for a distribution.
|
||||
DISTDEP = info Makefile
|
||||
# Files to distribute.
|
||||
DISTBIN = $(wildcard bin/verilator-*)
|
||||
|
||||
DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING COPYING.LESSER \
|
||||
*.in *.ac \
|
||||
@@ -129,7 +130,6 @@ DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING COPYING.LESSER \
|
||||
test_regress/t/*.pl \
|
||||
test_regress/t/*.pf \
|
||||
test_regress/t/*.v* \
|
||||
verilator.* \
|
||||
|
||||
INST_PROJ_FILES = \
|
||||
bin/verilator \
|
||||
@@ -171,7 +171,7 @@ msg_test:
|
||||
@echo
|
||||
|
||||
.PHONY:test
|
||||
ifeq ($(VERILATOR_AUTHOR_SITE),1) # Local... Else don't burden users
|
||||
ifeq ($(CFG_WITH_LONGTESTS),yes) # Local... Else don't burden users
|
||||
test: test_vcs test_c test_sc test_sp test_verilated test_regress
|
||||
else
|
||||
test: test_c test_sc test_sp
|
||||
@@ -203,17 +203,18 @@ test_regress: all_nomsg
|
||||
info: $(INFOS)
|
||||
|
||||
# Use --no-split to avoid creating filenames > 14 chars.
|
||||
verilator.1: bin/verilator
|
||||
verilator.1: ${srcdir}/bin/verilator
|
||||
pod2man $< $@
|
||||
|
||||
verilator.txt: bin/verilator
|
||||
verilator.txt: ${srcdir}/bin/verilator
|
||||
$(POD2TEXT) $< $@
|
||||
|
||||
verilator.html: bin/verilator
|
||||
verilator.html: ${srcdir}/bin/verilator
|
||||
pod2html $< >$@
|
||||
|
||||
verilator.pdf: bin/verilator $(DISTCONFIG)
|
||||
pod2latex --full --out verilator.tex bin/verilator
|
||||
# PDF needs DIST variables; but having configure.ac as dependency isn't detected
|
||||
verilator.pdf: ${srcdir}/bin/verilator Makefile
|
||||
pod2latex --full --out verilator.tex ${srcdir}/bin/verilator
|
||||
cat < verilator.tex \
|
||||
| sed 's/\\begin{document}/\\usepackage[left=1.7in,right=1.7in,top=1.3in,bottom=1.3in]{geometry}\n\\begin{document}/' \
|
||||
| sed 's/\\begin{document}/\\usepackage[pdftex,bookmarks=true,bookmarksnumbered=true,hypertexnames=false,breaklinks=true,linkbordercolor={0 0 1}]{hyperref}\n\\begin{document}/' \
|
||||
@@ -257,7 +258,7 @@ 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/*.[chv]* test_sp/Makefile test_sp/Makefile_obj \
|
||||
test_sp/Makefile test_sp/Makefile_obj \
|
||||
|
||||
installbin:
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(bindir)
|
||||
@@ -268,9 +269,11 @@ installbin:
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/bin
|
||||
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_includer $(DESTDIR)$(pkgdatadir)/bin/verilator_includer )
|
||||
|
||||
# Man files can either be part of the original kit, or built in current directory
|
||||
# So important we use $< so VPATH is searched
|
||||
installman: $(VL_INST_MAN_FILES)
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(mandir)/man1
|
||||
for p in $(VL_INST_MAN_FILES) ; do \
|
||||
for p in $< ; do \
|
||||
$(INSTALL_DATA) $$p $(DESTDIR)$(mandir)/man1/$$p; \
|
||||
done
|
||||
|
||||
@@ -315,6 +318,8 @@ install: all_nomsg installbin installman installdata install-msg
|
||||
install-here: installman ftp
|
||||
|
||||
ifeq ($(VERILATOR_AUTHOR_SITE),1) # Local... Else don't burden users
|
||||
DISTNAMEREV = $(shell sed -e '/DTVERSION/!d' -e 's/.*verilator_\([^"]*\).*/\1/' -e q ${srcdir}/src/config_rev.h)
|
||||
|
||||
DIRPROJECT := $(shell project_dir --project)
|
||||
VERILATOR_CAD_DIR = $(CAD_DIR)/verilator/$(DISTNAMEREV)/$(DIRPROJECT_ARCH)
|
||||
INST_PROJ_CVS = cp_if_cvs_diff
|
||||
@@ -323,7 +328,7 @@ install-project: dist
|
||||
@echo "Install-project to $(DIRPROJECT)"
|
||||
strip verilator_bin*
|
||||
$(MAKE) install-project-quick
|
||||
for p in verilator.1 ; do \
|
||||
for p in $(VL_INST_MAN_FILES) ; do \
|
||||
$(INSTALL_DATA) $$p $(DIRPROJECT_PREFIX)/man/man1/$$p; \
|
||||
done
|
||||
$(INST_PROJ_CVS) $(DISTNAME).tgz $(DIRPROJECT)/hw/utils/verilator/verilator.tgz
|
||||
@@ -347,7 +352,7 @@ install-cadtools: dist
|
||||
strip verilator_bin*
|
||||
$(MAKE) install-cadtools-quick
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(VERILATOR_CAD_DIR)/man/man1
|
||||
for p in verilator.1 ; do \
|
||||
for p in $(VL_INST_MAN_FILES) ; do \
|
||||
$(INSTALL_DATA) $$p $(VERILATOR_CAD_DIR)/man/man1/$$p; \
|
||||
done
|
||||
$(INST_PROJ_CVS) $(DISTNAME).tgz $(VERILATOR_CAD_DIR)/verilator.tgz
|
||||
@@ -371,6 +376,15 @@ endif
|
||||
# VERILATOR_AUTHOR_SITE
|
||||
endif
|
||||
|
||||
CPPCHECK = cppcheck
|
||||
CPPCHECK_FLAGS = --enable=all --inline-suppr --suppress=unusedScopedObject
|
||||
CPPCHECK_CPP = $(wildcard $(srcdir)/include/*.cpp $(srcdir)/src/*.cpp)
|
||||
CPPCHECK_DEP = $(subst .cpp,.cppcheck,$(CPPCHECK_CPP))
|
||||
|
||||
cppcheck: $(CPPCHECK_DEP)
|
||||
%.cppcheck: %.cpp
|
||||
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -I$(srcdir)/include -I$(srcdir)/src $<
|
||||
|
||||
ftp: info
|
||||
|
||||
install-msg:
|
||||
@@ -391,8 +405,13 @@ Makefile: Makefile.in config.status $(IN_WILD)
|
||||
src/Makefile: src/Makefile.in Makefile
|
||||
config.status: configure
|
||||
./config.status --recheck
|
||||
|
||||
configure: configure.ac
|
||||
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
|
||||
autoconf --warnings=all
|
||||
else
|
||||
autoconf
|
||||
endif
|
||||
|
||||
maintainer-clean::
|
||||
@echo "This command is intended for maintainers to use;"
|
||||
@@ -433,15 +452,12 @@ dist-file-list:
|
||||
######################################################################
|
||||
# Distributions
|
||||
|
||||
DISTCONFIG = ${srcdir}/src/config_build.h.in
|
||||
|
||||
DISTTITLE := $(shell sed -e '/DTVERSION/!d' -e 's/[^0-9]*\([0-9.a-z]*\).*/verilator-\1/' -e 's/v/V/' -e q $(DISTCONFIG))
|
||||
DISTNAME := $(shell sed -e '/DTVERSION/!d' -e 's/[^0-9]*\([0-9.a-z]*\).*/verilator-\1/' -e q $(DISTCONFIG))
|
||||
DISTDATEPRE := $(shell sed -e '/DTVERSION/!d' -e 's/.*\([1-2][0-9][0-9][0-9].[0-9]*[0-9].[0-9]*[0-9]\).*/\1/' -e q $(DISTCONFIG))
|
||||
DISTNAMEREV := $(shell sed -e '/DTVERSION/!d' -e 's/.*verilator_\([^"]*\).*/\1/' -e q src/config_rev.h)
|
||||
DISTTITLE := Verilator $(word 1,$(PACKAGE_VERSION))
|
||||
DISTNAME := verilator-$(word 1,$(PACKAGE_VERSION))
|
||||
DISTDATEPRE := $(word 2,$(PACKAGE_VERSION))
|
||||
DISTDATE := $(subst /,-,$(DISTDATEPRE))
|
||||
|
||||
DISTTAGNAME := $(subst .,_,$(subst -,_,$(DISTNAME)))
|
||||
DISTDATE := $(subst /,-,$(DISTDATEPRE))
|
||||
|
||||
tag:
|
||||
svnorcvs tag $(DISTTAGNAME)
|
||||
|
||||
+217
-87
@@ -70,7 +70,7 @@ if (! GetOptions (
|
||||
# "version!" => \&version, # Also passthru'ed
|
||||
# Switches
|
||||
"gdb=s" => \$opt_gdb, # Undocumented debugging
|
||||
"gdbbt!" => \$opt_gdbbt, # Undocumented debugging
|
||||
"gdbbt!" => \$opt_gdbbt,
|
||||
# Additional parameters
|
||||
"<>" => sub {}, # Ignored
|
||||
)) {
|
||||
@@ -99,7 +99,7 @@ if ($opt_gdbbt && !$opt_gdb && $Debug) {
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
sub usage {
|
||||
pod2usage(-exitstatus=>2, -verbose=>2);
|
||||
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
|
||||
}
|
||||
|
||||
sub debug {
|
||||
@@ -125,7 +125,14 @@ sub verilator_bin {
|
||||
$bin = "$dir/$basename"; # From pointing to kit directory
|
||||
}
|
||||
} else {
|
||||
$bin = $basename;
|
||||
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;
|
||||
}
|
||||
@@ -196,8 +203,9 @@ Verilator - Convert Verilog code to C++/SystemC
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Verilator converts synthesizable (not behavioral) Verilog code, plus some
|
||||
Synthesis, SystemVerilog and Sugar/PSL 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 and Sugar/PSL
|
||||
assertions, into C++, SystemC or SystemPerl code. It is not a complete
|
||||
simulator, just a compiler.
|
||||
|
||||
Verilator is invoked with parameters similar to GCC, Cadence
|
||||
Verilog-XL/NC-Verilog, or Synopsys's VCS. It reads the specified Verilog
|
||||
@@ -252,7 +260,7 @@ descriptions in the next sections for more information.
|
||||
--exe Link to create executable
|
||||
-F <file> Parse options from a file, relatively
|
||||
-f <file> Parse options from a file
|
||||
--gdbbt Run Verilator under GDB for backtrace
|
||||
--gdbbt Run Verilator under GDB for backtrace
|
||||
--help Display this help
|
||||
-I<dir> Directory to search for includes
|
||||
--if-depth <value> Tune IFDEPTH warning
|
||||
@@ -268,7 +276,7 @@ descriptions in the next sections for more information.
|
||||
--MP Create phony dependency targets
|
||||
--Mdir <directory> Name of output object directory
|
||||
--mod-prefix <topname> Name to prepend to lower classes
|
||||
--no-pins64 Don't use uint64_t's for 33-64 bit sigs
|
||||
--no-pins64 Don't use vluint64_t's for 33-64 bit sigs
|
||||
--no-skip-identical Disable skipping identical output
|
||||
+notimingchecks Ignored
|
||||
-O0 Disable optimizations
|
||||
@@ -292,6 +300,8 @@ descriptions in the next sections for more information.
|
||||
--top-module <topname> Name of top level input module
|
||||
--trace Enable waveform creation
|
||||
--trace-depth <levels> Depth of tracing
|
||||
--trace-max-array <depth> Maximum bit width for tracing
|
||||
--trace-max-width <width> Maximum array depth for tracing
|
||||
--trace-underscore Enable tracing of _signals
|
||||
-U<var> Undefine preprocessor define
|
||||
--unroll-count <loops> Tune maximum loop iterations
|
||||
@@ -304,6 +314,7 @@ descriptions in the next sections for more information.
|
||||
-Wno-<message> Disable warning
|
||||
-Wno-lint Disable all lint warnings
|
||||
-Wno-style Disable all style warnings
|
||||
-Wno-fatal Disable fatal exit on warnings
|
||||
-x-assign <mode> Initially assign Xs to this value
|
||||
-y <dir> Directory to search for modules
|
||||
|
||||
@@ -534,14 +545,18 @@ the command line that implement the main loop for your simulation.
|
||||
|
||||
Read the specified file, and act as if all text inside it was specified as
|
||||
command line parameters. Any relative paths are relative to the directory
|
||||
containing the specified file. Note -F is fairly standard across Verilog
|
||||
tools.
|
||||
containing the specified file. See also -f. Note -F is fairly standard
|
||||
across Verilog tools.
|
||||
|
||||
=item -f I<file>
|
||||
|
||||
Read the specified file, and act as if all text inside it was specified as
|
||||
command line parameters. Any relative paths are relative to the current
|
||||
directory. Note -f is fairly standard across Verilog tools.
|
||||
directory. See also -F. Note -f is fairly standard across Verilog tools.
|
||||
|
||||
The file may contain // comments which are ignored to the end of the line.
|
||||
Any $VAR, $(VAR), or ${VAR} will be replaced with the specified environment
|
||||
variable.
|
||||
|
||||
=item --gdbbt
|
||||
|
||||
@@ -555,10 +570,7 @@ Displays this message and program version and exits.
|
||||
|
||||
=item -II<dir>
|
||||
|
||||
Add the directory to the list of directories that should be searched for
|
||||
include directories or libraries. Same as +incdir and -y; +incdir and -y
|
||||
are fairly standard across Verilog tools while -I is an alias for GCC
|
||||
compatibility.
|
||||
See -y.
|
||||
|
||||
=item --if-depth I<value>
|
||||
|
||||
@@ -567,10 +579,7 @@ defaults to 0 which disables this warning.
|
||||
|
||||
=item +incdir+I<dir>
|
||||
|
||||
Add the directory to the list of directories that should be searched for
|
||||
include directories or libraries. Same as -I and -y; +incdir and -y
|
||||
are fairly standard across Verilog tools while -I is an alias for GCC
|
||||
compatibility.
|
||||
See -y.
|
||||
|
||||
=item --inhibit-sim
|
||||
|
||||
@@ -602,15 +611,19 @@ in the Make variable LDLIBS, not LDFLAGS.)
|
||||
|
||||
Select the language to be used when first processing each Verilog file.
|
||||
The language value must be "1364-1995", "1364-2001", "1364-2001",
|
||||
"1364-2005", or "1800-2005". This should only be used for legacy code, as
|
||||
the preferable option is to edit the code to repair new keywords, or add
|
||||
appropriate `begin_keywords.
|
||||
"1364-2005", "1800-2005", "VAMS-2.3". Verilator also allows the
|
||||
non-standard "1800+VAMS" to allow both the full SystemVerilog and
|
||||
Verilog-AMS keywords.
|
||||
|
||||
The --language flag is only recommended for legacy code, as the preferable
|
||||
option is to edit the code to repair new keywords, or add appropriate
|
||||
`begin_keywords.
|
||||
|
||||
=item +libext+I<ext>+I<ext>...
|
||||
|
||||
Specify the extensions that should be used for finding modules. If for
|
||||
example module I<x> is referenced, look in I<x>.I<ext>. Note +libext+ is
|
||||
fairly standard across Verilog tools.
|
||||
fairly standard across Verilog tools. Defaults to .v and .sv.
|
||||
|
||||
=item --lint-only
|
||||
|
||||
@@ -706,9 +719,10 @@ Backward compatible alias for "--pins-bv 65". Note that's a 65, not a 64.
|
||||
=item --pins-bv I<width>
|
||||
|
||||
Specifies SystemC inputs/outputs of greater than or equal to I<width> bits
|
||||
wide should use sc_bv's instead of uint32/uint64_t's. The default is
|
||||
wide should use sc_bv's instead of uint32/vluint64_t's. The default is
|
||||
"--pins-bv 65". Versions before Verilator 3.671 defaulted to "--pins-bv
|
||||
33". The more sc_bv is used, the worse for performance.
|
||||
33". The more sc_bv is used, the worse for performance. Use the
|
||||
"/*verilator sc_bv*/" attribute to select specific ports to be sc_bv.
|
||||
|
||||
=item --pins-uint8
|
||||
|
||||
@@ -816,6 +830,18 @@ Specify the number of levels deep to enable tracing, for example
|
||||
entire model. Using a small number will decrease visibility, but greatly
|
||||
improve runtime and trace file size.
|
||||
|
||||
=item --trace-max-array I<depth>
|
||||
|
||||
Rarely needed. Specify the maximum array depth of a signal that may be
|
||||
traced. Defaults to 32, as tracing large arrays may greatly slow traced
|
||||
simulations.
|
||||
|
||||
=item --trace-max-width I<width>
|
||||
|
||||
Rarely needed. Specify the maximum bit width of a signal that may be
|
||||
traced. Defaults to 256, as tracing large vectors may greatly slow traced
|
||||
simulations.
|
||||
|
||||
=item --trace-underscore
|
||||
|
||||
Enable tracing of signals that start with an underscore. Normally, these
|
||||
@@ -865,11 +891,11 @@ example C<-Werror-NOUNOPTFLAT>.
|
||||
|
||||
=item -Wfuture-I<message>
|
||||
|
||||
Suppress unknown Verilator comments or warning messages with the given
|
||||
message code. This is used to allow code written with pragmas for a later
|
||||
version of Verilator to run under a older version; add -Wfuture- arguments
|
||||
for each message code or comment that the new version supports which the
|
||||
older version does not support.
|
||||
Rarely needed. Suppress unknown Verilator comments or warning messages
|
||||
with the given message code. This is used to allow code written with
|
||||
pragmas for a later version of Verilator to run under a older version; add
|
||||
-Wfuture- arguments for each message code or comment that the new version
|
||||
supports which the older version does not support.
|
||||
|
||||
=item -Wno-I<message>
|
||||
|
||||
@@ -894,6 +920,14 @@ already disabled). This is equivalent to "-Wno-DECLFILENAME -Wno-DEFPARAM
|
||||
-Wno-INCABSPATH -Wno-SYNCASYNCNET -Wno-UNDRIVEN -Wno-UNUSED
|
||||
-Wno-VARHIDDEN".
|
||||
|
||||
=item -Wno-fatal
|
||||
|
||||
When warnings are detected, print them, but do not exit the simulator.
|
||||
|
||||
Having warning messages in builds is sloppy. It is strongly recommended
|
||||
you cleanup your code, use inline lint_off, or use -Wno-... flags rather
|
||||
than using this option.
|
||||
|
||||
=item -Wwarn-I<message>
|
||||
|
||||
Enables the specified warning message.
|
||||
@@ -903,14 +937,14 @@ Enables the specified warning message.
|
||||
Enable all lint related warning messages (note by default they are already
|
||||
enabled), but do not affect style messages. This is equivalent to
|
||||
"-Wwarn-CASEINCOMPLETE -Wwarn-CASEOVERLAP -Wwarn-CASEX -Wwarn-CASEWITHX
|
||||
-Wwarn-CMPCONST -Wwarn-IMPLICIT -Wwarn-LITENDIAN -Wwarn-UNSIGNED
|
||||
-Wwarn-WIDTH".
|
||||
-Wwarn-CMPCONST -Wwarn-IMPLICIT -Wwarn-LITENDIAN -Wwarn-REALCVT
|
||||
-Wwarn-UNSIGNED -Wwarn-WIDTH".
|
||||
|
||||
=item -Wwarn-style
|
||||
|
||||
Enable all code style related warning messages. This is equivalent to
|
||||
"-Wwarn-DECLFILENAME -Wwarn-DEFPARAM -Wwarn-INCABSPATH -Wwarn-SYNCASYNCNET
|
||||
-Wwarn-UNDRIVEN -Wwarn-UNUSED -Wwarn-VARHIDDEN".
|
||||
"-Wwarn ASSIGNDLY -Wwarn-DECLFILENAME -Wwarn-DEFPARAM -Wwarn-INCABSPATH
|
||||
-Wwarn-SYNCASYNCNET -Wwarn-UNDRIVEN -Wwarn-UNUSED -Wwarn-VARHIDDEN".
|
||||
|
||||
=item -x-assign 0
|
||||
|
||||
@@ -938,9 +972,14 @@ enable rerunning with that same seed so you can reproduce bugs.
|
||||
=item -y I<dir>
|
||||
|
||||
Add the directory to the list of directories that should be searched for
|
||||
include directories or libraries. Same as +incdir and -I; +incdir and +y
|
||||
are fairly standard across Verilog tools while -I is an alias for GCC
|
||||
compatibility.
|
||||
include files or libraries. The three flags -y, +incdir and -I have
|
||||
similar effect; +incdir and +y are fairly standard across Verilog tools while -I
|
||||
is an alias for GCC compatibility.
|
||||
|
||||
Verilator defaults to the current directory ("-y .") and any specified
|
||||
--Mdir, though these default paths are used after any user specified
|
||||
directories. This allows '-y "$(pwd)"' to be used if absolute filenames
|
||||
are desired for error messages instead of relative filenames.
|
||||
|
||||
=back
|
||||
|
||||
@@ -954,7 +993,7 @@ We'll compile this example into C++.
|
||||
|
||||
cat <<EOF >our.v
|
||||
module our;
|
||||
initial begin \$display("Hello World"); \$finish; end
|
||||
initial begin $display("Hello World"); $finish; end
|
||||
endmodule
|
||||
EOF
|
||||
|
||||
@@ -976,7 +1015,7 @@ your operating system (as an RPM), first you need to point to the kit:
|
||||
export PATH=$VERILATOR_ROOT/bin:$PATH
|
||||
|
||||
Now we run Verilator on our little example.
|
||||
|
||||
|
||||
verilator -Wall --cc our.v --exe sim_main.cpp
|
||||
|
||||
We can see the source code under the "obj_dir" directory. See the FILES
|
||||
@@ -1019,7 +1058,7 @@ This is an example similar to the above, but using SystemPerl.
|
||||
module our (clk);
|
||||
input clk; // Clock is required to get initial activation
|
||||
always @ (posedge clk)
|
||||
begin \$display("Hello World"); \$finish; end
|
||||
begin $display("Hello World"); $finish; end
|
||||
endmodule
|
||||
EOF
|
||||
|
||||
@@ -1199,11 +1238,6 @@ all runs of the C++ Compiler. For example, "objcache --read --write", or
|
||||
"ccache". If using distcc, it would generally be run under either objcache
|
||||
or ccache; see the documentation for those programs.
|
||||
|
||||
=item OBJCACHE_JOBS
|
||||
|
||||
Optionally lists Make flags that specifies parallel make jobs. For example
|
||||
a 4 CPU system may use "-j 6" to request 6 parallel compiles when making.
|
||||
|
||||
=item SYSTEMC
|
||||
|
||||
Required for SystemC output mode. If set, specifies the directory
|
||||
@@ -1279,10 +1313,13 @@ example:
|
||||
|
||||
Vtop *top; // Instantiation of module
|
||||
|
||||
unsigned int main_time = 0; // Current simulation time
|
||||
vluint64_t main_time = 0; // Current simulation time
|
||||
// This is a 64-bit integer to reduce wrap over issues and
|
||||
// allow modulus. You can also use a double, if you wish.
|
||||
|
||||
double sc_time_stamp () { // Called by $time in Verilog
|
||||
return main_time;
|
||||
return main_time; // converts to double, to match
|
||||
// what SystemC does
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
@@ -1325,7 +1362,7 @@ will plug directly into a SystemC netlist.
|
||||
The SC_MODULE gets the same pinout as the Verilog module, with the
|
||||
following type conversions: Pins of a single bit become bool. Pins 2-32
|
||||
bits wide become uint32_t's. Pins 33-64 bits wide become sc_bv's or
|
||||
uint64_t's depending on the --no-pins64 switch. Wider pins become sc_bv's.
|
||||
vluint64_t's depending on the --no-pins64 switch. Wider pins become sc_bv's.
|
||||
(Uints simulate the fastest so are used where possible.)
|
||||
|
||||
Lower modules are not pure SystemC code. This is a feature, as using the
|
||||
@@ -1410,6 +1447,38 @@ The /*verilator sformat*/ indicates that this function accepts a $display
|
||||
like format specifier followed by any number of arguments to satisfy the
|
||||
format.
|
||||
|
||||
=head2 DPI Context Functions
|
||||
|
||||
Verilator supports IEEE DPI Context Functions. Context imports pass the
|
||||
simulator context, including calling scope name, and filename and line
|
||||
number to the C code. For example, in Verilog:
|
||||
|
||||
import "DPI-C" context function int dpic_line();
|
||||
initial $display("This is line %d, again, line %d\n", `line, dpic_line());
|
||||
|
||||
This will call C++ code which may then use the svGet* functions to read
|
||||
information, in this case the line number of the Verilog statement that
|
||||
invoked the dpic_line function:
|
||||
|
||||
int dpic_line() {
|
||||
// Get a scope: svScope scope = svGetScope();
|
||||
|
||||
const char* scopenamep = svGetNameFromScope(scope);
|
||||
assert(scopenamep);
|
||||
|
||||
const char* filenamep = "";
|
||||
int lineno = 0;
|
||||
if (svGetCallerInfo(&filenamep, &lineno)) {
|
||||
printf("dpic_line called from scope %s on line %d\n",
|
||||
scopenamep, lineno);
|
||||
return lineno;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
See the IEEE Standard for more information.
|
||||
|
||||
=head2 DPI Header Isolation
|
||||
|
||||
Verilator places the IEEE standard header files such as svdpi.h into a
|
||||
@@ -1421,7 +1490,7 @@ svdpi.h and similar standard files with different contents, the vltstd
|
||||
directory should not be included to prevent picking up incompatible
|
||||
definitions.
|
||||
|
||||
=head2 Public Functions
|
||||
=head2 Public Functions
|
||||
|
||||
Instead of DPI exporting, there's also Verilator public functions, which
|
||||
are slightly faster, but less compatible.
|
||||
@@ -1602,7 +1671,7 @@ please file a bug if a feature you need is missing.
|
||||
Verilator supports ==? and !=? operators, ++ and -- in some contexts,
|
||||
$bits, $countones, $error, $fatal, $info, $isunknown, $onehot, $onehot0,
|
||||
$unit, $warning, always_comb, always_ff, always_latch, bit, byte, chandle,
|
||||
do-while, enum, export, final, import, int, logic, longint, package,
|
||||
const, do-while, enum, export, final, import, int, logic, longint, package,
|
||||
program, shortint, time, typedef, var, void, priority case/if, and unique
|
||||
case/if.
|
||||
|
||||
@@ -1621,6 +1690,18 @@ Verilator currently has some support for SystemVerilog 2009 synthesis
|
||||
constructs. As SystemVerilog features enter common usage they are added;
|
||||
please file a bug if a feature you need is missing.
|
||||
|
||||
=head2 Verilog AMS Support
|
||||
|
||||
Verilator implements a very small subset of Verilog AMS (Verilog Analog and
|
||||
Mixed-Signal Extensions) with the subset corresponding to those VMS
|
||||
keywords with near equivelents in the Verilog 2005 or SystemVerilog 2009
|
||||
languages.
|
||||
|
||||
AMS parsing is enabled with "--language VAMS" or "--language 1800+VAMS".
|
||||
|
||||
At present Verilator implements ceil, exp, floor, ln, log, pow, sqrt,
|
||||
string, and wreal.
|
||||
|
||||
=head2 Sugar/PSL Support
|
||||
|
||||
Most future work is being directed towards improving SystemVerilog
|
||||
@@ -1652,8 +1733,8 @@ assertion clocks.
|
||||
=head2 Synthesis Directive Assertion Support
|
||||
|
||||
With the --assert switch, Verilator reads any "//synopsys full_case" or "//
|
||||
synopsys parallel_case" directives. The same applies to any "//cadence" or
|
||||
"// ambit synthesis" directives of the same form.
|
||||
synopsys parallel_case" directives. The same applies to any "// ambit
|
||||
synthesis", "//cadence" or "//pragma" directives of the same form.
|
||||
|
||||
When these synthesis directives are discovered, Verilator will either
|
||||
formally prove the directive to be true, or failing that, will insert the
|
||||
@@ -1969,6 +2050,15 @@ should be declared in SystemC as a sc_clock instead of a bool. This was
|
||||
needed in SystemC 1.1 and 1.2 only; versions 2.0 and later do not require
|
||||
clock pins to be sc_clocks and this is no longer needed.
|
||||
|
||||
=item /*verilator sc_bv*/
|
||||
|
||||
Used after a port declaration. It sets the port to be of sc_bv<I<width>>
|
||||
type, instead of bool, vluint32_t or vluint64_t. This may be useful if
|
||||
the port width is parametrized and different of such modules interface
|
||||
a templated module (such as a transactor) or for other reasons. In general
|
||||
you should avoid using this attribute when not necessary as with increasing
|
||||
usage of sc_bv the performance increases significantly.
|
||||
|
||||
=item /*verilator sformat*/
|
||||
|
||||
Attached to the final input of a function or task "input string" to
|
||||
@@ -2037,7 +2127,7 @@ that Verilator will print a list of known scopes to help your debugging.
|
||||
|
||||
=head2 Floating Point
|
||||
|
||||
Floating Point numbers are not synthesizable, and so not supported.
|
||||
Floating Point (real) numbers are supported.
|
||||
|
||||
=head2 Latches
|
||||
|
||||
@@ -2080,7 +2170,7 @@ of the form:
|
||||
|
||||
inout driver;
|
||||
wire driver = (enable) ? output_value : 1'bz;
|
||||
|
||||
|
||||
Will be converted to
|
||||
|
||||
input driver__in; // Value being driven in from "external" drivers
|
||||
@@ -2189,11 +2279,23 @@ Increment/decrement can only be used as standalone statements or in for
|
||||
loops. They cannot be used as side effect operators inside more complicate
|
||||
expressions ("a = b++;").
|
||||
|
||||
=item cast operator
|
||||
|
||||
Casting is supported only between simple scalar types, signed and unsigned,
|
||||
not arrays nor structs.
|
||||
|
||||
=item chandle
|
||||
|
||||
Treated as a "longint"; does not yet warn about operations that are
|
||||
specified as illegal on chandles.
|
||||
|
||||
=item disable
|
||||
|
||||
Disable statements may be used only if the block being disabled is a block
|
||||
the disable statement itself is inside. This was commonly used to provide
|
||||
loop break and continue functionality before SystemVerilog added the break
|
||||
and continue keywords.
|
||||
|
||||
=item priority if, unique if
|
||||
|
||||
Priority and unique if's are treated as normal ifs and not asserted to be
|
||||
@@ -2242,11 +2344,6 @@ The rarely used optional parameter to $finish and $stop is ignored.
|
||||
|
||||
File descriptors passed to the file PLI calls must be file descriptors, not
|
||||
MCDs, which includes the mode parameter to $fopen being mandatory.
|
||||
Verilator will convert the integer used to hold the file descriptor into a
|
||||
internal FILE*. To prevent core dumps due to mis-use, and because integers
|
||||
are 32 bits while FILE*s may be 64 bits, the descriptor must be stored in a
|
||||
reg [63:0] rather than an integer. The define `verilator_file_descriptor in
|
||||
verilated.v can be used to hide this difference.
|
||||
|
||||
=item $fscanf, $sscanf
|
||||
|
||||
@@ -2270,10 +2367,6 @@ Read memory commands should work properly. Note Verilator and the Verilog
|
||||
specification does not include support for readmem to multi-dimensional
|
||||
arrays.
|
||||
|
||||
=item $realtime
|
||||
|
||||
Treated as $time.
|
||||
|
||||
=item $test$plusargs, $value$plusargs
|
||||
|
||||
Supported, but the instantiating C++/SystemC testbench must call
|
||||
@@ -2313,6 +2406,29 @@ List of all warnings:
|
||||
|
||||
=over 4
|
||||
|
||||
=item ASSIGNIN
|
||||
|
||||
Error that an assignment is being made to an input signal. This is almost
|
||||
certainly a mistake, though technically legal.
|
||||
|
||||
input a;
|
||||
assign a = 1'b1;
|
||||
|
||||
Ignoring this warning will only suppress the lint check, it will simulate
|
||||
correctly.
|
||||
|
||||
=item ASSIGNDLY
|
||||
|
||||
Warns that you have an assignment statement with a delayed time in front of
|
||||
it, for example:
|
||||
|
||||
a <= #100 b;
|
||||
assign #100 a = b;
|
||||
|
||||
Ignoring this warning may make Verilator simulations differ from other
|
||||
simulators, however at one point this was a common style so disabled by
|
||||
default as a code style warning.
|
||||
|
||||
=item BLKANDNBLK
|
||||
|
||||
BLKANDNBLK is an error that a variable comes from a mix of blocked and
|
||||
@@ -2553,6 +2669,11 @@ not really needed. The best solution is to insure that each module is in a
|
||||
unique file by the same name. Otherwise, make sure all library files are
|
||||
read in as libraries with -v, instead of automatically with -y.
|
||||
|
||||
=item REALCVT
|
||||
|
||||
Warns that a real number is being implicitly rounded to an integer, with
|
||||
possible loss of precision.
|
||||
|
||||
=item REDEFMACRO
|
||||
|
||||
Warns that you have redefined the same macro with a different value, for
|
||||
@@ -2881,6 +3002,11 @@ One limit is that you cannot under either license release a commercial
|
||||
Verilog simulation product incorporating Verilator without making the
|
||||
source code available.
|
||||
|
||||
As is standard with Open Source, contributions back to Verilator will be
|
||||
placed under the Verilator copyright and LGPL/Artistic license. Small test
|
||||
cases will be released into the public domain so they can be used anywhere,
|
||||
large tests under the LGPL/Artistic, unless requested otherwise.
|
||||
|
||||
=item Why is Verilation so slow?
|
||||
|
||||
Verilator needs more memory than the resulting simulator will require, as
|
||||
@@ -2987,8 +3113,8 @@ 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 currently require SystemPerl output mode and the SystemPerl
|
||||
package.
|
||||
coverage. Both require the SystemPerl package to be installed but do not
|
||||
require use of the SystemPerl output mode.
|
||||
|
||||
First, run verilator with the --coverage option. If you're using your own
|
||||
makefile, compile the model with the GCC flag -DSP_COVERAGE_ENABLE (if
|
||||
@@ -3078,10 +3204,9 @@ Between GCC 3.0 to 3.3, each compiled progressively slower, thus if you can
|
||||
use GCC 2.95, or GCC 3.4 you'll have faster builds. Two ways to cheat are
|
||||
to compile on parallel machines and avoid compilations altogether. See the
|
||||
--output-split option, and the web for the ccache, distcc and icecream
|
||||
packages, and the Make::Cache package available from
|
||||
L<http://www.veripool.org/>. Make::Cache will skip GCC runs between
|
||||
identical source builds, even across different users. You can use the
|
||||
OBJCACHE environment variable to use these CC wrappers.
|
||||
packages. ccache will skip GCC runs between identical source builds, even
|
||||
across different users. You can use the OBJCACHE environment variable to
|
||||
use these CC wrappers.
|
||||
|
||||
=item Why do so many files need to recompile when I add a signal?
|
||||
|
||||
@@ -3111,7 +3236,7 @@ as you would any other member variable.
|
||||
|
||||
Signals are the smallest of 8 bit chars, 16 bit shorts, 32 bit longs, or 64
|
||||
bit long longs that fits the width of the signal. Generally, you can use
|
||||
just uint32_t's for 1 to 32 bits, or uint64_t for 1 to 64 bits, and the
|
||||
just uint32_t's for 1 to 32 bits, or vluint64_t for 1 to 64 bits, and the
|
||||
compiler will properly up-convert smaller entities.
|
||||
|
||||
Signals wider than 64 bits are stored as an array of 32-bit uint32_t's.
|
||||
@@ -3232,25 +3357,30 @@ Brooks, Duane Galbi, Paul Wasson, and Wilson Snyder. Major testers include
|
||||
Jeff Dutton, Ralf Karge, David Hewson, Wim Michiels, and Gene Weber.
|
||||
|
||||
Some of the people who have provided ideas and feedback for Verilator
|
||||
include David Addison, Hans Van Antwerpen, Vasu Arasanipalai, Jens Arm, J
|
||||
include: David Addison, Hans Van Antwerpen, Vasu Arasanipalai, Jens Arm, J
|
||||
Baxter, Jeremy Bennett, David Black, Gregg Bouchard, Christopher Boumenot,
|
||||
Byron Bradley, Bryan Brady, Lane Brooks, John Brownlee, Lawrence Butcher,
|
||||
Chris Candler, Lauren Carlson, Donal Casey, Robert A. Clark, Allan
|
||||
Cochrane, Gunter Dannoritzer, Bernard Deadman, John Deroo, John Dickol,
|
||||
Danny Ding, Alex Duller, Jeff Dutton, Robert Farrell, Eugen Fekete, Andrea
|
||||
Foletto, Bob Fredieu, Shankar Giri, Sam Gladstone, Chitlesh Goorah, Thomas
|
||||
Hawkins, David Hewson, Jae Hossell, Ben Jackson, Mike Kagen, Guy-Armand
|
||||
Kamendje, Vasu Kandadi, Patricio Kaplan, Ralf Karge, Dan Katz, Sol Katzman,
|
||||
Jonathan Kimmitt, Gernot Koch, Soon Koh, Steve Kolecki, Steve Lang,
|
||||
Stephane Laurent, Charlie Lind, Dan Lussier, Fred Ma, Duraid Madina, Mark
|
||||
Marshall, Wim Michiels, Dennis Muhlestein, John Murphy, Richard Myers,
|
||||
Dimitris Nalbantis, Paul Nitza, Pete Nixon, Lisa Noack, Mark Nodine,
|
||||
Andreas Olofsson, Niranjan Prabhu, Oleg Rodionov, John Sanguinetti, Mike
|
||||
Shinkarovsky, Rafael Shirakawa, Rodney Sinclair, Brian Small, Art Stamness,
|
||||
John Stroebel, Emerson Suguimoto, Renga Sundararajan, Stefan Thiede, Gary
|
||||
Thomas, Steve Tong, Holger Waechtler, Shawn Wang, Greg Waters, Eugene
|
||||
Weber, Leon Wildman, Gerald Williams, Jeff Winston, Johan Wouters, and Ding
|
||||
Xiaoliang.
|
||||
Nick Bowler, Byron Bradley, Bryan Brady, Lane Brooks, John Brownlee,
|
||||
Lawrence Butcher, Chris Candler, Lauren Carlson, Donal Casey, Terry Chen,
|
||||
Robert A. Clark, Allan Cochrane, Gunter Dannoritzer, Ashutosh Das, Bernard
|
||||
Deadman, John Deroo, John Dickol, Danny Ding, Ivan Djordjevic, Alex Duller,
|
||||
Jeff Dutton, Chandan Egbert, Joe Eiler, Ahmed El-Mahmoudy, Robert Farrell,
|
||||
Eugen Fekete, Andrea Foletto, Bob Fredieu, Shankar Giri, Sam Gladstone,
|
||||
Amir Gonnen, Chitlesh Goorah, Neil Hamilton, Thomas Hawkins, David Hewson,
|
||||
Jae Hossell, Ben Jackson, Iztok Jeras, Mike Kagen, Guy-Armand Kamendje,
|
||||
Vasu Kandadi, Patricio Kaplan, Ralf Karge, Dan Katz, Sol Katzman, Jonathan
|
||||
Kimmitt, Gernot Koch, Soon Koh, Steve Kolecki, Steve Lang, Stephane
|
||||
Laurent, Christian Leber, Charlie Lind, Paul Liu, Dan Lussier, Fred Ma,
|
||||
Duraid Madina, Mark Marshall, Jason McMullan, Wim Michiels, Dennis
|
||||
Muhlestein, John Murphy, Richard Myers, Dimitris Nalbantis, Paul Nitza,
|
||||
Pete Nixon, Lisa Noack, Mark Nodine, Andreas Olofsson, Brad Parker, Dominic
|
||||
Plunkett, Niranjan Prabhu, Usha Priyadharshini, Oleg Rodionov, John
|
||||
Sanguinetti, Salman Sheikh, Mike Shinkarovsky, Rafael Shirakawa, Jeffrey
|
||||
Short, Rodney Sinclair, Brian Small, Alex Solomatnikov, Art Stamness, John
|
||||
Stroebel, Emerson Suguimoto, Gene Sullivan, Renga Sundararajan, Stefan
|
||||
Thiede, Gary Thomas, Steve Tong, Holger Waechtler, Stefan Wallentowitz,
|
||||
Shawn Wang, Greg Waters, Eugene Weber, David Welch, Leon Wildman, Gerald
|
||||
Williams, Trevor Williams, Jeff Winston, Joshua Wise, Johan Wouters, and
|
||||
Ding Xiaoliang.
|
||||
|
||||
Thanks all.
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ sub filter {
|
||||
next if $line =~ / This=/;
|
||||
$line =~ s/0x[a-f0-9]+/0x/g;
|
||||
$line =~ s/<e[0-9]+\#?>/<e>/g;
|
||||
$line =~ s/{\d+}/{}/g if !$Opt_Lineno;
|
||||
$line =~ s/{[a-z]*\d+}/{}/g if !$Opt_Lineno;
|
||||
print $f2 $line;
|
||||
}
|
||||
$f1->close;
|
||||
@@ -109,7 +109,7 @@ sub filter {
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
sub usage {
|
||||
pod2usage(-verbose=>2, -exitval => 2);
|
||||
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ profcfunc($Opt_File);
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
sub usage {
|
||||
pod2usage(-verbose=>2, -exitval => 2);
|
||||
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
|
||||
+100
-31
@@ -1,35 +1,83 @@
|
||||
dnl DESCRIPTION: Process this file with autoconf to produce a configure script.
|
||||
dnl
|
||||
dnl Copyright 2003-2011 by Wilson Snyder. Verilator is free software; you can
|
||||
dnl redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||
dnl General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
# DESCRIPTION: Process this file with autoconf to produce a configure script.
|
||||
#
|
||||
# Copyright 2003-2011 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.
|
||||
|
||||
AC_INIT(src/Verilator.cpp)
|
||||
AC_INIT([Verilator],[3.830])
|
||||
AC_CONFIG_HEADER(src/config_build.h)
|
||||
AC_CONFIG_FILES(Makefile src/Makefile src/Makefile_obj include/verilated.mk)
|
||||
|
||||
dnl Special Substitutions
|
||||
AC_ARG_ENABLE(defenv,
|
||||
[AS_HELP_STRING([--disable-defenv], [disable hardcoded default environment variables])],
|
||||
CFG_WITH_DEFENV=$enableval,
|
||||
CFG_WITH_DEFENV=yes)
|
||||
AC_MSG_RESULT([configuring for $PACKAGE_STRING])
|
||||
|
||||
# Special Substitutions - CFG_WITH_DEFENV
|
||||
AC_MSG_CHECKING(whether to disable hardcoded paths)
|
||||
AC_ARG_ENABLE([defenv],
|
||||
[AS_HELP_STRING([--disable-defenv],
|
||||
[disable using some hardcoded data paths extracted from some default environment variables (the default is to use hardcoded paths)])],
|
||||
[case "${enableval}" in
|
||||
yes) CFG_WITH_DEFENV=yes ;;
|
||||
no) CFG_WITH_DEFENV=no ;;
|
||||
*) AC_MSG_ERROR([bad value ${enableval} for --disable-defenv]) ;;
|
||||
esac],
|
||||
CFG_WITH_DEFENV=yes)
|
||||
AC_SUBST(CFG_WITH_DEFENV)
|
||||
AC_MSG_RESULT($CFG_WITH_DEFENV)
|
||||
|
||||
dnl Compiler flags
|
||||
# Special Substitutions - CFG_WITH_CCWARN
|
||||
AC_MSG_CHECKING(whether to show and stop on compilation warnings)
|
||||
AC_ARG_ENABLE([ccwarn],
|
||||
[AS_HELP_STRING([--enable-ccwarn],
|
||||
[enable showing and stopping on compilation warnings])],
|
||||
[case "${enableval}" in
|
||||
yes) CFG_WITH_CCWARN=yes ;;
|
||||
no) CFG_WITH_CCWARN=no ;;
|
||||
*) AC_MSG_ERROR([bad value ${enableval} for --enable-ccwarn]) ;;
|
||||
esac],
|
||||
[case "x${VERILATOR_AUTHOR_SITE}" in
|
||||
x) CFG_WITH_CCWARN=no ;;
|
||||
*) CFG_WITH_CCWARN=yes ;;
|
||||
esac]
|
||||
)
|
||||
AC_SUBST(CFG_WITH_CCWARN)
|
||||
AC_MSG_RESULT($CFG_WITH_CCWARN)
|
||||
|
||||
# Special Substitutions - CFG_WITH_LONGTESTS
|
||||
AC_MSG_CHECKING(whether to run long tests)
|
||||
AC_ARG_ENABLE([longtests],
|
||||
[AS_HELP_STRING([--enable-longtests],
|
||||
[enable running long developer tests])],
|
||||
[case "${enableval}" in
|
||||
yes) CFG_WITH_LONGTESTS=yes ;;
|
||||
no) CFG_WITH_LONGTESTS=no ;;
|
||||
*) AC_MSG_ERROR([bad value ${enableval} for --enable-longtests]) ;;
|
||||
esac],
|
||||
[case "x${VERILATOR_AUTHOR_SITE}" in
|
||||
x) CFG_WITH_LONGTESTS=no ;;
|
||||
*) CFG_WITH_LONGTESTS=yes ;;
|
||||
esac]
|
||||
)
|
||||
AC_SUBST(CFG_WITH_LONGTESTS)
|
||||
AC_MSG_RESULT($CFG_WITH_LONGTESTS)
|
||||
|
||||
# Compiler flags
|
||||
CFLAGS=-I${includedir}
|
||||
CPPFLAGS=-I${includedir}
|
||||
CXXFLAGS=-I${includedir}
|
||||
LDFLAGS=-L${libdir}
|
||||
|
||||
dnl Checks for programs.
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
AC_PROG_INSTALL
|
||||
|
||||
AC_LANG_PUSH(C++)
|
||||
AC_MSG_CHECKING([that C++ compiler can compile simple program])
|
||||
AC_TRY_RUN([int main() { return 0; }],
|
||||
AC_RUN_IFELSE(
|
||||
[AC_LANG_SOURCE([int main() { return 0; }])],
|
||||
AC_MSG_RESULT(yes),
|
||||
AC_MSG_RESULT(no);AC_MSG_ERROR([a working C++ compiler is required]))
|
||||
AC_MSG_RESULT(no);AC_MSG_ERROR([a working C++ compiler is required]),
|
||||
AC_MSG_RESULT(yes))
|
||||
|
||||
AC_PATH_PROG(PERL,perl)
|
||||
if test "x$PERL" = "x" ; then
|
||||
@@ -44,33 +92,54 @@ if test "x$YACC" = "x" ; then
|
||||
AC_MSG_ERROR([Cannot find "bison" in your PATH, please install it])
|
||||
fi
|
||||
|
||||
dnl Checks for libraries.
|
||||
# Checks for libraries.
|
||||
|
||||
dnl Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
AC_HEADER_SYS_WAIT
|
||||
AC_CHECK_HEADERS(fcntl.h unistd.h inttypes.h sys/file.h sys/time.h sys/un.h math.h stdint.h mingw/stdint.h)
|
||||
|
||||
dnl Checks for typedefs, structures
|
||||
# Checks for typedefs, structures
|
||||
AC_CHECK_TYPE(size_t,unsigned int)
|
||||
AC_CHECK_TYPE(uint_t,unsigned int)
|
||||
AC_CHECK_TYPE(ulong_t,unsigned long)
|
||||
AC_TYPE_SIZE_T
|
||||
AC_STRUCT_TM
|
||||
|
||||
dnl Checks for compiler characteristics.
|
||||
# Checks for compiler characteristics.
|
||||
AC_C_INLINE
|
||||
|
||||
dnl Checks for library functions.
|
||||
AC_DEFUN([_MY_CXX_CHECK_OPT],
|
||||
[# _MY_CXX_CHECK_OPT(flag) -- Check if compiler supports specific options
|
||||
ACO_SAVE_CXXFLAGS="$CXXFLAGS"
|
||||
# -Werror needed otherwise unknown -Wno-div-by-zero won't report problems
|
||||
CXXFLAGS="$CXXFLAGS $1 -Werror"
|
||||
AC_MSG_CHECKING([whether $CXX accepts $1])
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM([],[])],
|
||||
[_my_result=yes],
|
||||
[_my_result=no])
|
||||
AC_MSG_RESULT($_my_result)
|
||||
if test "$_my_result" = "yes" ; then
|
||||
CFG_CXXFLAGS_NO_UNUSED="$CFG_CXXFLAGS_NO_UNUSED $1"
|
||||
fi
|
||||
CXXFLAGS="$ACO_SAVE_CXXFLAGS"
|
||||
])# _MY_CXX_CHECK_OPT
|
||||
|
||||
dnl Checks for system services
|
||||
# For example, -Wno-div-by-zero isn't in 4.1.2
|
||||
_MY_CXX_CHECK_OPT(-Wno-char-subscripts)
|
||||
# Random code often does / 0. Unfortunately VL_DIV_I(0,0) will warn
|
||||
# without this flag, even though there's a conditional to prevent the divide.
|
||||
# We still don't add no-div-by-zero as it throws message to stdout, though doesn't die.
|
||||
#_MY_CXX_CHECK_OPT(-Wno-div-by-zero)
|
||||
_MY_CXX_CHECK_OPT(-Wno-sign-compare)
|
||||
_MY_CXX_CHECK_OPT(-Wno-uninitialized)
|
||||
_MY_CXX_CHECK_OPT(-Wno-unused-parameter)
|
||||
_MY_CXX_CHECK_OPT(-Wno-unused-variable)
|
||||
AC_SUBST(CFG_CXXFLAGS_NO_UNUSED)
|
||||
|
||||
dnl Other install directories
|
||||
# Checks for library functions.
|
||||
|
||||
# Checks for system services
|
||||
|
||||
# Other install directories
|
||||
pkgdatadir=${datadir}/verilator
|
||||
AC_SUBST(pkgdatadir)
|
||||
|
||||
AC_OUTPUT(Makefile src/Makefile src/Makefile_obj include/verilated.mk)
|
||||
AC_OUTPUT
|
||||
|
||||
AC_MSG_RESULT([])
|
||||
AC_MSG_RESULT([Now type 'gmake'])
|
||||
AC_MSG_RESULT([Now type 'make' (or sometimes 'gmake') to build Verilator.])
|
||||
AC_MSG_RESULT([])
|
||||
|
||||
+78
-12
@@ -26,7 +26,6 @@
|
||||
#define _VERILATED_CPP_
|
||||
#include "verilated_imp.h"
|
||||
#include <cctype>
|
||||
#include <vector>
|
||||
|
||||
#define VL_VALUE_STRING_MAX_WIDTH 1024 ///< Max static char array for VL_VALUE_STRING
|
||||
|
||||
@@ -285,12 +284,15 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
|
||||
// Note also assumes variables < 64 are not wide, this assumption is
|
||||
// sometimes not true in low-level routines written here in verilated.cpp
|
||||
static VL_THREAD char tmp[VL_VALUE_STRING_MAX_WIDTH];
|
||||
static VL_THREAD char tmpf[VL_VALUE_STRING_MAX_WIDTH];
|
||||
const char* pctp = NULL; // Most recent %##.##g format
|
||||
bool inPct = false;
|
||||
bool widthSet = false;
|
||||
int width = 0;
|
||||
const char* pos = formatp;
|
||||
for (; *pos; ++pos) {
|
||||
if (!inPct && pos[0]=='%') {
|
||||
pctp = pos;
|
||||
inPct = true;
|
||||
widthSet = false;
|
||||
width = 0;
|
||||
@@ -312,6 +314,9 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
|
||||
widthSet = true;
|
||||
width = width*10 + (fmt - '0');
|
||||
break;
|
||||
case '.':
|
||||
inPct = true; // Get more digits
|
||||
break;
|
||||
case '%':
|
||||
output += '%';
|
||||
break;
|
||||
@@ -325,6 +330,18 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
|
||||
output += cstrp;
|
||||
break;
|
||||
}
|
||||
case 'e':
|
||||
case 'f':
|
||||
case 'g': {
|
||||
const int lbits = va_arg(ap, int);
|
||||
double d = va_arg(ap, double);
|
||||
if (lbits) {} // UNUSED - always 64
|
||||
strncpy(tmpf, pctp, pos-pctp+1);
|
||||
tmpf[pos-pctp+1] = '\0';
|
||||
sprintf(tmp, tmpf, d);
|
||||
output += tmp;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// Deal with all read-and-print somethings
|
||||
const int lbits = va_arg(ap, int);
|
||||
@@ -358,14 +375,26 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
|
||||
case 'd': { // Signed decimal
|
||||
int digits=sprintf(tmp,"%" VL_PRI64 "d",(vlsint64_t)(VL_EXTENDS_QQ(lbits,lbits,ld)));
|
||||
int needmore = width-digits;
|
||||
if (needmore>0) output.append(needmore,' '); // Pre-pad spaces
|
||||
if (needmore>0) {
|
||||
if (pctp && pctp[0] && pctp[1]=='0') { //%0
|
||||
output.append(needmore,'0'); // Pre-pad zero
|
||||
} else {
|
||||
output.append(needmore,' '); // Pre-pad spaces
|
||||
}
|
||||
}
|
||||
output += tmp;
|
||||
break;
|
||||
}
|
||||
case 'u': { // Unsigned decimal
|
||||
int digits=sprintf(tmp,"%" VL_PRI64 "u",ld);
|
||||
int needmore = width-digits;
|
||||
if (needmore>0) output.append(needmore,' '); // Pre-pad spaces
|
||||
if (needmore>0) {
|
||||
if (pctp && pctp[0] && pctp[1]=='0') { //%0
|
||||
output.append(needmore,'0'); // Pre-pad zero
|
||||
} else {
|
||||
output.append(needmore,' '); // Pre-pad spaces
|
||||
}
|
||||
}
|
||||
output += tmp;
|
||||
break;
|
||||
}
|
||||
@@ -569,6 +598,17 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
||||
VL_SET_WQ(owp,ld);
|
||||
break;
|
||||
}
|
||||
case 'f':
|
||||
case 'e':
|
||||
case 'g': { // Real number
|
||||
_vl_vsss_skipspace(fp,floc,fromp);
|
||||
_vl_vsss_read(fp,floc,fromp, tmp, "+-.0123456789eE");
|
||||
if (!tmp[0]) goto done;
|
||||
union { double r; vlsint64_t ld; } u;
|
||||
u.r = strtod(tmp, NULL);
|
||||
VL_SET_WQ(owp,u.ld);
|
||||
break;
|
||||
}
|
||||
case 't': // FALLTHRU // Time
|
||||
case 'u': { // Unsigned decimal
|
||||
_vl_vsss_skipspace(fp,floc,fromp);
|
||||
@@ -628,6 +668,10 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
||||
//===========================================================================
|
||||
// File I/O
|
||||
|
||||
FILE* VL_CVT_I_FP(IData lhs) {
|
||||
return VerilatedImp::fdToFp(lhs);
|
||||
}
|
||||
|
||||
void _VL_VINT_TO_STRING(int obits, char* destoutp, WDataInP sourcep) {
|
||||
// See also VL_DATA_TO_STRING_NW
|
||||
int lsb=obits-1;
|
||||
@@ -655,8 +699,8 @@ void _VL_STRING_TO_VINT(int obits, void* destp, int srclen, const char* srcp) {
|
||||
for (; i<bytes; i++) { *op++ = 0; }
|
||||
}
|
||||
|
||||
IData VL_FGETS_IXQ(int obits, void* destp, QData fpq) {
|
||||
FILE* fp = VL_CVT_Q_FP(fpq);
|
||||
IData VL_FGETS_IXI(int obits, void* destp, IData fpi) {
|
||||
FILE* fp = VL_CVT_I_FP(fpi);
|
||||
if (VL_UNLIKELY(!fp)) return 0;
|
||||
|
||||
// The string needs to be padded with 0's in unused spaces in front of
|
||||
@@ -683,16 +727,26 @@ IData VL_FGETS_IXQ(int obits, void* destp, QData fpq) {
|
||||
return got;
|
||||
}
|
||||
|
||||
QData VL_FOPEN_QI(QData filename, IData mode) {
|
||||
IData VL_FOPEN_QI(QData filename, IData mode) {
|
||||
IData fnw[2]; VL_SET_WQ(fnw, filename);
|
||||
return VL_FOPEN_WI(2, fnw, mode);
|
||||
}
|
||||
QData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode) {
|
||||
IData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode) {
|
||||
char filenamez[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1];
|
||||
_VL_VINT_TO_STRING(fnwords*VL_WORDSIZE, filenamez, filenamep);
|
||||
char modez[5];
|
||||
_VL_VINT_TO_STRING(VL_WORDSIZE, modez, &mode);
|
||||
return VL_CVT_FP_Q(fopen(filenamez,modez));
|
||||
return VL_FOPEN_S(filenamez,modez);
|
||||
}
|
||||
IData VL_FOPEN_S(const char* filenamep, const char* modep) {
|
||||
return VerilatedImp::fdNew(fopen(filenamep,modep));
|
||||
}
|
||||
|
||||
void VL_FCLOSE_I(IData fdi) {
|
||||
FILE* fp = VL_CVT_I_FP(fdi);
|
||||
if (VL_UNLIKELY(!fp)) return;
|
||||
fclose(fp);
|
||||
VerilatedImp::fdDelete(fdi);
|
||||
}
|
||||
|
||||
void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) {
|
||||
@@ -726,8 +780,8 @@ void VL_WRITEF(const char* formatp, ...) {
|
||||
VL_PRINTF("%s", output.c_str());
|
||||
}
|
||||
|
||||
void VL_FWRITEF(QData fpq, const char* formatp, ...) {
|
||||
FILE* fp = VL_CVT_Q_FP(fpq);
|
||||
void VL_FWRITEF(IData fpi, const char* formatp, ...) {
|
||||
FILE* fp = VL_CVT_I_FP(fpi);
|
||||
if (VL_UNLIKELY(!fp)) return;
|
||||
|
||||
va_list ap;
|
||||
@@ -739,8 +793,8 @@ void VL_FWRITEF(QData fpq, const char* formatp, ...) {
|
||||
fputs(output.c_str(), fp);
|
||||
}
|
||||
|
||||
IData VL_FSCANF_IX(QData fpq, const char* formatp, ...) {
|
||||
FILE* fp = VL_CVT_Q_FP(fpq);
|
||||
IData VL_FSCANF_IX(IData fpi, const char* formatp, ...) {
|
||||
FILE* fp = VL_CVT_I_FP(fpi);
|
||||
if (VL_UNLIKELY(!fp)) return 0;
|
||||
|
||||
va_list ap;
|
||||
@@ -883,6 +937,17 @@ void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
}
|
||||
}
|
||||
|
||||
IData VL_SYSTEM_IQ(QData lhs) {
|
||||
IData lhsw[2]; VL_SET_WQ(lhsw, lhs);
|
||||
return VL_SYSTEM_IW(2, lhsw);
|
||||
}
|
||||
IData VL_SYSTEM_IW(int lhswords, WDataInP filenamep) {
|
||||
char filenamez[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1];
|
||||
_VL_VINT_TO_STRING(lhswords*VL_WORDSIZE, filenamez, filenamep);
|
||||
int code = system(filenamez);
|
||||
return code >> 8; // Want exit status
|
||||
}
|
||||
|
||||
IData VL_TESTPLUSARGS_I(const char* formatp) {
|
||||
string match = VerilatedImp::argPlusMatch(formatp);
|
||||
if (match == "") return 0;
|
||||
@@ -1038,6 +1103,7 @@ VerilatedScope::VerilatedScope() {
|
||||
m_callbacksp = NULL;
|
||||
m_namep = NULL;
|
||||
m_funcnumMax = 0;
|
||||
m_symsp = NULL;
|
||||
m_varsp = NULL;
|
||||
}
|
||||
|
||||
|
||||
+43
-24
@@ -35,6 +35,7 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
// <iostream> avoided to reduce compile time
|
||||
// <string> avoided and instead in verilated_heavy.h to reduce compile time
|
||||
using namespace std;
|
||||
@@ -321,11 +322,14 @@ extern WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp); ///< Zero reset a
|
||||
extern WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool is_modulus);
|
||||
|
||||
/// File I/O
|
||||
extern IData VL_FGETS_IXQ(int obits, void* destp, QData fpq);
|
||||
extern IData VL_FGETS_IXI(int obits, void* destp, IData fpi);
|
||||
|
||||
extern QData VL_FOPEN_WI(int fnwords, WDataInP ofilename, IData mode);
|
||||
extern QData VL_FOPEN_QI(QData ofilename, IData mode);
|
||||
inline QData VL_FOPEN_II(IData ofilename, IData mode) { return VL_FOPEN_QI(ofilename,mode); }
|
||||
extern IData VL_FOPEN_S(const char* filenamep, const char* mode);
|
||||
extern IData VL_FOPEN_WI(int fnwords, WDataInP ofilename, IData mode);
|
||||
extern IData VL_FOPEN_QI(QData ofilename, IData mode);
|
||||
inline IData VL_FOPEN_II(IData ofilename, IData mode) { return VL_FOPEN_QI(ofilename,mode); }
|
||||
|
||||
extern void VL_FCLOSE_I(IData fdi);
|
||||
|
||||
extern void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
WDataInP ofilename, void* memp, IData start, IData end);
|
||||
@@ -336,15 +340,19 @@ inline void VL_READMEM_I(bool hex, int width, int depth, int array_lsb, int fnwo
|
||||
VL_READMEM_Q(hex, width,depth,array_lsb,fnwords, ofilename,memp,start,end); }
|
||||
|
||||
extern void VL_WRITEF(const char* formatp, ...);
|
||||
extern void VL_FWRITEF(QData fpq, const char* formatp, ...);
|
||||
extern void VL_FWRITEF(IData fpi, const char* formatp, ...);
|
||||
|
||||
extern IData VL_FSCANF_IX(QData fpq, const char* formatp, ...);
|
||||
extern IData VL_FSCANF_IX(IData fpi, const char* formatp, ...);
|
||||
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, void* destp, const char* formatp, ...);
|
||||
|
||||
extern IData VL_SYSTEM_IW(int lhsnwords, WDataInP lhs);
|
||||
extern IData VL_SYSTEM_IQ(QData lhs);
|
||||
inline IData VL_SYSTEM_II(IData lhs) { return VL_SYSTEM_IQ(lhs); }
|
||||
|
||||
extern IData VL_TESTPLUSARGS_I(const char* formatp);
|
||||
extern IData VL_VALUEPLUSARGS_IW(int rbits, const char* prefixp, char fmt, WDataOutP rwp);
|
||||
extern const char* vl_mc_scan_plusargs(const char* prefixp); // PLIish
|
||||
@@ -364,15 +372,24 @@ extern const char* vl_mc_scan_plusargs(const char* prefixp); // PLIish
|
||||
#define VL_SET_QW(lwp) ( ((QData)(lwp[0])) | ((QData)(lwp[1])<<((QData)(VL_WORDSIZE)) ))
|
||||
#define _VL_SET_QII(ld,rd) ( ((QData)(ld)<<VL_ULL(32)) | (QData)(rd) )
|
||||
|
||||
/// Return FILE* from IData
|
||||
extern FILE* VL_CVT_I_FP(IData lhs);
|
||||
|
||||
// Use a union to avoid cast-to-different-size warnings
|
||||
/// Return FILE* from QData
|
||||
static inline FILE* VL_CVT_Q_FP(QData lhs) { union { FILE* fp; QData q; } u; u.q=lhs; return u.fp; }
|
||||
/// Return void* from QData
|
||||
static inline void* VL_CVT_Q_VP(QData lhs) { union { void* fp; QData q; } u; u.q=lhs; return u.fp; }
|
||||
/// Return QData from FILE*
|
||||
static inline QData VL_CVT_FP_Q(FILE* fp) { union { FILE* fp; QData q; } u; u.q=0; u.fp=fp; return u.q; }
|
||||
/// Return QData from void*
|
||||
static inline QData VL_CVT_VP_Q(void* fp) { union { void* fp; QData q; } u; u.q=0; u.fp=fp; return u.q; }
|
||||
/// Return double from QData (bits, not numerically)
|
||||
static inline double VL_CVT_D_Q(QData lhs) { union { double d; QData q; } u; u.q=lhs; return u.d; }
|
||||
/// Return QData from double (bits, not numerically)
|
||||
static inline QData VL_CVT_Q_D(double lhs) { union { double d; QData q; } u; u.d=lhs; return u.q; }
|
||||
/// Return double from QData (numeric)
|
||||
static inline double VL_ITOR_D_I(IData lhs) { return ((double)((vlsint32_t)(lhs))); }
|
||||
/// Return QData from double (numeric)
|
||||
static inline IData VL_RTOI_I_D(double lhs) { return ((vlsint32_t)(VL_TRUNC(lhs))); }
|
||||
/// Return QData from double (numeric)
|
||||
static inline IData VL_RTOIROUND_I_D(double lhs) { return ((vlsint32_t)(VL_ROUND(lhs))); }
|
||||
|
||||
// Sign extend such that if MSB set, we get ffff_ffff, else 0s
|
||||
// (Requires clean input)
|
||||
@@ -402,9 +419,11 @@ void _VL_DEBUG_PRINT_W(int lbits, WDataInP iwp);
|
||||
#if defined(SYSTEMC_VERSION) && (SYSTEMC_VERSION>20011000)
|
||||
# define VL_TIME_I() ((IData)(sc_time_stamp().to_default_time_units()*VL_TIME_MULTIPLIER))
|
||||
# define VL_TIME_Q() ((QData)(sc_time_stamp().to_default_time_units()*VL_TIME_MULTIPLIER))
|
||||
# define VL_TIME_D() ((double)(sc_time_stamp().to_default_time_units()*VL_TIME_MULTIPLIER))
|
||||
#else
|
||||
# define VL_TIME_I() ((IData)(sc_time_stamp()*VL_TIME_MULTIPLIER))
|
||||
# define VL_TIME_Q() ((QData)(sc_time_stamp()*VL_TIME_MULTIPLIER))
|
||||
# define VL_TIME_D() ((double)(sc_time_stamp()*VL_TIME_MULTIPLIER))
|
||||
extern double sc_time_stamp();
|
||||
#endif
|
||||
|
||||
@@ -947,11 +966,11 @@ static inline WDataOutP VL_SUB_W(int words, WDataOutP owp,WDataInP lwp,WDataInP
|
||||
|
||||
// Optimization bug in GCC 2.96 and presumably all-pre GCC 3 versions need this workaround,
|
||||
// we can't just
|
||||
//# define VL_UNARYMIN_I(data) (-(data))
|
||||
static inline IData VL_UNARYMIN_I(IData data) { return -data; }
|
||||
static inline QData VL_UNARYMIN_Q(QData data) { return -data; }
|
||||
//# define VL_NEGATE_I(data) (-(data))
|
||||
static inline IData VL_NEGATE_I(IData data) { return -data; }
|
||||
static inline QData VL_NEGATE_Q(QData data) { return -data; }
|
||||
|
||||
static inline WDataOutP VL_UNARYMIN_W(int words, WDataOutP owp,WDataInP lwp){
|
||||
static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp,WDataInP lwp){
|
||||
QData carry = 0;
|
||||
for (int i=0; i<words; i++) {
|
||||
carry = carry + (QData)(IData)(~lwp[i]);
|
||||
@@ -998,18 +1017,18 @@ static inline WDataOutP VL_MULS_WWW(int,int lbits,int, WDataOutP owp,WDataInP lw
|
||||
IData lneg = VL_SIGN_I(lbits,lwp[words-1]);
|
||||
if (lneg) { // Negate lhs
|
||||
lwusp = lwstore;
|
||||
VL_UNARYMIN_W(words, lwstore, lwp);
|
||||
VL_NEGATE_W(words, lwstore, lwp);
|
||||
lwstore[words-1] &= VL_MASK_I(lbits); // Clean it
|
||||
}
|
||||
IData rneg = VL_SIGN_I(lbits,rwp[words-1]);
|
||||
if (rneg) { // Negate rhs
|
||||
rwusp = rwstore;
|
||||
VL_UNARYMIN_W(words, rwstore, rwp);
|
||||
VL_NEGATE_W(words, rwstore, rwp);
|
||||
rwstore[words-1] &= VL_MASK_I(lbits); // Clean it
|
||||
}
|
||||
VL_MUL_W(words,owp,lwusp,rwusp);
|
||||
owp[words-1] &= VL_MASK_I(lbits); // Clean. Note it's ok for the multiply to overflow into the sign bit
|
||||
if ((lneg ^ rneg) & 1) { // Negate output (not using UNARYMIN, as owp==lwp)
|
||||
if ((lneg ^ rneg) & 1) { // Negate output (not using NEGATE, as owp==lwp)
|
||||
QData carry = 0;
|
||||
for (int i=0; i<words; i++) {
|
||||
carry = carry + (QData)(IData)(~owp[i]);
|
||||
@@ -1056,12 +1075,12 @@ static inline WDataOutP VL_DIVS_WWW(int lbits, WDataOutP owp,WDataInP lwp,WDataI
|
||||
IData rwstore[VL_MULS_MAX_WORDS];
|
||||
WDataInP ltup = lwp;
|
||||
WDataInP rtup = rwp;
|
||||
if (lsign) { ltup = _VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), lwstore, lwp)); }
|
||||
if (rsign) { rtup = _VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), rwstore, rwp)); }
|
||||
if (lsign) { ltup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), lwstore, lwp)); }
|
||||
if (rsign) { rtup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), rwstore, rwp)); }
|
||||
if ((lsign && !rsign) || (!lsign && rsign)) {
|
||||
IData qNoSign[VL_MULS_MAX_WORDS];
|
||||
VL_DIV_WWW(lbits,qNoSign,ltup,rtup);
|
||||
_VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), owp, qNoSign));
|
||||
_VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), owp, qNoSign));
|
||||
return owp;
|
||||
} else {
|
||||
return VL_DIV_WWW(lbits,owp,ltup,rtup);
|
||||
@@ -1075,12 +1094,12 @@ static inline WDataOutP VL_MODDIVS_WWW(int lbits, WDataOutP owp,WDataInP lwp,WDa
|
||||
IData rwstore[VL_MULS_MAX_WORDS];
|
||||
WDataInP ltup = lwp;
|
||||
WDataInP rtup = rwp;
|
||||
if (lsign) { ltup = _VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), lwstore, lwp)); }
|
||||
if (rsign) { rtup = _VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), rwstore, rwp)); }
|
||||
if (lsign) { ltup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), lwstore, lwp)); }
|
||||
if (rsign) { rtup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), rwstore, rwp)); }
|
||||
if (lsign) { // Only dividend sign matters for modulus
|
||||
IData qNoSign[VL_MULS_MAX_WORDS];
|
||||
VL_MODDIV_WWW(lbits,qNoSign,ltup,rtup);
|
||||
_VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), owp, qNoSign));
|
||||
_VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), owp, qNoSign));
|
||||
return owp;
|
||||
} else {
|
||||
return VL_MODDIV_WWW(lbits,owp,ltup,rtup);
|
||||
@@ -1633,6 +1652,6 @@ static inline WDataOutP VL_CONST_W_9X(int obits, WDataOutP o,
|
||||
|
||||
#undef _END
|
||||
|
||||
// Debugging
|
||||
//======================================================================
|
||||
|
||||
#endif /*_VERILATED_H_*/
|
||||
|
||||
+12
-6
@@ -13,6 +13,12 @@ LINK = @CXX@
|
||||
AR = ar
|
||||
RANLIB = ranlib
|
||||
|
||||
CFG_WITH_CCWARN = @CFG_WITH_CCWARN@
|
||||
CFG_WITH_LONGTESTS = @CFG_WITH_LONGTESTS@
|
||||
|
||||
# Compiler flags to use to turn off unused and generated code warnings, such as -Wno-div-by-zero
|
||||
CFG_CXXFLAGS_NO_UNUSED = @CFG_CXXFLAGS_NO_UNUSED@
|
||||
|
||||
######################################################################
|
||||
# Programs
|
||||
|
||||
@@ -38,13 +44,9 @@ VK_CPPFLAGS_ALWAYS += \
|
||||
-DVM_TRACE=$(VM_TRACE) \
|
||||
-DVM_COVERAGE=$(VM_COVERAGE) \
|
||||
|
||||
ifeq ($(VERILATOR_AUTHOR_SITE),1) # Local... Else don't burden users
|
||||
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
|
||||
VK_CPPFLAGS_WALL += -Wall \
|
||||
-Wno-char-subscripts \
|
||||
-Wno-sign-compare \
|
||||
-Wno-unused-parameter \
|
||||
-Wno-unused-variable \
|
||||
-Wno-uninitialized \
|
||||
$(CFG_CXXFLAGS_NO_UNUSED) \
|
||||
-Werror
|
||||
endif
|
||||
|
||||
@@ -116,6 +118,10 @@ ifeq ($(VM_SP),1)
|
||||
$(SP_PREPROC) -M sp_preproc.d --tree $(VM_PREFIX).sp_tree \
|
||||
--preproc $(VK_CLASSES_SP)
|
||||
else
|
||||
ifeq ($(VM_COVERAGE),1)
|
||||
CPPFLAGS += -I$(SYSTEMPERL_INCLUDE)
|
||||
VPATH += $(SYSTEMPERL_INCLUDE)
|
||||
endif
|
||||
preproc:
|
||||
endif
|
||||
|
||||
|
||||
+2
-6
@@ -27,11 +27,7 @@
|
||||
`define coverage_block_off
|
||||
`endif
|
||||
|
||||
// Hide file descriptor difference
|
||||
`ifdef verilator
|
||||
`define verilator_file_descriptor reg [63:0]
|
||||
`else
|
||||
`define verilator_file_descriptor integer
|
||||
`endif
|
||||
// Hide file descriptor difference - deprecated - for older versions
|
||||
`define verilator_file_descriptor integer
|
||||
|
||||
`endif // guard
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#define _VERILATED_DPI_CPP_
|
||||
#include "verilatedos.h"
|
||||
#include "verilated_dpi.h"
|
||||
#include "verilated_imp.h"
|
||||
|
||||
// On MSVC++ we need svdpi.h to declare exports, not imports
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2011 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.
|
||||
//
|
||||
//*************************************************************************
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator: Common include for all Verilated C files that use DPI
|
||||
///
|
||||
/// This file is included automatically by Verilator at the top of
|
||||
/// all C++ files it generates where DPI is used. It contains
|
||||
/// DPI interface functions required by the Verilated code.
|
||||
///
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _VERILATED_DPI_H_
|
||||
#define _VERILATED_DPI_H_ 1 ///< Header Guard
|
||||
|
||||
#include "verilated.h" // Presumed done by caller
|
||||
#include "svdpi.h"
|
||||
|
||||
//===================================================================
|
||||
// SETTING OPERATORS
|
||||
|
||||
/// Return svBitVecVal from WData
|
||||
static inline void VL_SET_W_SVBV(int obits, WDataOutP owp, svBitVecVal* lwp) {
|
||||
int words = VL_WORDS_I(obits);
|
||||
for (int i=0; i<words-1; i++) owp[i]=lwp[i];
|
||||
owp[words-1] = lwp[words-1] & VL_MASK_I(obits);
|
||||
}
|
||||
static inline void VL_SET_SVBV_W(int obits, svBitVecVal* owp, WDataInP lwp) {
|
||||
int words = VL_WORDS_I(obits);
|
||||
for (int i=0; i<words-1; i++) owp[i]=lwp[i];
|
||||
owp[words-1] = lwp[words-1] & VL_MASK_I(obits);
|
||||
}
|
||||
static inline void VL_SET_W_SVLV(int obits, WDataOutP owp, svLogicVecVal* lwp) {
|
||||
// Note we ignore X/Z in svLogicVecVal
|
||||
int words = VL_WORDS_I(obits);
|
||||
for (int i=0; i<words-1; i++) owp[i]=lwp[i].aval;
|
||||
owp[words-1] = lwp[words-1].aval & VL_MASK_I(obits);
|
||||
}
|
||||
static inline void VL_SET_SVLV_W(int obits, svLogicVecVal* owp, WDataInP lwp) {
|
||||
// Note we don't create X/Z in svLogicVecVal
|
||||
int words = VL_WORDS_I(obits);
|
||||
for (int i=0; i<words; i++) owp[i].bval=0;
|
||||
for (int i=0; i<words-1; i++) owp[i].aval=lwp[i];
|
||||
owp[words-1].aval = lwp[words-1] & VL_MASK_I(obits);
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
||||
#endif // _VERILATED_DPI_H_
|
||||
+39
-1
@@ -35,6 +35,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <string>
|
||||
|
||||
class VerilatedScope;
|
||||
@@ -62,9 +63,18 @@ class VerilatedImp {
|
||||
ExportNameMap m_exportMap; ///< Map of <export_func_proto, func number>
|
||||
int m_exportNext; ///< Next export funcnum
|
||||
|
||||
// File I/O
|
||||
vector<FILE*> m_fdps; ///< File descriptors
|
||||
deque<IData> m_fdFree; ///< List of free descriptors (SLOW - FOPEN/CLOSE only)
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// CONSTRUCTORS
|
||||
VerilatedImp() : m_argVecLoaded(false), m_exportNext(0) {}
|
||||
VerilatedImp() : m_argVecLoaded(false), m_exportNext(0) {
|
||||
m_fdps.resize(3);
|
||||
m_fdps[0] = stdin;
|
||||
m_fdps[1] = stdout;
|
||||
m_fdps[2] = stderr;
|
||||
}
|
||||
~VerilatedImp() {}
|
||||
|
||||
// METHODS - arguments
|
||||
@@ -184,6 +194,34 @@ public: // But only for verilated*.cpp
|
||||
}
|
||||
// We don't free up m_exportMap until the end, because we can't be sure
|
||||
// what other models are using the assigned funcnum's.
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// METHODS - file IO
|
||||
static IData fdNew(FILE* fp) {
|
||||
if (VL_UNLIKELY(!fp)) return 0;
|
||||
// Bit 31 indicates it's a descriptor not a MCD
|
||||
if (s_s.m_fdFree.empty()) {
|
||||
// Need to create more space in m_fdps and m_fdFree
|
||||
size_t start = s_s.m_fdps.size();
|
||||
s_s.m_fdps.resize(start*2);
|
||||
for (size_t i=start; i<start*2; i++) s_s.m_fdFree.push_back((IData)i);
|
||||
}
|
||||
IData idx = s_s.m_fdFree.back(); s_s.m_fdFree.pop_back();
|
||||
s_s.m_fdps[idx] = fp;
|
||||
return (idx | (1UL<<31)); // bit 31 indicates not MCD
|
||||
}
|
||||
static void fdDelete(IData fdi) {
|
||||
IData idx = VL_MASK_I(31) & fdi;
|
||||
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return;
|
||||
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free
|
||||
s_s.m_fdps[idx] = NULL;
|
||||
s_s.m_fdFree.push_back(idx);
|
||||
}
|
||||
static inline FILE* fdToFp(IData fdi) {
|
||||
IData idx = VL_MASK_I(31) & fdi;
|
||||
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return NULL;
|
||||
return s_s.m_fdps[idx];
|
||||
}
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
@@ -86,8 +86,8 @@ private:
|
||||
NameMap* m_namemapp; ///< List of names for the header
|
||||
static vector<VerilatedVcd*> s_vcdVecp; ///< List of all created traces
|
||||
|
||||
inline size_t bufferSize() { return 256*1024; } // See below for slack calculation
|
||||
inline size_t bufferInsertSize() { return 16*1024; }
|
||||
inline static size_t bufferSize() { return 256*1024; } // See below for slack calculation
|
||||
inline static size_t bufferInsertSize() { return 16*1024; }
|
||||
void bufferFlush();
|
||||
void bufferCheck() {
|
||||
// Flush the write buffer if there's not enough space left for new information
|
||||
@@ -110,6 +110,7 @@ private:
|
||||
void dumpHeader();
|
||||
void dumpPrep (vluint64_t timeui);
|
||||
void dumpFull (vluint64_t timeui);
|
||||
// cppcheck-suppress functionConst
|
||||
void dumpDone ();
|
||||
inline void printCode (vluint32_t code) {
|
||||
if (code>=(94*94*94)) *m_writep++ = ((char)((code/94/94/94)%94+33));
|
||||
@@ -117,7 +118,7 @@ private:
|
||||
if (code>=(94)) *m_writep++ = ((char)((code/94)%94+33));
|
||||
*m_writep++ = ((char)((code)%94+33));
|
||||
}
|
||||
string stringCode (vluint32_t code) {
|
||||
static string stringCode (vluint32_t code) {
|
||||
string out;
|
||||
if (code>=(94*94*94)) out += ((char)((code/94/94/94)%94+33));
|
||||
if (code>=(94*94)) out += ((char)((code/94/94)%94+33));
|
||||
@@ -141,6 +142,8 @@ public:
|
||||
m_evcd = false;
|
||||
m_scopeEscape = '.'; // Backward compatibility
|
||||
m_wroteBytes = 0;
|
||||
m_fd = 0;
|
||||
m_fullDump = true;
|
||||
}
|
||||
~VerilatedVcd();
|
||||
|
||||
|
||||
+42
-20
@@ -95,9 +95,14 @@ typedef PLI_INT32 (*VerilatedPliCb)(struct t_cb_data *);
|
||||
|
||||
class VerilatedVpioCb : public VerilatedVpio {
|
||||
t_cb_data m_cbData;
|
||||
s_vpi_value m_value;
|
||||
QData m_time;
|
||||
public:
|
||||
VerilatedVpioCb(const t_cb_data* cbDatap, QData time) : m_cbData(*cbDatap), m_time(time) {}
|
||||
// cppcheck-suppress uninitVar // m_value
|
||||
VerilatedVpioCb(const t_cb_data* cbDatap, QData time)
|
||||
: m_cbData(*cbDatap), m_time(time) {
|
||||
m_cbData.value = &m_value;
|
||||
}
|
||||
virtual ~VerilatedVpioCb() {}
|
||||
static inline VerilatedVpioCb* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioCb*>((VerilatedVpio*)h); }
|
||||
vluint32_t reason() const { return m_cbData.reason; }
|
||||
@@ -326,6 +331,7 @@ public:
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: value_callback %p %s v[0]=%d\n",
|
||||
vop,varop->fullname(), *((CData*)newDatap)););
|
||||
memcpy(prevDatap, newDatap, varop->entSize());
|
||||
vpi_get_value(vop->cb_datap()->obj, vop->cb_datap()->value);
|
||||
(vop->cb_rtnp()) (vop->cb_datap());
|
||||
}
|
||||
}
|
||||
@@ -735,19 +741,26 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p,
|
||||
|
||||
// I/O routines
|
||||
|
||||
//-PLI_UINT32 vpi_mcd_open(PLI_BYTE8 *fileName) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
//-PLI_UINT32 vpi_mcd_close(PLI_UINT32 mcd) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
//-PLI_BYTE8 *vpi_mcd_name(PLI_UINT32 cd) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
//-PLI_INT32 vpi_mcd_printf(PLI_UINT32 mcd, PLI_BYTE8 *format, ...) {
|
||||
PLI_UINT32 vpi_mcd_open(PLI_BYTE8 *filenamep) {
|
||||
return VL_FOPEN_S(filenamep,"wb");
|
||||
}
|
||||
|
||||
PLI_UINT32 vpi_mcd_close(PLI_UINT32 mcd) {
|
||||
VL_FCLOSE_I(mcd); return 0;
|
||||
}
|
||||
|
||||
//-PLI_BYTE8 *vpi_mcd_name(PLI_UINT32 mcd) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
|
||||
PLI_INT32 vpi_mcd_printf(PLI_UINT32 mcd, PLI_BYTE8 *formatp, ...) {
|
||||
va_list ap;
|
||||
va_start(ap,formatp);
|
||||
int chars = vpi_mcd_vprintf(mcd, formatp, ap);
|
||||
va_end(ap);
|
||||
return chars;
|
||||
}
|
||||
|
||||
PLI_INT32 vpi_printf(PLI_BYTE8 *formatp, ...) {
|
||||
va_list ap;
|
||||
va_start(ap,formatp);
|
||||
@@ -760,15 +773,24 @@ PLI_INT32 vpi_vprintf(PLI_BYTE8* formatp, va_list ap) {
|
||||
return VL_VPRINTF(formatp, ap);
|
||||
}
|
||||
|
||||
//-PLI_INT32 vpi_mcd_vprintf(PLI_UINT32 mcd, PLI_BYTE8 *format, va_list ap) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
//-PLI_INT32 vpi_flush(void) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
//-PLI_INT32 vpi_mcd_flush(PLI_UINT32 mcd) {
|
||||
//- _VL_VPI_UNIMP(); return 0;
|
||||
//-}
|
||||
PLI_INT32 vpi_mcd_vprintf(PLI_UINT32 mcd, PLI_BYTE8 *format, va_list ap) {
|
||||
FILE* fp = VL_CVT_I_FP(mcd);
|
||||
if (VL_UNLIKELY(!fp)) return 0;
|
||||
int chars = vfprintf(fp, format, ap);
|
||||
return chars;
|
||||
}
|
||||
|
||||
PLI_INT32 vpi_flush(void) {
|
||||
Verilated::flushCall();
|
||||
return 0;
|
||||
}
|
||||
|
||||
PLI_INT32 vpi_mcd_flush(PLI_UINT32 mcd) {
|
||||
FILE* fp = VL_CVT_I_FP(mcd);
|
||||
if (VL_UNLIKELY(!fp)) return 1;
|
||||
fflush(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// utility routines
|
||||
|
||||
|
||||
@@ -221,6 +221,18 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
#define VL_BITBIT_I(bit) ((bit)&VL_SIZEBITS_I) ///< Bit number for a bit in a long
|
||||
#define VL_BITBIT_Q(bit) ((bit)&VL_SIZEBITS_Q) ///< Bit number for a bit in a quad
|
||||
|
||||
//=========================================================================
|
||||
// Floating point
|
||||
// #defines, to avoid requiring math.h on all compile runs
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define VL_TRUNC(n) (((n)<0) ? ceil((n)) : floor((n)))
|
||||
# define VL_ROUND(n) (((n)<0) ? ceil((n)-0.5) : floor((n)+0.5))
|
||||
#else
|
||||
# define VL_TRUNC(n) trunc(n)
|
||||
# define VL_ROUND(n) round(n)
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
|
||||
#endif /*guard*/
|
||||
|
||||
+6
-5
@@ -207,10 +207,10 @@ viewers let us know; ZGRViewer isn't great for large graphs.
|
||||
Tree files are dumps of the AST Tree and are produced between every major
|
||||
algorithmic stage. An example:
|
||||
|
||||
NETLIST 0x90fb00 <e1> {0} w0
|
||||
1: MODULE 0x912b20 <e8822> {8} w0 top L2 [P]
|
||||
*1:2: VAR 0x91a780 <e74#> {22} w70 out_wide [O] WIRE
|
||||
1:2:1: BASICDTYPE 0x91a3c0 <e73> {22} w70 [logic]
|
||||
NETLIST 0x90fb00 <e1> {a0} w0
|
||||
1: MODULE 0x912b20 <e8822> {a8} w0 top L2 [P]
|
||||
*1:2: VAR 0x91a780 <e74#> {a22} w70 out_wide [O] WIRE
|
||||
1:2:1: BASICDTYPE 0x91a3c0 <e73> {a22} w70 [logic]
|
||||
|
||||
=over 4
|
||||
|
||||
@@ -224,7 +224,8 @@ algorithmic stage. An example:
|
||||
this node. A trailing # indicates this node changed since the last tree
|
||||
dump was made. You can gdb break on this edit; see below.
|
||||
|
||||
"{22}" indicates this node is related to line 22 in the source.
|
||||
"{a22}" indicates this node is related to line 22 in the source filename
|
||||
"a", where "a" is the first file read, "z" the 36th, and "aa" the 37th.
|
||||
|
||||
"w70" indicates the width is 70 bits. sw70 would be signed 70 bits.
|
||||
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ cwrite ("graph_export.cpp");
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
sub usage {
|
||||
pod2usage(-verbose=>2, -exitval => 2);
|
||||
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ dotwrite();
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
sub usage {
|
||||
pod2usage(-verbose=>2, -exitval => 2);
|
||||
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
|
||||
+55
-11
@@ -12,12 +12,15 @@ use vars qw ($Debug);
|
||||
#======================================================================
|
||||
# main
|
||||
|
||||
our $Opt_Stage = 0;
|
||||
|
||||
autoflush STDOUT 1;
|
||||
autoflush STDERR 1;
|
||||
Getopt::Long::config ("no_auto_abbrev");
|
||||
if (! GetOptions (
|
||||
"debug" => sub { $Debug = 1; },
|
||||
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
|
||||
"stage=i" => \$Opt_Stage,
|
||||
)) {
|
||||
die "%Error: Bad usage, try 'install_test --help'\n";
|
||||
}
|
||||
@@ -37,8 +40,10 @@ sub test {
|
||||
my $srcdir = getcwd();
|
||||
my $blddir = $srcdir."/test_regress/obj_dir/install_test_bld";
|
||||
my $prefix = $srcdir."/test_regress/obj_dir/install_test_prefix";
|
||||
my $testdir = $srcdir."/test_regress/obj_dir/install_test_test";
|
||||
if (1) {
|
||||
my $testdirp= $srcdir."/test_regress/obj_dir/install_test_testp";
|
||||
my $testdirn= $srcdir."/test_regress/obj_dir/install_test_testn";
|
||||
|
||||
if ($Opt_Stage <= 0) {
|
||||
run("/bin/rm -rf $blddir");
|
||||
run("/bin/mkdir -p $blddir");
|
||||
run("cd $blddir && $srcdir/configure --prefix $prefix");
|
||||
@@ -46,24 +51,63 @@ sub test {
|
||||
}
|
||||
|
||||
# Install it under the prefix
|
||||
if (1) {
|
||||
if ($Opt_Stage <= 1) {
|
||||
run("/bin/rm -rf $prefix");
|
||||
run("/bin/mkdir -p $prefix");
|
||||
run("cd $blddir && make install");
|
||||
run("test -e $prefix/share/man/man1/verilator.1");
|
||||
run("test -e $prefix/share/verilator/examples/test_c/Makefile");
|
||||
run("test -e $prefix/share/verilator/include/verilated.h");
|
||||
run("test -e $prefix/bin/verilator");
|
||||
run("test -e $prefix/bin/verilator_bin");
|
||||
run("test -e $prefix/bin/verilator_bin_dbg");
|
||||
run("test -e $prefix/bin/verilator_profcfunc");
|
||||
}
|
||||
|
||||
# Run a test using just the path
|
||||
if (1) {
|
||||
run("/bin/rm -rf $testdir");
|
||||
run("/bin/mkdir -p $testdir");
|
||||
if ($Opt_Stage <= 2) {
|
||||
my $dir = $testdirp;
|
||||
run("/bin/rm -rf $dir");
|
||||
run("/bin/mkdir -p $dir");
|
||||
my $bin1 = $prefix."/bin";
|
||||
my $bin2 = $prefix."/share/bin";
|
||||
IO::File->new(">$testdir/foo.v")->print('module t; initial begin $display("HELLO WORLD"); end endmodule'."\n");
|
||||
run("cd $testdir && PATH=$bin1:$bin2:\$PATH verilator --cc foo.v");
|
||||
run("cd $testdir/obj_dir && PATH=$bin1:$bin2:\$PATH make -f Vfoo.mk");
|
||||
#Need .c file, and --exe for this to work
|
||||
#run("cd $testdir && PATH=$bin1:$bin2:\$PATH obj_dir/Vfoo");
|
||||
write_verilog($dir);
|
||||
run("cd $dir && PATH=$bin1:$bin2:\$PATH verilator --cc foo.v --exe foo.cpp");
|
||||
run("cd $dir/obj_dir && PATH=$bin1:$bin2:\$PATH make -f Vfoo.mk");
|
||||
run("cd $dir && PATH=$bin1:$bin2:\$PATH obj_dir/Vfoo");
|
||||
}
|
||||
|
||||
# Run a test using exact path to binary
|
||||
if ($Opt_Stage <= 3) {
|
||||
my $dir = $testdirn;
|
||||
run("/bin/rm -rf $dir");
|
||||
run("/bin/mkdir -p $dir");
|
||||
write_verilog($dir);
|
||||
my $bin1 = $prefix."/bin";
|
||||
my $bin2 = $prefix."/share/bin";
|
||||
run("cd $dir && $bin1/verilator --cc foo.v --exe foo.cpp");
|
||||
run("cd $dir/obj_dir && make -f Vfoo.mk");
|
||||
run("cd $dir/obj_dir && ./Vfoo");
|
||||
}
|
||||
}
|
||||
|
||||
sub write_verilog {
|
||||
my $dir = shift;
|
||||
IO::File->new(">$dir/foo.v")->print('module t; initial begin $display("HELLO WORLD"); $finish; end endmodule'."\n");
|
||||
my $fh = IO::File->new(">$dir/foo.cpp");
|
||||
$fh->print('#include "Vfoo.h"' ,"\n");
|
||||
$fh->print('unsigned int main_time = 0;' ,"\n");
|
||||
$fh->print('double sc_time_stamp () {' ,"\n");
|
||||
$fh->print(' return main_time;' ,"\n");
|
||||
$fh->print('}' ,"\n");
|
||||
$fh->print('int main() {' ,"\n");
|
||||
$fh->print(' Vfoo *top = new Vfoo;' ,"\n");
|
||||
$fh->print(' while (!Verilated::gotFinish()) {',"\n");
|
||||
$fh->print(' top->eval();' ,"\n");
|
||||
$fh->print(' main_time++;' ,"\n");
|
||||
$fh->print(' }' ,"\n");
|
||||
$fh->print(' top->final();' ,"\n");
|
||||
$fh->print('}' ,"\n");
|
||||
}
|
||||
|
||||
sub cleanenv {
|
||||
|
||||
+1
-13
@@ -8,21 +8,9 @@ use strict;
|
||||
#======================================================================
|
||||
# main
|
||||
|
||||
delete $ENV{MODULE_VERSION};
|
||||
_setup_modules();
|
||||
module('add','axiom-athdl');
|
||||
eval `modulecmd perl add axiom-athdl`;
|
||||
exec('atsim',@ARGV);
|
||||
|
||||
#######################################################################
|
||||
# Modules package
|
||||
|
||||
sub _setup_modules {
|
||||
# Load the 'module' command into the environment
|
||||
my $init = "$ENV{MODULESHOME}/init/perl";
|
||||
(-f $init) or die "%Error: Script not found: $init,";
|
||||
require $init;
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
__END__
|
||||
|
||||
|
||||
+1
-13
@@ -8,21 +8,9 @@ use strict;
|
||||
#======================================================================
|
||||
# main
|
||||
|
||||
delete $ENV{MODULE_VERSION};
|
||||
_setup_modules();
|
||||
module('add','cadence-ius');
|
||||
eval `modulecmd perl add cds-ius`;
|
||||
exec('iccr',@ARGV);
|
||||
|
||||
#######################################################################
|
||||
# Modules package
|
||||
|
||||
sub _setup_modules {
|
||||
# Load the 'module' command into the environment
|
||||
my $init = "$ENV{MODULESHOME}/init/perl";
|
||||
(-f $init) or die "%Error: Script not found: $init,";
|
||||
require $init;
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
__END__
|
||||
|
||||
|
||||
+1
-13
@@ -8,21 +8,9 @@ use strict;
|
||||
#======================================================================
|
||||
# main
|
||||
|
||||
delete $ENV{MODULE_VERSION};
|
||||
_setup_modules();
|
||||
module('add','cadence-ius');
|
||||
eval `modulecmd perl add cds-ius`;
|
||||
exec('ncverilog',@ARGV);
|
||||
|
||||
#######################################################################
|
||||
# Modules package
|
||||
|
||||
sub _setup_modules {
|
||||
# Load the 'module' command into the environment
|
||||
my $init = "$ENV{MODULESHOME}/init/perl";
|
||||
(-f $init) or die "%Error: Script not found: $init,";
|
||||
require $init;
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
__END__
|
||||
|
||||
|
||||
+1
-13
@@ -8,21 +8,9 @@ use strict;
|
||||
#======================================================================
|
||||
# main
|
||||
|
||||
delete $ENV{MODULE_VERSION};
|
||||
_setup_modules();
|
||||
module('add','synopsys-vcs');
|
||||
eval `modulecmd perl add synopsys-vcs`;
|
||||
exec('vcs',@ARGV);
|
||||
|
||||
#######################################################################
|
||||
# Modules package
|
||||
|
||||
sub _setup_modules {
|
||||
# Load the 'module' command into the environment
|
||||
my $init = "$ENV{MODULESHOME}/init/perl";
|
||||
(-f $init) or die "%Error: Script not found: $init,";
|
||||
require $init;
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
__END__
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ print '(query-replace-regexp "(\\([0-9a-z_]+\\))" "\\1" nil nil nil)',"\n";
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
sub usage {
|
||||
pod2usage(-verbose=>2, -exitval => 2);
|
||||
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
@@ -256,7 +256,7 @@ sub gentree {
|
||||
'TRACE' => sub { p "TRACE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'UCFUNC' => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ")"; },
|
||||
'UCSTMT' => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ");";nl; },
|
||||
'UNARYMIN' => sub { p " -";p1; },
|
||||
'NEGATE' => sub { p " -";p1; },
|
||||
'VAR' => sub { p_var(); },
|
||||
'VARPIN' => sub { p "VARPIN what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'VARREF' => sub { a1; },
|
||||
|
||||
@@ -91,6 +91,10 @@ headers.
|
||||
|
||||
=item
|
||||
|
||||
You will need the C<flex> and C<bison> packages installed.
|
||||
|
||||
=item
|
||||
|
||||
C<cd> to the Verilator directory containing this README.
|
||||
|
||||
=item
|
||||
@@ -147,6 +151,9 @@ most GNU tools support:
|
||||
unsetenv VERILATOR_ROOT # if your shell is csh
|
||||
./configure --prefix /opt/verilator-VERSION
|
||||
|
||||
Then after installing you will need to add /opt/verilator-VERSION/bin to
|
||||
PATH.
|
||||
|
||||
=back
|
||||
|
||||
=item
|
||||
|
||||
+13
-24
@@ -24,6 +24,7 @@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
PERL = @PERL@
|
||||
EXEEXT = @EXEEXT@
|
||||
|
||||
#### End of system configuration section. ####
|
||||
|
||||
@@ -32,25 +33,11 @@ default: dbg opt
|
||||
debug: dbg
|
||||
optimize: opt
|
||||
|
||||
ifeq ($(OBJCACHE_HOSTS),)
|
||||
ifneq ($(SLCHOOSED_HOST),)
|
||||
ifeq ($(VERILATOR_AUTHOR_SITE),1)
|
||||
export OBJCACHE_HOSTS := $(shell rschedule --no-allow-reserved --similar hostnames)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(OBJCACHE_JOBS),)
|
||||
ifneq ($(OBJCACHE_HOSTS),)
|
||||
export OBJCACHE_JOBS := -j $(shell objcache --jobs "$(OBJCACHE_HOSTS)")
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(words $(CURDIR)),1)
|
||||
$(error Unsupported: GNU Make cannot build in directories containing spaces, build elsewhere: '$(CURDIR)')
|
||||
endif
|
||||
|
||||
UNDER_GIT = $(wildcard ../.git/logs/HEAD)
|
||||
UNDER_GIT = $(wildcard ${srcdir}/../.git/logs/HEAD)
|
||||
|
||||
#*********************************************************************
|
||||
|
||||
@@ -65,26 +52,25 @@ opt: ../verilator_bin
|
||||
ifeq ($(VERILATOR_NO_OPT_BUILD),1) # Faster laptop development... One build
|
||||
../verilator_bin: ../verilator_bin_dbg
|
||||
-rm -rf $@ $@.exe
|
||||
-cp -p $< $@
|
||||
-cp -p $<.exe $@.exe
|
||||
-cp -p $<$(EXEEXT) $@$(EXEEXT)
|
||||
else
|
||||
../verilator_bin: obj_opt prefiles
|
||||
cd obj_opt && $(MAKE) -j 1 TGT=../$@ -f ../Makefile_obj serial
|
||||
cd obj_opt && $(MAKE) $(OBJCACHE_JOBS) TGT=../$@ -f ../Makefile_obj
|
||||
cd obj_opt && $(MAKE) -j 1 TGT=../$@ -f ../Makefile_obj serial
|
||||
cd obj_opt && $(MAKE) TGT=../$@ -f ../Makefile_obj
|
||||
endif
|
||||
|
||||
dbg: ../verilator_bin_dbg
|
||||
../verilator_bin_dbg: obj_dbg prefiles
|
||||
cd obj_dbg && $(MAKE) -j 1 TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj serial
|
||||
cd obj_dbg && $(MAKE) $(OBJCACHE_JOBS) TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj
|
||||
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
|
||||
|
||||
prefiles::
|
||||
|
||||
ifneq ($(UNDER_GIT),) # If local git tree... Else don't burden users
|
||||
prefiles:: config_rev.h
|
||||
# This output goes into srcdir, as we need to distribute it as part of the kit.
|
||||
config_rev.h: config_rev.pl ../.git/logs/HEAD
|
||||
$(PERL) config_rev.pl . >$@
|
||||
# This output goes into srcdir if locally configured, as we need to distribute it as part of the kit.
|
||||
config_rev.h: ${srcdir}/config_rev.pl ${srcdir}/../.git/logs/HEAD
|
||||
$(PERL) ${srcdir}/config_rev.pl ${srcdir} >$@
|
||||
endif
|
||||
|
||||
maintainer-copy::
|
||||
@@ -96,3 +82,6 @@ clean mostlyclean distclean maintainer-clean::
|
||||
|
||||
distclean maintainer-clean::
|
||||
-rm -f Makefile Makefile_obj config_build.h
|
||||
|
||||
maintainer-clean::
|
||||
-rm -f config_rev.h
|
||||
|
||||
+14
-14
@@ -57,9 +57,11 @@ datarootdir = @datarootdir@
|
||||
pkgdatadir = @pkgdatadir@
|
||||
|
||||
# Compile options
|
||||
CFG_WITH_CCWARN = @CFG_WITH_CCWARN@
|
||||
CFG_WITH_DEFENV = @CFG_WITH_DEFENV@
|
||||
CPPFLAGSNOWALL += @CPPFLAGS@
|
||||
CPPFLAGS += @CPPFLAGS@
|
||||
LDFLAGS += @LDFLAGS@
|
||||
EXEEXT = @EXEEXT@
|
||||
|
||||
#### End of system configuration section. ####
|
||||
|
||||
@@ -85,17 +87,18 @@ endif
|
||||
# -lfl not needed as Flex invoked with %nowrap option
|
||||
LIBS = -lm
|
||||
|
||||
CPPFLAGSNOWALL += -MMD
|
||||
CPPFLAGSNOWALL += -I. -I$(bldsrc) -I$(srcdir) -I$(incdir)
|
||||
CPPFLAGSNOWALL += -DYYDEBUG # Required to get nice error messages
|
||||
#CPPFLAGSNOWALL += -DVL_LEAK_CHECKS # If running valgrind or other hunting tool
|
||||
CPPFLAGSNOWALL += $(COPT)
|
||||
CPPFLAGS = $(CPPFLAGSNOWALL)
|
||||
ifeq ($(VERILATOR_AUTHOR_SITE),1) # Local... Else don't burden users
|
||||
CPPFLAGSNOWALL += -MP # Only works on recent GCC versions
|
||||
CPPFLAGS += -MMD
|
||||
CPPFLAGS += -I. -I$(bldsrc) -I$(srcdir) -I$(incdir)
|
||||
CPPFLAGS += -DYYDEBUG # Required to get nice error messages
|
||||
#CPPFLAGS += -DVL_LEAK_CHECKS # If running valgrind or other hunting tool
|
||||
CPPFLAGS += $(COPT)
|
||||
CPPFLAGS += -MP # Only works on recent GCC versions
|
||||
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
|
||||
CPPFLAGS += -W -Wall -Wno-unused-parameter -Wno-char-subscripts -Werror
|
||||
#CPPFLAGS += -pedantic-errors
|
||||
endif
|
||||
CPPFLAGSWALL = $(CPPFLAGS)
|
||||
CPPFLAGSNOWALL = $(CPPFLAGS) -Wno-unused
|
||||
|
||||
ifneq ($(SYSTEMPERL),) # Intuit SYSTEMPERL_INCLUDE as it's new
|
||||
SYSTEMPERL_INCLUDE ?= $(SYSTEMPERL)/src
|
||||
@@ -209,7 +212,6 @@ RAW_OBJS = \
|
||||
V3PreShell.o \
|
||||
V3Premit.o \
|
||||
V3Scope.o \
|
||||
V3Signed.o \
|
||||
V3Slice.o \
|
||||
V3Split.o \
|
||||
V3SplitAs.o \
|
||||
@@ -251,8 +253,6 @@ $(TGT): V3Ast__gen_classes.h $(OBJS)
|
||||
@echo " Linking $@..."
|
||||
-rm -rf $@ [email protected]
|
||||
${LINK} ${LDFLAGS} -o $@ $(OBJS) $(CCMALLOC) ${LIBS}
|
||||
@-(cp [email protected] $@ || true)
|
||||
# ok if cp failes on linux, it's there to insure executable works on NT
|
||||
|
||||
V3Number_test: V3Number_test.o
|
||||
${LINK} ${LDFLAGS} -o $@ $^ ${LIBS}
|
||||
@@ -263,9 +263,9 @@ V3Number_test: V3Number_test.o
|
||||
$(PERL) $(ASTGEN) -I$(srcdir) $*.cpp
|
||||
|
||||
%.o: %.cpp
|
||||
$(OBJCACHE) ${CXX} ${CPPFLAGS} -c $<
|
||||
$(OBJCACHE) ${CXX} ${CPPFLAGSWALL} -c $<
|
||||
%.o: %.c
|
||||
$(OBJCACHE) ${CC} ${CPPFLAGS} -c $<
|
||||
$(OBJCACHE) ${CC} ${CPPFLAGSWALL} -c $<
|
||||
|
||||
V3ParseLex.o: V3ParseLex.cpp V3Lexer.yy.cpp V3ParseBison.c
|
||||
$(OBJCACHE) ${CXX} ${CPPFLAGSNOWALL} -c $<
|
||||
|
||||
+5
-1
@@ -148,7 +148,11 @@ public:
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
ActiveNamer() {}
|
||||
ActiveNamer() {
|
||||
m_scopep = NULL;
|
||||
m_iActivep = NULL;
|
||||
m_cActivep = NULL;
|
||||
}
|
||||
virtual ~ActiveNamer() {}
|
||||
void main(AstScope* nodep) {
|
||||
nodep->accept(*this);
|
||||
|
||||
+5
-5
@@ -184,7 +184,7 @@ private:
|
||||
}
|
||||
if (nodep->fullPragma() || nodep->priorityPragma()) {
|
||||
// Simply need to add a default if there isn't one already
|
||||
m_statAsFull++;
|
||||
++m_statAsFull;
|
||||
if (!has_default) {
|
||||
nodep->addItemsp(new AstCaseItem(nodep->fileline(), NULL/*DEFAULT*/,
|
||||
newFireAssert(nodep, "synthesis full_case, but non-match found")));
|
||||
@@ -193,7 +193,7 @@ private:
|
||||
if (nodep->parallelPragma() || nodep->uniquePragma() || nodep->unique0Pragma()) {
|
||||
// Need to check that one, and only one of the case items match at any moment
|
||||
// If there's a default, we allow none to match, else exactly one must match
|
||||
m_statAsFull++;
|
||||
++m_statAsFull;
|
||||
if (!has_default && !nodep->itemsp()) {
|
||||
// Not parallel, but harmlessly so.
|
||||
} else {
|
||||
@@ -241,18 +241,18 @@ private:
|
||||
if (m_beginp && nodep->name() == "") nodep->name(m_beginp->name());
|
||||
newPslAssertion(nodep, nodep->propp(), nodep->sentreep(),
|
||||
nodep->stmtsp(), nodep->name()); nodep=NULL;
|
||||
m_statAsCover++;
|
||||
++m_statAsCover;
|
||||
}
|
||||
virtual void visit(AstPslAssert* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
newPslAssertion(nodep, nodep->propp(), nodep->sentreep(),
|
||||
NULL, nodep->name()); nodep=NULL;
|
||||
m_statAsPsl++;
|
||||
++m_statAsPsl;
|
||||
}
|
||||
virtual void visit(AstVAssert* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
newVAssertion(nodep, nodep->propp()); nodep=NULL;
|
||||
m_statAsSV++;
|
||||
++m_statAsSV;
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
||||
|
||||
+6
-4
@@ -74,7 +74,9 @@ void AstNode::init() {
|
||||
m_clonep = NULL;
|
||||
m_cloneCnt = 0;
|
||||
// Attributes
|
||||
m_signed = false;
|
||||
m_numeric = (int)AstNumeric::UNSIGNED;
|
||||
m_didWidth = false;
|
||||
m_doingWidth = false;
|
||||
m_width = 0;
|
||||
m_widthMin = 0;
|
||||
m_user1p = NULL;
|
||||
@@ -428,7 +430,7 @@ void AstNode::replaceWith(AstNode* newp) {
|
||||
repHandle.relink(newp);
|
||||
}
|
||||
|
||||
void AstNRelinker::dump(ostream& str) {
|
||||
void AstNRelinker::dump(ostream& str) const {
|
||||
str<<" BK="<<(uint32_t*)m_backp;
|
||||
str<<" ITER="<<(uint32_t*)m_iterpp;
|
||||
str<<" CHG="<<(m_chg==RELINK_NEXT?"[NEXT] ":"");
|
||||
@@ -873,7 +875,7 @@ bool AstNode::sameTreeIter(AstNode* node2p, bool ignNext) {
|
||||
if (this==NULL || node2p==NULL) return false;
|
||||
if (this->type() != node2p->type()
|
||||
|| this->width() != node2p->width()
|
||||
|| this->isSigned() != node2p->isSigned()
|
||||
|| this->numeric() != node2p->numeric()
|
||||
|| !this->same(node2p)) {
|
||||
return false;
|
||||
}
|
||||
@@ -945,7 +947,7 @@ void AstNode::checkTree() {
|
||||
}
|
||||
}
|
||||
|
||||
void AstNode::dumpPtrs(ostream& os) {
|
||||
void AstNode::dumpPtrs(ostream& os) const {
|
||||
os<<"This="<<typeName()<<" "<<(void*)this;
|
||||
os<<" back="<<(void*)backp();
|
||||
if (nextp()) os<<" next="<<(void*)nextp();
|
||||
|
||||
+86
-27
@@ -27,6 +27,7 @@
|
||||
#include "V3Error.h"
|
||||
#include "V3Number.h"
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
|
||||
#include "V3Ast__gen_classes.h" // From ./astgen
|
||||
// Things like:
|
||||
@@ -56,9 +57,40 @@ public:
|
||||
|
||||
//######################################################################
|
||||
|
||||
class AstNumeric {
|
||||
public:
|
||||
enum en {
|
||||
UNSIGNED,
|
||||
SIGNED,
|
||||
DOUBLE
|
||||
// Limited to 2 bits, unless change V3Ast's packing function
|
||||
};
|
||||
enum en m_e;
|
||||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
"UNSIGNED","SIGNED","DOUBLE"
|
||||
};
|
||||
return names[m_e];
|
||||
};
|
||||
inline AstNumeric () : m_e(UNSIGNED) {}
|
||||
inline AstNumeric (en _e) : m_e(_e) {}
|
||||
explicit inline AstNumeric (int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en () const { return m_e; }
|
||||
inline bool isDouble() const { return m_e==DOUBLE; }
|
||||
inline bool isSigned() const { return m_e==SIGNED; }
|
||||
inline bool isUnsigned() const { return m_e==UNSIGNED; }
|
||||
};
|
||||
inline bool operator== (AstNumeric lhs, AstNumeric rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator== (AstNumeric lhs, AstNumeric::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator== (AstNumeric::en lhs, AstNumeric rhs) { return (lhs == rhs.m_e); }
|
||||
inline ostream& operator<<(ostream& os, AstNumeric rhs) { return os<<rhs.ascii(); }
|
||||
|
||||
//######################################################################
|
||||
|
||||
class AstPragmaType {
|
||||
public:
|
||||
enum en {
|
||||
ILLEGAL,
|
||||
COVERAGE_BLOCK_OFF,
|
||||
INLINE_MODULE,
|
||||
NO_INLINE_MODULE,
|
||||
@@ -67,7 +99,7 @@ public:
|
||||
PUBLIC_TASK
|
||||
};
|
||||
enum en m_e;
|
||||
inline AstPragmaType () {}
|
||||
inline AstPragmaType () : m_e(ILLEGAL) {}
|
||||
inline AstPragmaType (en _e) : m_e(_e) {}
|
||||
explicit inline AstPragmaType (int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en () const { return m_e; }
|
||||
@@ -90,7 +122,7 @@ public:
|
||||
TRACE_CHANGE_SUB
|
||||
};
|
||||
enum en m_e;
|
||||
inline AstCFuncType () {}
|
||||
inline AstCFuncType () : m_e(FT_NORMAL) {}
|
||||
inline AstCFuncType (en _e) : m_e(_e) {}
|
||||
explicit inline AstCFuncType (int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en () const { return m_e; }
|
||||
@@ -158,7 +190,7 @@ public:
|
||||
};
|
||||
return names[m_e];
|
||||
};
|
||||
inline AstEdgeType () {}
|
||||
inline AstEdgeType () : m_e(ET_ILLEGAL) {}
|
||||
inline AstEdgeType (en _e) : m_e(_e) {}
|
||||
explicit inline AstEdgeType (int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en () const { return m_e; }
|
||||
@@ -172,6 +204,7 @@ public:
|
||||
class AstAttrType {
|
||||
public:
|
||||
enum en {
|
||||
ILLEGAL,
|
||||
EXPR_BITS, // V3Const converts to constant
|
||||
//
|
||||
VAR_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
|
||||
@@ -182,19 +215,20 @@ public:
|
||||
VAR_PUBLIC_FLAT_RD, // V3LinkParse moves to AstVar::sigPublic
|
||||
VAR_PUBLIC_FLAT_RW, // V3LinkParse moves to AstVar::sigPublic
|
||||
VAR_ISOLATE_ASSIGNMENTS, // V3LinkParse moves to AstVar::attrIsolateAssign
|
||||
VAR_SC_BV, // V3LinkParse moves to AstVar::attrScBv
|
||||
VAR_SFORMAT // V3LinkParse moves to AstVar::attrSFormat
|
||||
};
|
||||
enum en m_e;
|
||||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
"EXPR_BITS", "VAR_BASE",
|
||||
"%E-AT", "EXPR_BITS", "VAR_BASE",
|
||||
"VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC",
|
||||
"VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD","VAR_PUBLIC_FLAT_RW",
|
||||
"VAR_ISOLATE_ASSIGNMENTS", "VAR_SFORMAT"
|
||||
"VAR_ISOLATE_ASSIGNMENTS", "VAR_SC_BV", "VAR_SFORMAT"
|
||||
};
|
||||
return names[m_e];
|
||||
};
|
||||
inline AstAttrType () {}
|
||||
inline AstAttrType () : m_e(ILLEGAL) {}
|
||||
inline AstAttrType (en _e) : m_e(_e) {}
|
||||
explicit inline AstAttrType (int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en () const { return m_e; }
|
||||
@@ -208,8 +242,9 @@ public:
|
||||
class AstBasicDTypeKwd {
|
||||
public:
|
||||
enum en {
|
||||
UNKNOWN,
|
||||
BIT, BYTE, CHANDLE, INT, INTEGER, LOGIC, LONGINT,
|
||||
REAL, REALTIME, SHORTINT, SHORTREAL, TIME,
|
||||
DOUBLE, SHORTINT, FLOAT, TIME,
|
||||
// Closer to a class type, but limited usage
|
||||
STRING,
|
||||
// Internal types for mid-steps
|
||||
@@ -220,8 +255,9 @@ public:
|
||||
enum en m_e;
|
||||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
"%E-unk",
|
||||
"bit", "byte", "chandle", "int", "integer", "logic", "longint",
|
||||
"real", "realtime", "shortint", "shortreal", "time",
|
||||
"real", "shortint", "shortreal", "time",
|
||||
"string",
|
||||
"VerilatedScope*", "char*",
|
||||
"LOGIC_IMPLICIT"
|
||||
@@ -230,15 +266,16 @@ public:
|
||||
};
|
||||
const char* dpiType() const {
|
||||
static const char* names[] = {
|
||||
"%E-unk",
|
||||
"unsigned char", "char", "void*", "int", "int", "svLogic", "long long",
|
||||
"double", "double", "short int", "float", "long long",
|
||||
"double", "short int", "float", "long long",
|
||||
"const char*",
|
||||
"dpiScope", "const char*",
|
||||
""
|
||||
};
|
||||
return names[m_e];
|
||||
};
|
||||
inline AstBasicDTypeKwd () {}
|
||||
inline AstBasicDTypeKwd () : m_e(UNKNOWN) {}
|
||||
inline AstBasicDTypeKwd (en _e) : m_e(_e) {}
|
||||
explicit inline AstBasicDTypeKwd (int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en () const { return m_e; }
|
||||
@@ -251,6 +288,8 @@ public:
|
||||
case INTEGER: return 32;
|
||||
case LOGIC: return 1;
|
||||
case LONGINT: return 64;
|
||||
case DOUBLE: return 64;
|
||||
case FLOAT: return 32;
|
||||
case SHORTINT: return 16;
|
||||
case TIME: return 64;
|
||||
case STRING: return 64; // Just the pointer, for today
|
||||
@@ -265,7 +304,7 @@ public:
|
||||
}
|
||||
bool isZeroInit() const { // Otherwise initializes to X
|
||||
return (m_e==BIT || m_e==BYTE || m_e==CHANDLE || m_e==INT || m_e==LONGINT || m_e==SHORTINT
|
||||
|| m_e==STRING);
|
||||
|| m_e==STRING || m_e==DOUBLE || m_e==FLOAT);
|
||||
}
|
||||
bool isSloppy() const { // Don't be as anal about width warnings
|
||||
return !(m_e==LOGIC || m_e==BIT);
|
||||
@@ -274,10 +313,13 @@ public:
|
||||
return (m_e==LOGIC || m_e==BIT);
|
||||
}
|
||||
bool isDpiUnsupported() const {
|
||||
return (m_e==LOGIC || m_e==TIME || m_e==REALTIME);
|
||||
return (m_e==LOGIC || m_e==TIME);
|
||||
}
|
||||
bool isOpaque() const { // IE not a simple number we can bit optimize
|
||||
return (m_e==STRING || m_e==SCOPEPTR || m_e==CHARPTR);
|
||||
return (m_e==STRING || m_e==SCOPEPTR || m_e==CHARPTR || m_e==DOUBLE || m_e==FLOAT);
|
||||
}
|
||||
bool isDouble() const {
|
||||
return (m_e==DOUBLE);
|
||||
}
|
||||
};
|
||||
inline bool operator== (AstBasicDTypeKwd lhs, AstBasicDTypeKwd rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
@@ -316,7 +358,7 @@ public:
|
||||
XTEMP
|
||||
};
|
||||
enum en m_e;
|
||||
inline AstVarType () {}
|
||||
inline AstVarType () : m_e(UNKNOWN) {}
|
||||
inline AstVarType (en _e) : m_e(_e) {}
|
||||
explicit inline AstVarType (int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en () const { return m_e; }
|
||||
@@ -374,7 +416,7 @@ public:
|
||||
CT_CASEZ
|
||||
};
|
||||
enum en m_e;
|
||||
inline AstCaseType () {}
|
||||
inline AstCaseType () : m_e(CT_CASE) {}
|
||||
inline AstCaseType (en _e) : m_e(_e) {}
|
||||
explicit inline AstCaseType (int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en () const { return m_e; }
|
||||
@@ -396,7 +438,7 @@ public:
|
||||
DT_FATAL
|
||||
};
|
||||
enum en m_e;
|
||||
inline AstDisplayType () {}
|
||||
inline AstDisplayType () : m_e(DT_DISPLAY) {}
|
||||
inline AstDisplayType (en _e) : m_e(_e) {}
|
||||
explicit inline AstDisplayType (int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en () const { return m_e; }
|
||||
@@ -606,7 +648,7 @@ public:
|
||||
AstNRelinker() { m_backp=NULL; m_chg=RELINK_BAD; m_iterpp=NULL;}
|
||||
void relink(AstNode* newp);
|
||||
AstNode* oldp() const { return m_oldp; }
|
||||
void dump(ostream& str=cout);
|
||||
void dump(ostream& str=cout) const;
|
||||
};
|
||||
inline ostream& operator<<(ostream& os, AstNRelinker& rhs) { rhs.dump(os); return os;}
|
||||
|
||||
@@ -684,7 +726,9 @@ class AstNode {
|
||||
static int s_cloneCntGbl; // Count of which userp is set
|
||||
|
||||
// Attributes
|
||||
bool m_signed:1; // Node is signed
|
||||
uint32_t m_numeric:2; // Node is real/signed - important that bitfields remain unsigned
|
||||
bool m_didWidth:1; // Did V3Width computation
|
||||
bool m_doingWidth:1; // Inside V3Width
|
||||
// // Space for more bools here
|
||||
|
||||
int m_width; // Bit width of operation
|
||||
@@ -717,6 +761,7 @@ class AstNode {
|
||||
void deleteTreeIter();
|
||||
void deleteNode();
|
||||
static void relinkOneLink(AstNode*& pointpr, AstNode* newp);
|
||||
// cppcheck-suppress functionConst
|
||||
void debugTreeChange(const char* prefix, int lineno, bool next);
|
||||
|
||||
protected:
|
||||
@@ -780,6 +825,9 @@ public:
|
||||
static int instrCountLd() { return 2; } ///< Instruction cycles to load memory
|
||||
static int instrCountMul() { return 3; } ///< Instruction cycles to multiply integers
|
||||
static int instrCountPli() { return 20; } ///< Instruction cycles to call pli routines
|
||||
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 instrCountCall() { return instrCountBranch()+10; } ///< Instruction cycles to call subroutine
|
||||
static int instrCountTime() { return instrCountCall()+5; } ///< Instruction cycles to determine simulation time
|
||||
|
||||
@@ -807,10 +855,18 @@ public:
|
||||
bool widthSized() const { return !m_widthMin || m_widthMin==m_width; }
|
||||
void width(int width, int sized) { m_width=width; m_widthMin=sized; }
|
||||
void widthFrom(AstNode* fromp) { if (fromp) { m_width=fromp->m_width; m_widthMin=fromp->m_widthMin; }}
|
||||
void widthSignedFrom(AstNode* fromp) { widthFrom(fromp); signedFrom(fromp); }
|
||||
void signedFrom(AstNode* fromp) { if (fromp) { m_signed=fromp->m_signed; }}
|
||||
void isSigned(bool flag) { m_signed=flag; }
|
||||
bool isSigned() const { return m_signed; }
|
||||
void widthSignedFrom(AstNode* fromp) { widthFrom(fromp); numericFrom(fromp); }
|
||||
void numericFrom(AstNode* fromp) { numeric(fromp->numeric()); }
|
||||
void numeric(AstNumeric flag) { m_numeric = (int)flag; if (flag.isDouble()) width(64,64); }
|
||||
AstNumeric numeric() const { return AstNumeric(m_numeric); }
|
||||
bool isDouble() const { return numeric().isDouble(); }
|
||||
bool isSigned() const { return numeric().isSigned(); }
|
||||
void isSigned(bool flag) { numeric(flag ? AstNumeric::SIGNED : AstNumeric::UNSIGNED); }
|
||||
bool isUnsigned() const { return numeric().isUnsigned(); }
|
||||
void didWidth(bool flag) { m_didWidth=flag; }
|
||||
bool didWidth() const { return m_didWidth; }
|
||||
void doingWidth(bool flag) { m_doingWidth=flag; }
|
||||
bool doingWidth() const { return m_doingWidth; }
|
||||
bool isQuad() const { return (width()>VL_WORDSIZE && width()<=VL_QUADSIZE); }
|
||||
bool isWide() const { return (width()>VL_QUADSIZE); }
|
||||
|
||||
@@ -898,7 +954,7 @@ public:
|
||||
bool sameTree(AstNode* node2p); // Does tree of this == node2p?
|
||||
void deleteTree(); // Always deletes the next link
|
||||
void checkTree(); // User Interface version
|
||||
void dumpPtrs(ostream& str=cout);
|
||||
void dumpPtrs(ostream& str=cout) const;
|
||||
void dumpTree(ostream& str=cout, const string& indent=" ", int maxDepth=0);
|
||||
void dumpTreeAndNext(ostream& str=cout, const string& indent=" ", int maxDepth=0);
|
||||
void dumpTreeFile(const string& filename, bool append=false);
|
||||
@@ -965,6 +1021,7 @@ struct AstNodeTermop : public AstNodeMath {
|
||||
ASTNODE_BASE_FUNCS(NodeTermop)
|
||||
// Know no children, and hot function, so skip iterator for speed
|
||||
// See checkTreeIter also that asserts no children
|
||||
// cppcheck-suppress functionConst
|
||||
void iterateChildren(AstNVisitor& v, AstNUser* vup=NULL) { }
|
||||
};
|
||||
|
||||
@@ -976,10 +1033,13 @@ struct AstNodeUniop : public AstNodeMath {
|
||||
setOp1p(lhsp); }
|
||||
ASTNODE_BASE_FUNCS(NodeUniop)
|
||||
AstNode* lhsp() const { return op1p()->castNode(); }
|
||||
void lhsp(AstNode* nodep) { return setOp1p(nodep); }
|
||||
// METHODS
|
||||
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 int instrCount() const { return widthInstrs(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode*) const { return true; }
|
||||
@@ -1002,6 +1062,7 @@ struct AstNodeBiop : public AstNodeMath {
|
||||
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 int instrCount() const { return widthInstrs(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode*) const { return true; }
|
||||
@@ -1223,6 +1284,7 @@ public:
|
||||
void packagep(AstPackage* nodep) { m_packagep=nodep; }
|
||||
// Know no children, and hot function, so skip iterator for speed
|
||||
// See checkTreeIter also that asserts no children
|
||||
// cppcheck-suppress functionConst
|
||||
void iterateChildren(AstNVisitor& v, AstNUser* vup=NULL) { }
|
||||
};
|
||||
|
||||
@@ -1274,7 +1336,6 @@ private:
|
||||
string m_name; // Name of task
|
||||
string m_cname; // Name of task if DPI import
|
||||
bool m_taskPublic:1; // Public task
|
||||
bool m_didSigning:1; // V3Signed completed; can skip iteration
|
||||
bool m_attrIsolateAssign:1;// User isolate_assignments attribute
|
||||
bool m_prototype:1; // Just a prototype
|
||||
bool m_dpiExport:1; // DPI exported
|
||||
@@ -1285,7 +1346,7 @@ private:
|
||||
public:
|
||||
AstNodeFTask(FileLine* fileline, const string& name, AstNode* stmtsp)
|
||||
: AstNode(fileline)
|
||||
, m_name(name), m_taskPublic(false), m_didSigning(false)
|
||||
, m_name(name), m_taskPublic(false)
|
||||
, m_attrIsolateAssign(false), m_prototype(false)
|
||||
, m_dpiExport(false), m_dpiImport(false), m_dpiContext(false)
|
||||
, m_dpiTask(false), m_pure(false) {
|
||||
@@ -1312,8 +1373,6 @@ public:
|
||||
void scopeNamep(AstNode* nodep) { setNOp4p(nodep); }
|
||||
void taskPublic(bool flag) { m_taskPublic=flag; }
|
||||
bool taskPublic() const { return m_taskPublic; }
|
||||
void didSigning(bool flag) { m_didSigning=flag; }
|
||||
bool didSigning() const { return m_didSigning; }
|
||||
void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; }
|
||||
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
|
||||
void prototype(bool flag) { m_prototype = flag; }
|
||||
|
||||
+12
-7
@@ -70,7 +70,7 @@ bool AstVar::isScQuad() const {
|
||||
}
|
||||
|
||||
bool AstVar::isScBv() const {
|
||||
return (isSc() && width() >= v3Global.opt.pinsBv());
|
||||
return ((isSc() && width() >= v3Global.opt.pinsBv()) || m_attrScBv);
|
||||
}
|
||||
|
||||
void AstVar::combineType(AstVarType type) {
|
||||
@@ -113,6 +113,10 @@ string AstVar::vlArgType(bool named, bool forReturn) const {
|
||||
arg += "const char*";
|
||||
} else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::SCOPEPTR) {
|
||||
arg += "const VerilatedScope*";
|
||||
} else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::DOUBLE) {
|
||||
arg += "double";
|
||||
} else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::FLOAT) {
|
||||
arg += "float";
|
||||
} else if (strtype) {
|
||||
if (isInOnly()) arg += "const ";
|
||||
arg += "string";
|
||||
@@ -185,7 +189,7 @@ string AstVar::cPubArgType(bool named, bool forReturn) const {
|
||||
} else if (isWide()) {
|
||||
arg += "uint32_t"; // []'s added later
|
||||
} else {
|
||||
arg += "uint64_t";
|
||||
arg += "vluint64_t";
|
||||
}
|
||||
if (isWide()) {
|
||||
if (forReturn) v3error("Unsupported: Public functions with >64 bit outputs; make an output of a public task instead");
|
||||
@@ -202,7 +206,6 @@ string AstVar::dpiArgType(bool named, bool forReturn) const {
|
||||
if (forReturn) named=false;
|
||||
string arg;
|
||||
if (!basicp()) arg = "UNKNOWN";
|
||||
if (isWide()) v3error("Unsupported: DPI functions with vectored outputs > 32-bits");
|
||||
if (basicp()->isBitLogic()) {
|
||||
if (widthMin() == 1) {
|
||||
arg = "unsigned char";
|
||||
@@ -238,7 +241,7 @@ string AstVar::scType() const {
|
||||
return "uint32_t";
|
||||
}
|
||||
} else {
|
||||
return "uint64_t";
|
||||
return "vluint64_t";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -498,8 +501,9 @@ void AstNode::dump(ostream& os) {
|
||||
//<<" "<<(void*)this->m_backp
|
||||
<<" <e"<<dec<<editCount()
|
||||
<<((editCount()>=editCountLast())?"#>":">")
|
||||
<<" {"<<dec<<fileline()->lineno()<<"}"
|
||||
<<" {"<<fileline()->filenameLetters()<<dec<<fileline()->lineno()<<"}"
|
||||
<<" "<<(isSigned()?"s":"")
|
||||
<<(isDouble()?"d":"")
|
||||
<<"w"<<(widthSized()?"":"u")<<width();
|
||||
if (!widthSized()) os<<"/"<<widthMin();
|
||||
if (name()!="") os<<" "<<AstNode::quoteName(name());
|
||||
@@ -522,7 +526,7 @@ void AstBasicDType::dump(ostream& str) {
|
||||
str<<" ["<<keyword().ascii()<<"]";
|
||||
if (implicit()) str<<" [IMPLICIT]";
|
||||
}
|
||||
void AstCast::dump(ostream& str) {
|
||||
void AstCCast::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
str<<" sz"<<size();
|
||||
}
|
||||
@@ -609,7 +613,8 @@ void AstVar::dump(ostream& str) {
|
||||
else if (isInput()) str<<" [I]";
|
||||
else if (isOutput()) str<<" [O]";
|
||||
}
|
||||
if (isUsedClock()) str<<" [C]";
|
||||
if (isConst()) str<<" [CONST]";
|
||||
if (isUsedClock()) str<<" [CLK]";
|
||||
if (isSigPublic()) str<<" [P]";
|
||||
if (isUsedLoopIdx()) str<<" [LOOP]";
|
||||
if (attrClockEn()) str<<" [aCLKEN]";
|
||||
|
||||
+473
-49
@@ -46,19 +46,25 @@ struct AstConst : public AstNodeMath {
|
||||
private:
|
||||
V3Number m_num; // Constant value
|
||||
public:
|
||||
class Unsized32 {}; // for creator type-overload selection
|
||||
AstConst(FileLine* fl, const V3Number& num)
|
||||
:AstNodeMath(fl)
|
||||
,m_num(num) {
|
||||
width(m_num.width(), m_num.sized()?0:m_num.minWidth());
|
||||
isSigned(m_num.isSigned());
|
||||
numeric(m_num.isDouble() ? AstNumeric::DOUBLE
|
||||
: m_num.isSigned() ? AstNumeric::SIGNED
|
||||
: AstNumeric::UNSIGNED);
|
||||
}
|
||||
AstConst(FileLine* fl, uint32_t num)
|
||||
:AstNodeMath(fl)
|
||||
,m_num(V3Number(fl,32,num)) { width(m_num.width(), m_num.sized()?0:m_num.minWidth()); }
|
||||
class Unsized32 {}; // for creator type-overload selection
|
||||
AstConst(FileLine* fl, Unsized32, uint32_t num) // Unsized 32-bit integer of specified value
|
||||
:AstNodeMath(fl)
|
||||
,m_num(V3Number(fl,32,num)) { m_num.width(32,false); width(32,m_num.minWidth()); }
|
||||
class RealDouble {}; // for creator type-overload selection
|
||||
AstConst(FileLine* fl, RealDouble, double num)
|
||||
:AstNodeMath(fl)
|
||||
,m_num(V3Number(fl,64)) { m_num.setDouble(num); numeric(AstNumeric::DOUBLE); }
|
||||
class LogicFalse {};
|
||||
AstConst(FileLine* fl, LogicFalse) // Shorthand const 0, know the dtype should be a logic of size 1
|
||||
:AstNodeMath(fl)
|
||||
@@ -258,7 +264,8 @@ private:
|
||||
m_keyword = AstBasicDTypeKwd::LOGIC;
|
||||
}
|
||||
if (signst == signedst_NOP && keyword().isSigned()) signst = signedst_SIGNED;
|
||||
setSignedState(signst);
|
||||
if (keyword().isDouble()) numeric(AstNumeric::DOUBLE);
|
||||
else setSignedState(signst);
|
||||
if (!rangep) { // Set based on keyword properties
|
||||
// V3Width will pull from this width
|
||||
if (keyword().width() > 1 && !isOpaque()) rangep = new AstRange(fileline(), keyword().width()-1, 0);
|
||||
@@ -278,7 +285,8 @@ public:
|
||||
AstRange* rangep() const { return op1p()->castRange(); } // op1 = Range of variable
|
||||
void rangep(AstRange* nodep) { setNOp1p(nodep); }
|
||||
void setSignedState(AstSignedState signst) {
|
||||
if (signst!=signedst_NOP) isSigned(signst==signedst_SIGNED);
|
||||
if (signst==signedst_UNSIGNED) numeric(AstNumeric::UNSIGNED);
|
||||
else if (signst==signedst_SIGNED) numeric(AstNumeric::SIGNED);
|
||||
}
|
||||
// METHODS
|
||||
virtual AstBasicDType* basicp() const { return (AstBasicDType*)this; } // (Slow) recurse down to find basic data type
|
||||
@@ -300,6 +308,25 @@ public:
|
||||
void implicit(bool flag) { m_implicit = flag; }
|
||||
};
|
||||
|
||||
struct AstConstDType : public AstNodeDType {
|
||||
// const data type, ie "const some_dtype var_name [2:0]"
|
||||
// ConstDType are removed in V3LinkLValue and become AstVar::isConst.
|
||||
// When more generic types are supported AstConstDType will be propagated further.
|
||||
AstConstDType(FileLine* fl, AstNodeDType* dtypep)
|
||||
: AstNodeDType(fl) {
|
||||
setOp1p(dtypep);
|
||||
widthSignedFrom(dtypep);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(ConstDType, CONSTDTYPE)
|
||||
AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
|
||||
void dtypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
||||
// METHODS
|
||||
virtual AstBasicDType* basicp() const { return dtypep()->basicp(); } // (Slow) recurse down to find basic data type
|
||||
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
|
||||
virtual int widthAlignBytes() const { return dtypep()->widthAlignBytes(); }
|
||||
virtual int widthTotalBytes() const { return dtypep()->widthTotalBytes(); }
|
||||
};
|
||||
|
||||
struct AstRefDType : public AstNodeDType {
|
||||
private:
|
||||
AstTypedef* m_defp;
|
||||
@@ -364,9 +391,10 @@ public:
|
||||
struct AstEnumItemRef : public AstNodeMath {
|
||||
private:
|
||||
AstEnumItem* m_itemp; // [AfterLink] Pointer to item
|
||||
AstPackage* m_packagep; // Package hierarchy
|
||||
public:
|
||||
AstEnumItemRef(FileLine* fl, AstEnumItem* itemp)
|
||||
: AstNodeMath(fl), m_itemp(itemp) {
|
||||
AstEnumItemRef(FileLine* fl, AstEnumItem* itemp, AstPackage* packagep)
|
||||
: AstNodeMath(fl), m_itemp(itemp), m_packagep(packagep) {
|
||||
if (m_itemp) widthSignedFrom(m_itemp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(EnumItemRef, ENUMITEMREF)
|
||||
@@ -381,6 +409,8 @@ public:
|
||||
virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual bool cleanOut() { return true; }
|
||||
AstPackage* packagep() const { return m_packagep; }
|
||||
void packagep(AstPackage* nodep) { m_packagep=nodep; }
|
||||
};
|
||||
|
||||
struct AstEnumDType : public AstNodeDType {
|
||||
@@ -431,10 +461,10 @@ public:
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
virtual int instrCount() const { return widthInstrs(); }
|
||||
unsigned length() { return m_length; }
|
||||
unsigned length() const { return m_length; }
|
||||
void length(unsigned length) { m_length = length; }
|
||||
void start(unsigned start) { m_start = start; }
|
||||
unsigned start() { return m_start; }
|
||||
unsigned start() const { return m_start; }
|
||||
// Special operators
|
||||
static int dimension(AstNode* nodep); ///< How many dimensions is this reference from the base variable?
|
||||
static AstNode* baseFromp(AstNode* nodep); ///< What is the base variable (or const) this dereferences?
|
||||
@@ -557,6 +587,7 @@ private:
|
||||
bool m_funcLocal:1; // Local variable for a function
|
||||
bool m_funcReturn:1; // Return variable for a function
|
||||
bool m_attrClockEn:1;// User clock enable attribute
|
||||
bool m_attrScBv:1; // User force bit vector attribute
|
||||
bool m_attrIsolateAssign:1;// User isolate_assignments attribute
|
||||
bool m_attrSFormat:1;// User sformat attribute
|
||||
bool m_fileDescr:1; // File descriptor
|
||||
@@ -571,7 +602,7 @@ private:
|
||||
m_usedClock=false; m_usedParam=false; m_usedLoopIdx=false;
|
||||
m_sigPublic=false; m_sigModPublic=false; m_sigUserRdPublic=false; m_sigUserRWPublic=false;
|
||||
m_funcLocal=false; m_funcReturn=false;
|
||||
m_attrClockEn=false; m_attrIsolateAssign=false; m_attrSFormat=false;
|
||||
m_attrClockEn=false; m_attrScBv=false; m_attrIsolateAssign=false; m_attrSFormat=false;
|
||||
m_fileDescr=false; m_isConst=false; m_isStatic=false;
|
||||
m_trace=false;
|
||||
}
|
||||
@@ -582,6 +613,7 @@ public:
|
||||
init();
|
||||
combineType(type); setOp1p(dtypep);
|
||||
if (dtypep && dtypep->basicp()) {
|
||||
numericFrom(dtypep);
|
||||
width(dtypep->basicp()->width(), 0);
|
||||
} else width(1, 0);
|
||||
}
|
||||
@@ -601,6 +633,7 @@ public:
|
||||
if (examplep->dtypep()) {
|
||||
setOp1p(examplep->dtypep()->cloneTree(true));
|
||||
}
|
||||
numericFrom(examplep);
|
||||
width(examplep->width(), examplep->widthMin());
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(Var, VAR)
|
||||
@@ -632,6 +665,7 @@ public:
|
||||
void attrClockEn(bool flag) { m_attrClockEn = flag; }
|
||||
void attrFileDescr(bool flag) { m_fileDescr = flag; }
|
||||
void attrScClocked(bool flag) { m_scClocked = flag; }
|
||||
void attrScBv(bool flag) { m_attrScBv = flag; }
|
||||
void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; }
|
||||
void attrSFormat(bool flag) { m_attrSFormat = flag; }
|
||||
void usedClock(bool flag) { m_usedClock = flag; }
|
||||
@@ -667,7 +701,7 @@ public:
|
||||
bool isToggleCoverable() const { return ((isIO() || isSignal())
|
||||
&& (isIO() || isBitLogic())
|
||||
// Wrapper would otherwise duplicate wrapped module's coverage
|
||||
&& !isSc() && !isPrimaryIO()); }
|
||||
&& !isSc() && !isPrimaryIO() && !isConst()); }
|
||||
bool isStatementTemp() const { return (varType()==AstVarType::STMTTEMP); }
|
||||
bool isMovableToBlock() const { return (varType()==AstVarType::BLOCKTEMP || isFuncLocal()); }
|
||||
bool isPure() const { return (varType()==AstVarType::XTEMP); }
|
||||
@@ -692,6 +726,7 @@ public:
|
||||
bool isFuncLocal() const { return m_funcLocal; }
|
||||
bool isFuncReturn() const { return m_funcReturn; }
|
||||
bool attrClockEn() const { return m_attrClockEn; }
|
||||
bool attrScBv() const { return m_attrScBv; }
|
||||
bool attrFileDescr() const { return m_fileDescr; }
|
||||
bool attrScClocked() const { return m_scClocked; }
|
||||
bool attrSFormat() const { return m_attrSFormat; }
|
||||
@@ -938,6 +973,14 @@ struct AstModule : public AstNodeModule {
|
||||
virtual string verilogKwd() const { return "module"; }
|
||||
};
|
||||
|
||||
struct AstNotFoundModule : public AstNodeModule {
|
||||
// A missing module declaration
|
||||
AstNotFoundModule(FileLine* fl, const string& name)
|
||||
: AstNodeModule (fl,name) {}
|
||||
ASTNODE_NODE_FUNCS(NotFoundModule, NOTFOUNDMODULE)
|
||||
virtual string verilogKwd() const { return "/*not-found-*/ module"; }
|
||||
};
|
||||
|
||||
struct AstPackage : public AstNodeModule {
|
||||
// A package declaration
|
||||
AstPackage(FileLine* fl, const string& name)
|
||||
@@ -1595,7 +1638,7 @@ public:
|
||||
void ignoreOverlap(bool flag) { m_ignoreOverlap = flag; }
|
||||
};
|
||||
|
||||
class AstSFormatF : public AstNode {
|
||||
struct AstSFormatF : public AstNode {
|
||||
// Convert format to string, generally under a AstDisplay or AstSFormat
|
||||
// Also used as "real" function for /*verilator sformat*/ functions
|
||||
string m_text;
|
||||
@@ -1852,6 +1895,45 @@ public:
|
||||
AstNode* msbp() const { return op4p()->castNode(); }
|
||||
};
|
||||
|
||||
struct AstSystemT : public AstNodeStmt {
|
||||
// $system used as task
|
||||
AstSystemT(FileLine* fileline, AstNode* lhsp)
|
||||
: AstNodeStmt (fileline) {
|
||||
setOp1p(lhsp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(SystemT, SYSTEMT)
|
||||
virtual string verilogKwd() const { return "$system"; }
|
||||
virtual bool isGateOptimizable() const { return false; }
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
virtual bool isSplittable() const { return false; }
|
||||
virtual bool isOutputter() const { return true; }
|
||||
virtual bool isUnlikely() const { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
AstNode* lhsp() const { return op1p(); }
|
||||
};
|
||||
|
||||
struct AstSystemF : public AstNodeMath {
|
||||
// $system used as function
|
||||
AstSystemF(FileLine* fileline, AstNode* lhsp)
|
||||
: AstNodeMath (fileline) {
|
||||
setOp1p(lhsp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(SystemF, SYSTEMF)
|
||||
virtual string verilogKwd() const { return "$system"; }
|
||||
virtual string emitVerilog() { return verilogKwd(); }
|
||||
virtual string emitC() { return "VL_SYSTEM_%nq(%lw, %P)"; }
|
||||
virtual bool isGateOptimizable() const { return false; }
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
virtual bool isSplittable() const { return false; }
|
||||
virtual bool isOutputter() const { return true; }
|
||||
virtual bool isUnlikely() const { return true; }
|
||||
virtual bool cleanOut() { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
AstNode* lhsp() const { return op1p(); }
|
||||
};
|
||||
|
||||
struct AstValuePlusArgs : public AstNodeMath {
|
||||
// Parents: expr
|
||||
// Child: variable to set. If NULL then this is a $test$plusargs instead of $value$plusargs
|
||||
@@ -1963,6 +2045,18 @@ struct AstContinue : public AstNodeStmt {
|
||||
virtual bool isSplittable() const { return false; } // SPECIAL: We don't process code after breaks
|
||||
};
|
||||
|
||||
struct AstDisable : public AstNodeStmt {
|
||||
private:
|
||||
string m_name; // Name of block
|
||||
public:
|
||||
AstDisable(FileLine* fileline, const string& name)
|
||||
: AstNodeStmt(fileline), m_name(name) {}
|
||||
ASTNODE_NODE_FUNCS(Disable, DISABLE)
|
||||
virtual string name() const { return m_name; } // * = Block name
|
||||
void name(const string& flag) { m_name=flag; }
|
||||
virtual bool isSplittable() const { return false; } // SPECIAL: We don't process code after breaks
|
||||
};
|
||||
|
||||
struct AstReturn : public AstNodeStmt {
|
||||
AstReturn(FileLine* fileline, AstNode* lhsp=NULL)
|
||||
: AstNodeStmt (fileline) {
|
||||
@@ -2406,6 +2500,20 @@ struct AstTime : public AstNodeTermop {
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
};
|
||||
|
||||
struct AstTimeD : public AstNodeTermop {
|
||||
AstTimeD(FileLine* fl) : AstNodeTermop(fl) {
|
||||
numeric(AstNumeric::DOUBLE); }
|
||||
ASTNODE_NODE_FUNCS(TimeD, TIMED)
|
||||
virtual string emitVerilog() { return "%f$realtime"; }
|
||||
virtual string emitC() { return "VL_TIME_D()"; }
|
||||
virtual bool cleanOut() { return true; }
|
||||
virtual bool isGateOptimizable() const { return false; }
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
virtual int instrCount() const { return instrCountTime(); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
};
|
||||
|
||||
struct AstUCFunc : public AstNodeMath {
|
||||
// User's $c function
|
||||
// Perhaps this should be a AstNodeListop; but there's only one list math right now
|
||||
@@ -2431,19 +2539,32 @@ struct AstUCFunc : public AstNodeMath {
|
||||
//======================================================================
|
||||
// Unary ops
|
||||
|
||||
struct AstUnaryMin : public AstNodeUniop {
|
||||
AstUnaryMin(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
struct AstNegate : public AstNodeUniop {
|
||||
AstNegate(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
if (lhsp) widthSignedFrom(lhsp); }
|
||||
ASTNODE_NODE_FUNCS(UnaryMin, UNARYMIN)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opUnaryMin(lhs); }
|
||||
ASTNODE_NODE_FUNCS(Negate, NEGATE)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opNegate(lhs); }
|
||||
virtual string emitVerilog() { return "%f(- %l)"; }
|
||||
virtual string emitC() { return "VL_UNARYMIN_%lq(%lW, %P, %li)"; }
|
||||
virtual string emitC() { return "VL_NEGATE_%lq(%lW, %P, %li)"; }
|
||||
virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return true;}
|
||||
};
|
||||
struct AstNegateD : public AstNodeUniop {
|
||||
AstNegateD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
numeric(AstNumeric::DOUBLE); }
|
||||
ASTNODE_NODE_FUNCS(NegateD, NEGATED)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opNegateD(lhs); }
|
||||
virtual string emitVerilog() { return "%f(- %l)"; }
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual string emitSimpleOperator() { return "-"; }
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountDouble(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
struct AstRedAnd : public AstNodeUniop {
|
||||
AstRedAnd(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
width(1,1); }
|
||||
width(1,1); numeric(AstNumeric::UNSIGNED); }
|
||||
ASTNODE_NODE_FUNCS(RedAnd, REDAND)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRedAnd(lhs); }
|
||||
virtual string emitVerilog() { return "%f(& %l)"; }
|
||||
@@ -2453,7 +2574,7 @@ struct AstRedAnd : public AstNodeUniop {
|
||||
};
|
||||
struct AstRedOr : public AstNodeUniop {
|
||||
AstRedOr(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
width(1,1); }
|
||||
width(1,1); numeric(AstNumeric::UNSIGNED); }
|
||||
ASTNODE_NODE_FUNCS(RedOr, REDOR)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRedOr(lhs); }
|
||||
virtual string emitVerilog() { return "%f(| %l)"; }
|
||||
@@ -2463,7 +2584,7 @@ struct AstRedOr : public AstNodeUniop {
|
||||
};
|
||||
struct AstRedXor : public AstNodeUniop {
|
||||
AstRedXor(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
width(1,1); }
|
||||
width(1,1); numeric(AstNumeric::UNSIGNED); }
|
||||
ASTNODE_NODE_FUNCS(RedXor, REDXOR)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRedXor(lhs); }
|
||||
virtual string emitVerilog() { return "%f(^ %l)"; }
|
||||
@@ -2477,7 +2598,7 @@ struct AstRedXor : public AstNodeUniop {
|
||||
struct AstRedXnor : public AstNodeUniop {
|
||||
// AstRedXnors are replaced with AstRedXors in V3Const.
|
||||
AstRedXnor(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
width(1,1); }
|
||||
width(1,1); numeric(AstNumeric::UNSIGNED); }
|
||||
ASTNODE_NODE_FUNCS(RedXnor, REDXNOR)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRedXnor(lhs); }
|
||||
virtual string emitVerilog() { return "%f(~^ %l)"; }
|
||||
@@ -2535,7 +2656,7 @@ struct AstExtendS : public AstNodeUniop {
|
||||
struct AstSigned : public AstNodeUniop {
|
||||
// $signed(lhs)
|
||||
AstSigned(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
isSigned(true);
|
||||
numeric(AstNumeric::SIGNED);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(Signed, SIGNED)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opAssign(lhs); out.isSigned(false); }
|
||||
@@ -2548,7 +2669,7 @@ struct AstSigned : public AstNodeUniop {
|
||||
struct AstUnsigned : public AstNodeUniop {
|
||||
// $unsigned(lhs)
|
||||
AstUnsigned(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
isSigned(false);
|
||||
numeric(AstNumeric::UNSIGNED);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(Unsigned, UNSIGNED)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opAssign(lhs); out.isSigned(false); }
|
||||
@@ -2558,6 +2679,63 @@ struct AstUnsigned : public AstNodeUniop {
|
||||
virtual bool sizeMattersLhs() {return true;} // Eliminated before matters
|
||||
virtual int instrCount() const { return 0; }
|
||||
};
|
||||
struct AstRToIS : public AstNodeUniop {
|
||||
// $rtoi(lhs)
|
||||
AstRToIS(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
width(32,32); }
|
||||
ASTNODE_NODE_FUNCS(RToIS, RTOIS)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRToIS(lhs); }
|
||||
virtual string emitVerilog() { return "%f$rtoi(%l)"; }
|
||||
virtual string emitC() { return "VL_RTOI_I_D(%li)"; }
|
||||
virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} // Eliminated before matters
|
||||
virtual bool sizeMattersLhs() {return false;} // Eliminated before matters
|
||||
virtual int instrCount() const { return instrCountDouble(); }
|
||||
};
|
||||
struct AstRToIRoundS : public AstNodeUniop {
|
||||
AstRToIRoundS(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
width(32,32); }
|
||||
ASTNODE_NODE_FUNCS(RToIRoundS, RTOIROUNDS)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRToIRoundS(lhs); }
|
||||
virtual string emitVerilog() { return "%f$rtoi_rounded(%l)"; }
|
||||
virtual string emitC() { return "VL_RTOIROUND_I_D(%li)"; }
|
||||
virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} // Eliminated before matters
|
||||
virtual bool sizeMattersLhs() {return false;} // Eliminated before matters
|
||||
virtual int instrCount() const { return instrCountDouble(); }
|
||||
};
|
||||
struct AstIToRD : public AstNodeUniop {
|
||||
AstIToRD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
numeric(AstNumeric::DOUBLE); }
|
||||
ASTNODE_NODE_FUNCS(IToRD, ITORD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opIToRD(lhs); }
|
||||
virtual string emitVerilog() { return "%f$itor(%l)"; }
|
||||
virtual string emitC() { return "VL_ITOR_D_I(%li)"; }
|
||||
virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} // Eliminated before matters
|
||||
virtual bool sizeMattersLhs() {return false;} // Eliminated before matters
|
||||
virtual int instrCount() const { return instrCountDouble(); }
|
||||
};
|
||||
struct AstRealToBits : public AstNodeUniop {
|
||||
AstRealToBits(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
width(64,64); }
|
||||
ASTNODE_NODE_FUNCS(RealToBits, REALTOBITS)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRealToBits(lhs); }
|
||||
virtual string emitVerilog() { return "%f$realtobits(%l)"; }
|
||||
virtual string emitC() { return "VL_CVT_Q_D(%li)"; }
|
||||
virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} // Eliminated before matters
|
||||
virtual bool sizeMattersLhs() {return false;} // Eliminated before matters
|
||||
virtual int instrCount() const { return instrCountDouble(); }
|
||||
};
|
||||
struct AstBitsToRealD : public AstNodeUniop {
|
||||
AstBitsToRealD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
numeric(AstNumeric::DOUBLE); }
|
||||
ASTNODE_NODE_FUNCS(BitsToRealD, BITSTOREALD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opBitsToRealD(lhs); }
|
||||
virtual string emitVerilog() { return "%f$bitstoreal(%l)"; }
|
||||
virtual string emitC() { return "VL_CVT_D_Q(%li)"; }
|
||||
virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} // Eliminated before matters
|
||||
virtual bool sizeMattersLhs() {return false;} // Eliminated before matters
|
||||
virtual int instrCount() const { return instrCountDouble(); }
|
||||
};
|
||||
|
||||
struct AstCLog2 : public AstNodeUniop {
|
||||
AstCLog2(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {}
|
||||
ASTNODE_NODE_FUNCS(CLog2, CLOG2)
|
||||
@@ -2615,27 +2793,42 @@ struct AstOneHot0 : public AstNodeUniop {
|
||||
virtual int instrCount() const { return widthInstrs()*3; }
|
||||
};
|
||||
|
||||
struct AstCast : public AstNodeUniop {
|
||||
// Cast to appropriate data type
|
||||
struct AstCast : public AstNode {
|
||||
// Cast to appropriate data type - note lhsp is value, to match AstTypedef, AstCCast, etc
|
||||
AstCast(FileLine* fl, AstNode* lhsp, AstNodeDType* dtypep) : AstNode(fl) {
|
||||
setOp1p(lhsp); setOp2p(dtypep);
|
||||
if (dtypep) { widthSignedFrom(dtypep); }
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(Cast, CAST)
|
||||
virtual string emitVerilog() { return "((%r)'(%l))"; }
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual bool cleanOut() { V3ERROR_NA; return true;} virtual bool cleanLhs() {return true;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
AstNode* lhsp() const { return op1p(); }
|
||||
AstNodeDType* dtypep() const { return op2p()->castNodeDType(); }
|
||||
};
|
||||
|
||||
struct AstCCast : public AstNodeUniop {
|
||||
// Cast to C-based data type
|
||||
private:
|
||||
int m_size;
|
||||
public:
|
||||
AstCast(FileLine* fl, AstNode* lhsp, int setwidth) : AstNodeUniop(fl, lhsp) {
|
||||
AstCCast(FileLine* fl, AstNode* lhsp, int setwidth) : AstNodeUniop(fl, lhsp) {
|
||||
m_size=setwidth;
|
||||
if (setwidth) { width(setwidth,setwidth); }
|
||||
}
|
||||
AstCast(FileLine* fl, AstNode* lhsp, AstNode* widthFromp) : AstNodeUniop(fl, lhsp) {
|
||||
AstCCast(FileLine* fl, AstNode* lhsp, AstNode* widthFromp) : AstNodeUniop(fl, lhsp) {
|
||||
if (widthFromp) { widthSignedFrom(widthFromp); }
|
||||
m_size=width();
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(Cast, CAST)
|
||||
ASTNODE_NODE_FUNCS(CCast, CCAST)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opAssign(lhs); }
|
||||
virtual string emitVerilog() { return "%f$_CAST(%l)"; }
|
||||
virtual string emitC() { return "VL_CAST_%nq%lq(%nw,%lw, %P, %li)"; }
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;}
|
||||
virtual bool sizeMattersLhs() {return false;} // Special cased in V3Cast
|
||||
virtual V3Hash sameHash() const { return V3Hash(size()); }
|
||||
virtual bool same(AstNode* samep) const { return size()==samep->castCast()->size(); }
|
||||
virtual bool same(AstNode* samep) const { return size()==samep->castCCast()->size(); }
|
||||
virtual void dump(ostream& str=cout);
|
||||
//
|
||||
int size() const { return m_size; }
|
||||
@@ -2660,7 +2853,7 @@ struct AstFEof : public AstNodeUniop {
|
||||
ASTNODE_NODE_FUNCS(FEof, FEOF)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; }
|
||||
virtual string emitVerilog() { return "%f$feof(%l)"; }
|
||||
virtual string emitC() { return "(%li ? feof(VL_CVT_Q_FP(%li)) : true)"; }
|
||||
virtual string emitC() { return "(%li ? feof(VL_CVT_I_FP(%li)) : true)"; }
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual int instrCount() const { return widthInstrs()*16; }
|
||||
@@ -2673,13 +2866,97 @@ struct AstFGetC : public AstNodeUniop {
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; }
|
||||
virtual string emitVerilog() { return "%f$fgetc(%l)"; }
|
||||
// Non-existent filehandle returns EOF
|
||||
virtual string emitC() { return "(%li ? fgetc(VL_CVT_Q_FP(%li)) : -1)"; }
|
||||
virtual string emitC() { return "(%li ? fgetc(VL_CVT_I_FP(%li)) : -1)"; }
|
||||
virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual int instrCount() const { return widthInstrs()*64; }
|
||||
AstNode* filep() const { return lhsp(); }
|
||||
};
|
||||
|
||||
struct AstCeilD : public AstNodeUniop {
|
||||
AstCeilD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
numeric(AstNumeric::DOUBLE); }
|
||||
ASTNODE_NODE_FUNCS(CeilD, CEILD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) {
|
||||
out.setDouble(ceil(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$ceil(%l)"; }
|
||||
virtual string emitC() { return "ceil(%li)"; }
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountDoubleTrig(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
|
||||
struct AstExpD : public AstNodeUniop {
|
||||
AstExpD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
numeric(AstNumeric::DOUBLE); }
|
||||
ASTNODE_NODE_FUNCS(ExpD, EXPD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) {
|
||||
out.setDouble(exp(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$exp(%l)"; }
|
||||
virtual string emitC() { return "exp(%li)"; }
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountDoubleTrig(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
|
||||
struct AstFloorD : public AstNodeUniop {
|
||||
AstFloorD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
numeric(AstNumeric::DOUBLE); }
|
||||
ASTNODE_NODE_FUNCS(FloorD, FLOORD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) {
|
||||
out.setDouble(floor(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$floor(%l)"; }
|
||||
virtual string emitC() { return "floor(%li)"; }
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountDoubleTrig(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
|
||||
struct AstLogD : public AstNodeUniop {
|
||||
AstLogD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
numeric(AstNumeric::DOUBLE); }
|
||||
ASTNODE_NODE_FUNCS(LogD, LOGD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) {
|
||||
out.setDouble(log(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$ln(%l)"; }
|
||||
virtual string emitC() { return "log(%li)"; }
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountDoubleTrig(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
|
||||
struct AstLog10D : public AstNodeUniop {
|
||||
AstLog10D(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
numeric(AstNumeric::DOUBLE); }
|
||||
ASTNODE_NODE_FUNCS(Log10D, LOG10D)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) {
|
||||
out.setDouble(log10(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$log10(%l)"; }
|
||||
virtual string emitC() { return "log10(%li)"; }
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountDoubleTrig(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
|
||||
struct AstSqrtD : public AstNodeUniop {
|
||||
AstSqrtD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
numeric(AstNumeric::DOUBLE); }
|
||||
ASTNODE_NODE_FUNCS(SqrtD, SQRTD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) {
|
||||
out.setDouble(sqrt(lhs.toDouble())); }
|
||||
virtual string emitVerilog() { return "%f$sqrt(%l)"; }
|
||||
virtual string emitC() { return "sqrt(%li)"; }
|
||||
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;}
|
||||
virtual int instrCount() const { return instrCountDoubleTrig(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
// Binary ops
|
||||
|
||||
@@ -2795,6 +3072,20 @@ struct AstEq : public AstNodeBiCom {
|
||||
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
};
|
||||
struct AstEqD : public AstNodeBiCom {
|
||||
AstEqD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiCom(fl, lhsp, rhsp) {
|
||||
width(1,1); }
|
||||
ASTNODE_NODE_FUNCS(EqD, EQD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opEqD(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 instrCountDouble(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
struct AstNeq : public AstNodeBiCom {
|
||||
AstNeq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiCom(fl, lhsp, rhsp) {
|
||||
width(1,1); }
|
||||
@@ -2807,6 +3098,20 @@ struct AstNeq : public AstNodeBiCom {
|
||||
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
};
|
||||
struct AstNeqD : public AstNodeBiCom {
|
||||
AstNeqD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiCom(fl, lhsp, rhsp) {
|
||||
width(1,1); }
|
||||
ASTNODE_NODE_FUNCS(NeqD, NEQD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opNeqD(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 instrCountDouble(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
struct AstLt : public AstNodeBiop {
|
||||
AstLt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
width(1,1); }
|
||||
@@ -2819,6 +3124,20 @@ struct AstLt : public AstNodeBiop {
|
||||
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
};
|
||||
struct AstLtD : public AstNodeBiop {
|
||||
AstLtD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
width(1,1); }
|
||||
ASTNODE_NODE_FUNCS(LtD, LTD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLtD(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 instrCountDouble(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
struct AstLtS : public AstNodeBiop {
|
||||
AstLtS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
width(1,1); }
|
||||
@@ -2844,6 +3163,20 @@ struct AstGt : public AstNodeBiop {
|
||||
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
};
|
||||
struct AstGtD : public AstNodeBiop {
|
||||
AstGtD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
width(1,1); }
|
||||
ASTNODE_NODE_FUNCS(GtD, GTD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGtD(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 instrCountDouble(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
struct AstGtS : public AstNodeBiop {
|
||||
AstGtS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
width(1,1); }
|
||||
@@ -2869,6 +3202,20 @@ struct AstGte : public AstNodeBiop {
|
||||
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
};
|
||||
struct AstGteD : public AstNodeBiop {
|
||||
AstGteD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
width(1,1); }
|
||||
ASTNODE_NODE_FUNCS(GteD, GTED)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGteD(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 instrCountDouble(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
struct AstGteS : public AstNodeBiop {
|
||||
AstGteS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
width(1,1); }
|
||||
@@ -2894,6 +3241,20 @@ struct AstLte : public AstNodeBiop {
|
||||
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
};
|
||||
struct AstLteD : public AstNodeBiop {
|
||||
AstLteD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
width(1,1); }
|
||||
ASTNODE_NODE_FUNCS(LteD, LTED)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLteD(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 instrCountDouble(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
struct AstLteS : public AstNodeBiop {
|
||||
AstLteS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
width(1,1); }
|
||||
@@ -2962,6 +3323,20 @@ struct AstAdd : public AstNodeBiComAsv {
|
||||
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return true;}
|
||||
};
|
||||
struct AstAddD : public AstNodeBiComAsv {
|
||||
AstAddD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiComAsv(fl, lhsp, rhsp) {
|
||||
numeric(AstNumeric::DOUBLE); }
|
||||
ASTNODE_NODE_FUNCS(AddD, ADDD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opAddD(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 instrCountDouble(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
struct AstSub : public AstNodeBiop {
|
||||
AstSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
if (lhsp) widthSignedFrom(lhsp); }
|
||||
@@ -2974,6 +3349,20 @@ struct AstSub : public AstNodeBiop {
|
||||
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return true;}
|
||||
};
|
||||
struct AstSubD : public AstNodeBiop {
|
||||
AstSubD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
numeric(AstNumeric::DOUBLE); }
|
||||
ASTNODE_NODE_FUNCS(SubD, SUBD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opSubD(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 instrCountDouble(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
struct AstMul : public AstNodeBiComAsv {
|
||||
AstMul(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiComAsv(fl, lhsp, rhsp) {
|
||||
if (lhsp) widthSignedFrom(lhsp); }
|
||||
@@ -2987,6 +3376,20 @@ struct AstMul : public AstNodeBiComAsv {
|
||||
virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return true;}
|
||||
virtual int instrCount() const { return widthInstrs()*instrCountMul(); }
|
||||
};
|
||||
struct AstMulD : public AstNodeBiComAsv {
|
||||
AstMulD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiComAsv(fl, lhsp, rhsp) {
|
||||
numeric(AstNumeric::DOUBLE); }
|
||||
ASTNODE_NODE_FUNCS(MulD, MULD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opMulD(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 true;} virtual bool sizeMattersRhs() {return true;}
|
||||
virtual int instrCount() const { return instrCountDouble(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
struct AstMulS : public AstNodeBiComAsv {
|
||||
AstMulS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiComAsv(fl, lhsp, rhsp) {
|
||||
if (lhsp) widthSignedFrom(lhsp); }
|
||||
@@ -3013,6 +3416,20 @@ struct AstDiv : public AstNodeBiop {
|
||||
virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return true;}
|
||||
virtual int instrCount() const { return widthInstrs()*instrCountDiv(); }
|
||||
};
|
||||
struct AstDivD : public AstNodeBiop {
|
||||
AstDivD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
numeric(AstNumeric::DOUBLE); }
|
||||
ASTNODE_NODE_FUNCS(DivD, DIVD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opDivD(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 instrCountDoubleDiv(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
struct AstDivS : public AstNodeBiop {
|
||||
AstDivS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
if (lhsp) widthSignedFrom(lhsp); }
|
||||
@@ -3063,6 +3480,19 @@ struct AstPow : public AstNodeBiop {
|
||||
virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return false;}
|
||||
virtual int instrCount() const { return widthInstrs()*instrCountMul(); }
|
||||
};
|
||||
struct AstPowD : public AstNodeBiop {
|
||||
AstPowD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
numeric(AstNumeric::DOUBLE); }
|
||||
ASTNODE_NODE_FUNCS(PowD, POWD)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opPowD(lhs,rhs); }
|
||||
virtual string emitVerilog() { return "%k(%l %f** %r)"; }
|
||||
virtual string emitC() { return "pow(%li,%ri)"; }
|
||||
virtual bool cleanOut() {return false;}
|
||||
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 instrCountDoubleDiv(); }
|
||||
virtual bool doubleFlavor() const { return true; }
|
||||
};
|
||||
struct AstPowS : public AstNodeBiop {
|
||||
AstPowS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
if (lhsp) widthSignedFrom(lhsp); }
|
||||
@@ -3152,6 +3582,19 @@ struct AstReplicate : public AstNodeBiop {
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
virtual int instrCount() const { return widthInstrs()*2; }
|
||||
};
|
||||
struct AstBufIf1 : public AstNodeBiop {
|
||||
// lhs is enable, rhs is data to drive
|
||||
AstBufIf1(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
|
||||
if (lhsp) widthSignedFrom(lhsp); }
|
||||
ASTNODE_NODE_FUNCS(BufIf1, BUFIF1)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opBufIf1(lhs,rhs); }
|
||||
virtual string emitVerilog() { return "bufif(%r,%l)"; }
|
||||
virtual string emitC() { V3ERROR_NA; return "";} // Lclean || Rclean
|
||||
virtual string emitSimpleOperator() { V3ERROR_NA; return "";} // Lclean || Rclean
|
||||
virtual bool cleanOut() {V3ERROR_NA; return "";} // Lclean || Rclean
|
||||
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
|
||||
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
|
||||
};
|
||||
struct AstFGetS : public AstNodeBiop {
|
||||
AstFGetS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {}
|
||||
ASTNODE_NODE_FUNCS(FGetS, FGETS)
|
||||
@@ -3586,25 +4029,6 @@ struct AstCReturn : public AstNodeStmt {
|
||||
AstNode* lhsp() const { return op1p(); }
|
||||
};
|
||||
|
||||
struct AstCInclude : public AstNode {
|
||||
// C++ use of another class
|
||||
// Parents: MODULE
|
||||
// Children: None
|
||||
private:
|
||||
AstNodeModule* m_modp;
|
||||
public:
|
||||
AstCInclude(FileLine* fl, AstNodeModule* modp)
|
||||
: AstNode(fl) {
|
||||
m_modp = modp;
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(CInclude, CINCLUDE)
|
||||
virtual bool broken() const { return (m_modp && !m_modp->brokeExists()); }
|
||||
virtual void cloneRelink() { if (m_modp && m_modp->clonep()) {
|
||||
m_modp = m_modp->clonep()->castNodeModule();
|
||||
}}
|
||||
AstNodeModule* modp() const { return m_modp; }
|
||||
};
|
||||
|
||||
struct AstCMath : public AstNodeMath {
|
||||
private:
|
||||
bool m_cleanOut;
|
||||
|
||||
+8
-4
@@ -148,17 +148,19 @@ private:
|
||||
|
||||
bool isCaseTreeFast(AstCase* nodep) {
|
||||
int width = 0;
|
||||
bool opaque = false;
|
||||
m_caseItems = 0;
|
||||
m_caseNoOverlapsAllCovered = true;
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
|
||||
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
|
||||
if (icondp->width() > width) width = icondp->width();
|
||||
if (icondp->isDouble()) opaque = true;
|
||||
if (!icondp->castConst()) width = CASE_BARF; // Can't parse; not a constant
|
||||
m_caseItems++;
|
||||
}
|
||||
}
|
||||
m_caseWidth = width;
|
||||
if (width==0 || width > CASE_OVERLAP_WIDTH) {
|
||||
if (width==0 || width > CASE_OVERLAP_WIDTH || opaque) {
|
||||
m_caseNoOverlapsAllCovered = false;
|
||||
return false; // Too wide for analysis
|
||||
}
|
||||
@@ -348,7 +350,9 @@ private:
|
||||
and1p = cexprp->cloneTree(false);
|
||||
and2p = icondp;
|
||||
}
|
||||
AstEq* condp = new AstEq(itemp->fileline(), and1p, and2p);
|
||||
AstNodeBiop* condp = (and1p->isDouble()
|
||||
? (new AstEqD(itemp->fileline(), and1p, and2p))->castNodeBiop()
|
||||
: (new AstEq(itemp->fileline(), and1p, and2p))->castNodeBiop());
|
||||
if (!ifexprp) {
|
||||
ifexprp = condp;
|
||||
} else {
|
||||
@@ -448,10 +452,10 @@ private:
|
||||
if (isCaseTreeFast(nodep) && v3Global.opt.oCase()) {
|
||||
// It's a simple priority encoder or complete statement
|
||||
// we can make a tree of statements to avoid extra comparisons
|
||||
m_statCaseFast++;
|
||||
++m_statCaseFast;
|
||||
replaceCaseFast(nodep); nodep=NULL;
|
||||
} else {
|
||||
m_statCaseSlow++;
|
||||
++m_statCaseSlow;
|
||||
replaceCaseComplicated(nodep); nodep=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -77,7 +77,7 @@ private:
|
||||
AstNRelinker relinkHandle;
|
||||
nodep->unlinkFrBack(&relinkHandle);
|
||||
//
|
||||
AstCast* castp = new AstCast (nodep->fileline(), nodep, needsize);
|
||||
AstCCast* castp = new AstCCast (nodep->fileline(), nodep, needsize);
|
||||
castp->width(needsize, nodep->widthMin());
|
||||
relinkHandle.relink(castp);
|
||||
//if (debug()>8) castp->dumpTree(cout,"-castins: ");
|
||||
@@ -97,13 +97,13 @@ private:
|
||||
insertCast(nodep, castSize(nodep->backp()));
|
||||
}
|
||||
}
|
||||
void insureLower32Cast(AstCast* nodep) {
|
||||
void insureLower32Cast(AstCCast* nodep) {
|
||||
// If we have uint64 = CAST(uint64(x)) then the upcasting
|
||||
// really needs to be CAST(uint64(CAST(uint32(x))).
|
||||
// Otherwise a (uint64)(a>b) would return wrong value, as
|
||||
// less than has undeterministic signedness.
|
||||
if (nodep->isQuad() && !nodep->lhsp()->isQuad()
|
||||
&& !nodep->lhsp()->castCast()) {
|
||||
&& !nodep->lhsp()->castCCast()) {
|
||||
insertCast(nodep->lhsp(), VL_WORDSIZE);
|
||||
}
|
||||
}
|
||||
@@ -130,12 +130,12 @@ private:
|
||||
if (nodep->sizeMattersRhs()) insureCast(nodep->rhsp());
|
||||
if (nodep->sizeMattersThs()) insureCast(nodep->thsp());
|
||||
}
|
||||
virtual void visit(AstCast* nodep, AstNUser*) {
|
||||
virtual void visit(AstCCast* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
insureLower32Cast(nodep);
|
||||
nodep->user1(1);
|
||||
}
|
||||
virtual void visit(AstUnaryMin* nodep, AstNUser*) {
|
||||
virtual void visit(AstNegate* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->user1(nodep->lhsp()->user1());
|
||||
if (nodep->lhsp()->widthMin()==1) {
|
||||
@@ -149,7 +149,7 @@ private:
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
if (!nodep->lvalue()
|
||||
&& !nodep->backp()->castCast()
|
||||
&& !nodep->backp()->castCCast()
|
||||
&& nodep->backp()->castNodeMath()
|
||||
&& nodep->backp()->width()
|
||||
&& castSize(nodep) != castSize(nodep->varp())) {
|
||||
|
||||
+30
-6
@@ -46,6 +46,8 @@
|
||||
#include "V3EmitV.h"
|
||||
#include "V3File.h"
|
||||
|
||||
#define CDC_WEIGHT_ASYNC 0x1000 // Weight for edges that feed async logic
|
||||
|
||||
//######################################################################
|
||||
|
||||
class CdcBaseVisitor : public AstNVisitor {
|
||||
@@ -314,7 +316,9 @@ private:
|
||||
UINFO(3,__FUNCTION__<<": "<<endl);
|
||||
//if (debug()>6) m_graph.dump();
|
||||
if (debug()>6) m_graph.dumpDotFilePrefixed("cdc_pre");
|
||||
m_graph.removeRedundantEdgesSum(&V3GraphEdge::followAlwaysTrue);
|
||||
//
|
||||
m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue); // This will MAX across edge weights
|
||||
//
|
||||
m_graph.dumpDotFilePrefixed("cdc_simp");
|
||||
//
|
||||
analyzeReset();
|
||||
@@ -411,12 +415,15 @@ private:
|
||||
CdcEitherVertex* eToVertexp = (CdcEitherVertex*)edgep->top();
|
||||
if (!eToVertexp) targetp = eToVertexp;
|
||||
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(eToVertexp)) {
|
||||
if (vvertexp->isFlop()) {
|
||||
if (vvertexp->isFlop() // IE the target flop that is upsetting us
|
||||
&& edgep->weight() >= CDC_WEIGHT_ASYNC) { // And this signal feeds an async reset line
|
||||
targetp = eToVertexp;
|
||||
//UINFO(9," targetasync "<<targetp->name()<<" "<<" from "<<vertexp->name()<<endl);
|
||||
break;
|
||||
}
|
||||
} // else it might be random logic that's not relevant
|
||||
}
|
||||
//UINFO(9," finalflop "<<targetp->name()<<" "<<targetp->nodep()->fileline()<<endl);
|
||||
warnAndFile(markp->nodep(),V3ErrorCode::CDCRSTLOGIC,"Logic in path that feeds async reset, via signal: "+nodep->prettyName());
|
||||
dumpAsyncRecurse(targetp, "", " ",0);
|
||||
}
|
||||
@@ -469,6 +476,12 @@ private:
|
||||
|
||||
void edgeReport() {
|
||||
// Make report of all signal names and what clock edges they have
|
||||
//
|
||||
// Due to flattening, many interesting direct-connect signals are
|
||||
// lost, so we can't make a report showing I/Os for a low level
|
||||
// module. Disabling flattening though makes us consider each
|
||||
// signal in it's own unique clock domain.
|
||||
|
||||
UINFO(3,__FUNCTION__<<": "<<endl);
|
||||
|
||||
// Trace all sources and sinks
|
||||
@@ -498,6 +511,10 @@ private:
|
||||
|
||||
ostringstream os;
|
||||
os.setf(ios::left);
|
||||
// Module name - doesn't work due to flattening having lost the original
|
||||
// so we assume the modulename matches the filebasename
|
||||
string fname = vvertexp->varScp()->fileline()->filebasename() + ":";
|
||||
os<<" "<<setw(20)<<fname;
|
||||
os<<" "<<setw(8)<<whatp;
|
||||
os<<" "<<setw(40)<<vvertexp->varScp()->prettyName();
|
||||
os<<" SRC=";
|
||||
@@ -618,8 +635,9 @@ private:
|
||||
if (!varscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp\n");
|
||||
CdcVarVertex* varvertexp = makeVarVertex(varscp);
|
||||
UINFO(5," VARREF to "<<varscp<<endl);
|
||||
// We use weight of one; if we ref the var more than once, when we simplify,
|
||||
// the weight will increase
|
||||
// We use weight of one for normal edges,
|
||||
// Weight of CDC_WEIGHT_ASYNC to indicate feeds async (for reporting)
|
||||
// When simplify we'll take the MAX weight
|
||||
if (nodep->lvalue()) {
|
||||
new V3GraphEdge(&m_graph, m_logicVertexp, varvertexp, 1);
|
||||
if (m_inDly) {
|
||||
@@ -628,7 +646,13 @@ private:
|
||||
varvertexp->srcDomainSet(true);
|
||||
}
|
||||
} else {
|
||||
new V3GraphEdge(&m_graph, varvertexp, m_logicVertexp, 1);
|
||||
if (varvertexp->cntAsyncRst()) {
|
||||
//UINFO(9," edgeasync "<<varvertexp->name()<<" to "<<m_logicVertexp<<endl);
|
||||
new V3GraphEdge(&m_graph, varvertexp, m_logicVertexp, CDC_WEIGHT_ASYNC);
|
||||
} else {
|
||||
//UINFO(9," edgena "<<varvertexp->name()<<" to "<<m_logicVertexp<<endl);
|
||||
new V3GraphEdge(&m_graph, varvertexp, m_logicVertexp, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -725,7 +749,7 @@ public:
|
||||
|
||||
nodep->accept(*this);
|
||||
analyze();
|
||||
//edgeReport(); // Not useful at the moment
|
||||
if (debug()>=1) edgeReport(); // Not useful to users at the moment
|
||||
|
||||
if (0) { *m_ofp<<"\nDBG-test-dumper\n"; V3EmitV::verilogPrefixedTree(nodep, *m_ofp, "DBG ",40,NULL,true); *m_ofp<<endl; }
|
||||
}
|
||||
|
||||
+2
-1
@@ -315,6 +315,7 @@ public:
|
||||
m_exprp = exprp;
|
||||
m_original = original;
|
||||
m_state = STATE_UNKNOWN;
|
||||
m_cloning = false;
|
||||
if (debug()>=9) nodep->dumpTree(cout," GateBodyIn: ");
|
||||
nodep->bodysp()->iterateAndNext(*this);
|
||||
if (debug()>=9) nodep->dumpTree(cout," GateBodyOut: ");
|
||||
@@ -696,7 +697,7 @@ class GaterVisitor : public GaterBaseVisitor {
|
||||
// Blow old statements from new body
|
||||
GaterBodyVisitor(alwp,exprp,false);
|
||||
|
||||
m_statGaters++;
|
||||
++m_statGaters;
|
||||
if (debug()>=9) alwp->dumpTree(cout," new: ");
|
||||
}
|
||||
|
||||
|
||||
+6
-4
@@ -70,8 +70,8 @@ protected:
|
||||
virtual ~CombBaseVisitor() {}
|
||||
|
||||
//***** optimization levels
|
||||
bool emptyFunctionDeletion() { return true; }
|
||||
bool duplicateFunctionCombine() { return true; }
|
||||
static bool emptyFunctionDeletion() { return true; }
|
||||
static bool duplicateFunctionCombine() { return true; }
|
||||
// Note this is disabled, it still needed work
|
||||
// Also repair it for DPI functions; when make __common need to insure proper
|
||||
// flags get inherited from the old to new AstCFunc, and that AstText doesn't
|
||||
@@ -146,7 +146,9 @@ private:
|
||||
}
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
CombCallVisitor() {}
|
||||
CombCallVisitor() {
|
||||
m_find = false;
|
||||
}
|
||||
virtual ~CombCallVisitor() {}
|
||||
void main(AstNetlist* nodep) {
|
||||
nodep->accept(*this);
|
||||
@@ -257,7 +259,7 @@ private:
|
||||
UINFO(5," DupFunc "<<hex<<V3Hash(newfuncp->user4p())<<" "<<newfuncp<<endl);
|
||||
UINFO(5," and "<<hex<<V3Hash(oldfuncp->user4p())<<" "<<oldfuncp<<endl);
|
||||
// Mark user3p on entire old tree, so we don't process it more
|
||||
m_statCombs++;
|
||||
++m_statCombs;
|
||||
CombMarkVisitor visitor(oldfuncp);
|
||||
m_call.replaceFunc(oldfuncp, newfuncp);
|
||||
oldfuncp->unlinkFrBack();
|
||||
|
||||
+126
-13
@@ -37,7 +37,6 @@
|
||||
#include "V3Const.h"
|
||||
#include "V3Ast.h"
|
||||
#include "V3Width.h"
|
||||
#include "V3Signed.h"
|
||||
#include "V3Simulate.h"
|
||||
|
||||
//######################################################################
|
||||
@@ -290,13 +289,61 @@ private:
|
||||
// SEL(EXTEND(any,width,...),(width-1),0) -> ...
|
||||
// Since select's return unsigned, this is always an extend
|
||||
AstExtend* extendp = nodep->fromp()->castExtend();
|
||||
return (m_doV
|
||||
&& extendp
|
||||
&& nodep->lsbp()->castConst()
|
||||
&& nodep->widthp()->castConst()
|
||||
&& nodep->lsbConst()==0
|
||||
&& (int)nodep->widthConst()==extendp->lhsp()->width()
|
||||
);
|
||||
if (!(m_doV
|
||||
&& extendp
|
||||
&& nodep->lsbp()->castConst()
|
||||
&& nodep->widthp()->castConst()
|
||||
&& nodep->lsbConst()==0
|
||||
&& (int)nodep->widthConst()==extendp->lhsp()->width()
|
||||
)) return false;
|
||||
replaceWChild(nodep, extendp->lhsp()); nodep=NULL;
|
||||
return true;
|
||||
}
|
||||
bool operandSelBiLower(AstSel* nodep) {
|
||||
// SEL(ADD(a,b),(width-1),0) -> ADD(SEL(a),SEL(b))
|
||||
// Add or any operation which doesn't care if we discard top bits
|
||||
AstNodeBiop* bip = nodep->fromp()->castNodeBiop();
|
||||
if (!(m_doV
|
||||
&& bip
|
||||
&& nodep->lsbp()->castConst()
|
||||
&& nodep->widthp()->castConst()
|
||||
&& nodep->lsbConst()==0
|
||||
)) return false;
|
||||
if (debug()>=9) nodep->dumpTree(cout,"SEL(BI)-in:");
|
||||
AstNode* bilhsp = bip->lhsp()->unlinkFrBack();
|
||||
AstNode* birhsp = bip->rhsp()->unlinkFrBack();
|
||||
bip->lhsp(new AstSel(nodep->fileline(), bilhsp, 0, nodep->widthConst()));
|
||||
bip->rhsp(new AstSel(nodep->fileline(), birhsp, 0, nodep->widthConst()));
|
||||
if (debug()>=9) bip->dumpTree(cout,"SEL(BI)-ou:");
|
||||
replaceWChild(nodep, bip); nodep=NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operandBiExtendConst(AstNodeBiop* nodep) {
|
||||
// Loop unrolling likes standalone compares
|
||||
// EQ(EXTEND(xx{width3}), const{width32}) -> EQ(xx{3},const{3})
|
||||
// Beware that the constant must have zero bits (+ 1 if signed) or compare
|
||||
// would be incorrect
|
||||
AstExtend* extendp = nodep->lhsp()->castExtend();
|
||||
if (!extendp) return false;
|
||||
AstNode* smallerp = extendp->lhsp();
|
||||
int subsize = smallerp->width();
|
||||
AstConst* constp = nodep->rhsp()->castConst();
|
||||
if (!constp) return false;
|
||||
if (!constp->num().isBitsZero(constp->width()-1, subsize)) return false;
|
||||
//
|
||||
if (debug()>=9) nodep->dumpTree(cout,"BI(EXTEND)-in:");
|
||||
smallerp->unlinkFrBack();
|
||||
extendp->unlinkFrBack()->deleteTree(); // aka nodep->lhsp.
|
||||
nodep->lhsp(smallerp);
|
||||
|
||||
constp->unlinkFrBack();
|
||||
V3Number num (constp->fileline(), subsize);
|
||||
num.opAssign(constp->num());
|
||||
nodep->rhsp(new AstConst(constp->fileline(), num));
|
||||
constp->deleteTree(); constp=NULL;
|
||||
if (debug()>=9) nodep->dumpTree(cout,"BI(EXTEND)-ou:");
|
||||
return true;
|
||||
}
|
||||
|
||||
AstNode* afterComment(AstNode* nodep) {
|
||||
@@ -774,7 +821,9 @@ private:
|
||||
AstNodeAssign* asn2ap=nodep->cloneType(lc2p, sel2p)->castNodeAssign();
|
||||
asn1ap->width(msb1-lsb1+1,msb1-lsb1+1);
|
||||
asn2ap->width(msb2-lsb2+1,msb2-lsb2+1);
|
||||
// cppcheck-suppress nullPointer // addNext deals with it
|
||||
newp = newp->addNext(asn1ap);
|
||||
// cppcheck-suppress nullPointer // addNext deals with it
|
||||
newp = newp->addNext(asn2ap);
|
||||
} else {
|
||||
if (!m_modp) nodep->v3fatalSrc("Not under module");
|
||||
@@ -805,12 +854,16 @@ private:
|
||||
asn2ap->width(msb2-lsb2+1,msb2-lsb2+1);
|
||||
asn2bp->width(msb2-lsb2+1,msb2-lsb2+1);
|
||||
// This order matters
|
||||
// cppcheck-suppress nullPointer // addNext deals with it
|
||||
newp = newp->addNext(asn1ap);
|
||||
// cppcheck-suppress nullPointer // addNext deals with it
|
||||
newp = newp->addNext(asn2ap);
|
||||
// cppcheck-suppress nullPointer // addNext deals with it
|
||||
newp = newp->addNext(asn1bp);
|
||||
// cppcheck-suppress nullPointer // addNext deals with it
|
||||
newp = newp->addNext(asn2bp);
|
||||
}
|
||||
if (debug()>=9) newp->dumpTreeAndNext(cout," _new: ");
|
||||
if (debug()>=9 && newp) newp->dumpTreeAndNext(cout," _new: ");
|
||||
nodep->addNextHere(newp);
|
||||
// Cleanup
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
@@ -1061,6 +1114,38 @@ private:
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
|
||||
void replaceSelIntoBiop(AstSel* nodep) {
|
||||
// SEL(BUFIF1(a,b),1,bit) => BUFIF1(SEL(a,1,bit),SEL(b,1,bit))
|
||||
AstNodeBiop* fromp = nodep->fromp()->unlinkFrBack()->castNodeBiop();
|
||||
if (!fromp) nodep->v3fatalSrc("Called on non biop");
|
||||
AstNode* lsbp = nodep->lsbp()->unlinkFrBack();
|
||||
AstNode* widthp = nodep->widthp()->unlinkFrBack();
|
||||
//
|
||||
AstNode* bilhsp = fromp->lhsp()->unlinkFrBack();
|
||||
AstNode* birhsp = fromp->rhsp()->unlinkFrBack();
|
||||
//
|
||||
fromp->lhsp(new AstSel(nodep->fileline(),
|
||||
bilhsp, lsbp->cloneTree(true), widthp->cloneTree(true)));
|
||||
fromp->rhsp(new AstSel(nodep->fileline(),
|
||||
birhsp, lsbp, widthp));
|
||||
fromp->widthSignedFrom(nodep);
|
||||
nodep->replaceWith(fromp); nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
void replaceSelIntoUniop(AstSel* nodep) {
|
||||
// SEL(NOT(a),1,bit) => NOT(SEL(a,bit))
|
||||
AstNodeUniop* fromp = nodep->fromp()->unlinkFrBack()->castNodeUniop();
|
||||
if (!fromp) nodep->v3fatalSrc("Called on non biop");
|
||||
AstNode* lsbp = nodep->lsbp()->unlinkFrBack();
|
||||
AstNode* widthp = nodep->widthp()->unlinkFrBack();
|
||||
//
|
||||
AstNode* bilhsp = fromp->lhsp()->unlinkFrBack();
|
||||
//
|
||||
fromp->lhsp(new AstSel(nodep->fileline(),
|
||||
bilhsp, lsbp->cloneTree(true), widthp->cloneTree(true)));
|
||||
fromp->widthSignedFrom(nodep);
|
||||
nodep->replaceWith(fromp); nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (!nodep->varp()) nodep->v3fatalSrc("Not linked");
|
||||
@@ -1439,7 +1524,7 @@ private:
|
||||
if (!inPct && ch=='%') {
|
||||
inPct = true;
|
||||
fmt = ch;
|
||||
} else if (inPct && isdigit(ch)) {
|
||||
} else if (inPct && (isdigit(ch) || ch=='.')) {
|
||||
fmt += ch;
|
||||
} else if (inPct) {
|
||||
inPct = false;
|
||||
@@ -1455,7 +1540,7 @@ private:
|
||||
UINFO(9," DispConst: "<<fmt<<" -> "<<out<<" for "<<argp<<endl);
|
||||
{ // fmt = out w/ replace % with %% as it must be literal.
|
||||
fmt = "";
|
||||
for (string::iterator pos = out.begin(); pos != out.end(); pos++) {
|
||||
for (string::iterator pos = out.begin(); pos != out.end(); ++pos) {
|
||||
if (*pos == '%') fmt += '%';
|
||||
fmt += *pos;
|
||||
}
|
||||
@@ -1584,7 +1669,7 @@ private:
|
||||
TREEOP ("AstShiftRS{$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
|
||||
TREEOP ("AstXor {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP ("AstXnor {$lhsp.isZero, $rhsp}", "AstNot{$rhsp}");
|
||||
TREEOP ("AstSub {$lhsp.isZero, $rhsp}", "AstUnaryMin{$rhsp}");
|
||||
TREEOP ("AstSub {$lhsp.isZero, $rhsp}", "AstNegate{$rhsp}");
|
||||
TREEOP ("AstAdd {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
|
||||
TREEOP ("AstAnd {$lhsp, $rhsp.isZero}", "replaceZero(nodep)");
|
||||
TREEOP ("AstLogAnd{$lhsp, $rhsp.isZero}", "replaceZero(nodep)");
|
||||
@@ -1684,6 +1769,13 @@ private:
|
||||
TREEOP ("AstShiftL{operandShiftShift(nodep)}", "replaceShiftShift(nodep)");
|
||||
TREEOP ("AstShiftR{operandShiftShift(nodep)}", "replaceShiftShift(nodep)");
|
||||
TREEOP ("AstWordSel{operandWordOOB(nodep)}", "replaceZero(nodep)");
|
||||
// Compress out EXTENDs to appease loop unroller
|
||||
TREEOPV("AstEq {$lhsp.castExtend,operandBiExtendConst(nodep)}", "DONE");
|
||||
TREEOPV("AstNeq {$lhsp.castExtend,operandBiExtendConst(nodep)}", "DONE");
|
||||
TREEOPV("AstGt {$lhsp.castExtend,operandBiExtendConst(nodep)}", "DONE");
|
||||
TREEOPV("AstGte {$lhsp.castExtend,operandBiExtendConst(nodep)}", "DONE");
|
||||
TREEOPV("AstLt {$lhsp.castExtend,operandBiExtendConst(nodep)}", "DONE");
|
||||
TREEOPV("AstLte {$lhsp.castExtend,operandBiExtendConst(nodep)}", "DONE");
|
||||
// Identical operands on both sides
|
||||
// AstLogAnd/AstLogOr already converted to AstAnd/AstOr for these rules
|
||||
// AstAdd->ShiftL(#,1) but uncommon
|
||||
@@ -1696,17 +1788,23 @@ private:
|
||||
TREEOP ("AstXnor {operandsSame($lhsp,,$rhsp)}", "replaceAllOnes(nodep)");
|
||||
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 ("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 ("AstGtS {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
|
||||
TREEOP ("AstGte {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
|
||||
TREEOP ("AstGteD {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 ("AstLtS {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
|
||||
TREEOP ("AstLte {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
|
||||
TREEOP ("AstLteD {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 ("AstNeqCase{operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
|
||||
TREEOP ("AstNeqWild{operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
|
||||
TREEOP ("AstLogAnd {operandsSame($lhsp,,$rhsp), $lhsp.width1}", "replaceWLhs(nodep)");
|
||||
@@ -1761,12 +1859,27 @@ private:
|
||||
TREEOPV("AstReplicate{$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)}", "replaceWChild(nodep, nodep->fromp()->castExtend()->lhsp())");
|
||||
TREEOPV("AstSel{operandSelExtend(nodep)}", "DONE");
|
||||
TREEOPV("AstSel{operandSelFull(nodep)}", "replaceWChild(nodep, nodep->fromp())");
|
||||
TREEOPV("AstSel{$fromp.castSel}", "replaceSelSel(nodep)");
|
||||
TREEOPV("AstSel{$fromp.castAdd, operandSelBiLower(nodep)}", "DONE");
|
||||
TREEOPV("AstSel{$fromp.castAnd, operandSelBiLower(nodep)}", "DONE");
|
||||
TREEOPV("AstSel{$fromp.castOr, operandSelBiLower(nodep)}", "DONE");
|
||||
TREEOPV("AstSel{$fromp.castSub, operandSelBiLower(nodep)}", "DONE");
|
||||
TREEOPV("AstSel{$fromp.castXnor,operandSelBiLower(nodep)}", "DONE");
|
||||
TREEOPV("AstSel{$fromp.castXor, operandSelBiLower(nodep)}", "DONE");
|
||||
TREEOPC("AstSel{$fromp.castConst, $lsbp.castConst, $widthp.castConst, }", "replaceConst(nodep)");
|
||||
TREEOPV("AstSel{$fromp.castConcat, $lsbp.castConst, $widthp.castConst, }", "replaceSelConcat(nodep)");
|
||||
TREEOPV("AstSel{$fromp.castReplicate, $lsbp.castConst, $widthp.isOne, }", "replaceSelReplicate(nodep)");
|
||||
// V3Tristate requires selects below BufIf1.
|
||||
// Also do additional operators that are bit-independent, but only definite
|
||||
// win if bit select is a constant (otherwise we may need to compute bit index several times)
|
||||
TREEOPV("AstSel{$fromp.castBufIf1}", "replaceSelIntoBiop(nodep)");
|
||||
TREEOPV("AstSel{$fromp.castNot}", "replaceSelIntoUniop(nodep)");
|
||||
TREEOPV("AstSel{$fromp.castAnd,$lhsp.castConst}", "replaceSelIntoUniop(nodep)");
|
||||
TREEOPV("AstSel{$fromp.castOr,$lhsp.castConst}", "replaceSelIntoUniop(nodep)");
|
||||
TREEOPV("AstSel{$fromp.castXor,$lhsp.castConst}", "replaceSelIntoUniop(nodep)");
|
||||
TREEOPV("AstSel{$fromp.castXnor,$lhsp.castConst}", "replaceSelIntoUniop(nodep)");
|
||||
// Conversions
|
||||
TREEOPV("AstRedXnor{$lhsp}", "AstNot{AstRedXor{$lhsp}}"); // Just eliminate XNOR's
|
||||
TREEOPV("AstLogIf {$lhsp, $rhsp}", "AstLogOr{AstLogNot{$lhsp},$rhsp}");
|
||||
|
||||
@@ -97,7 +97,7 @@ private:
|
||||
removep->unlinkFrBack(); pushDeletep(removep); removep=NULL;
|
||||
// Remove node from comparison so don't hit it again
|
||||
hashed.erase(dupit);
|
||||
m_statToggleJoins++;
|
||||
++m_statToggleJoins;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +122,12 @@ private:
|
||||
nodep->packagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
virtual void visit(AstEnumItemRef* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->packagep()) {
|
||||
nodep->packagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVarScope* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
m_vscsp.push_back(nodep);
|
||||
|
||||
+1
-3
@@ -224,7 +224,6 @@ private:
|
||||
}
|
||||
//
|
||||
//=== Setting/not setting boolean: __Vdlyvset__
|
||||
bool sharedVset = false;
|
||||
AstVarScope* setvscp;
|
||||
|
||||
if (nodep->user3p()) {
|
||||
@@ -232,9 +231,8 @@ private:
|
||||
// then we told this nodep->user3 we can use its Vdlyvset rather than making a new one.
|
||||
// This is good for code like:
|
||||
// for (i=0; i<5; i++) vector[i] <= something;
|
||||
sharedVset = true;
|
||||
setvscp = nodep->user3p()->castNode()->castVarScope();
|
||||
m_statSharedSet++;
|
||||
++m_statSharedSet;
|
||||
} else { // Create new one
|
||||
string setvarname = (string("__Vdlyvset__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
|
||||
setvscp = createVarSc(varrefp->varScopep(), setvarname, 1);
|
||||
|
||||
+56
-13
@@ -55,9 +55,9 @@ public:
|
||||
}
|
||||
|
||||
// ACCESSORS
|
||||
int splitFilenum() { return m_splitFilenum; }
|
||||
int splitFilenum() const { return m_splitFilenum; }
|
||||
int splitFilenumInc() { m_splitSize = 0; return ++m_splitFilenum; }
|
||||
int splitSize() { return m_splitSize; }
|
||||
int splitSize() const { return m_splitSize; }
|
||||
void splitSizeInc(AstNode* nodep) { m_splitSize += EmitCBaseCounterVisitor(nodep).count(); }
|
||||
bool splitNeeded() { return (splitSize() && v3Global.opt.outputSplit() > 1
|
||||
&& v3Global.opt.outputSplit() < splitSize()); }
|
||||
@@ -127,6 +127,7 @@ public:
|
||||
nodep->lhsp()->iterateAndNext(*this); puts(", ");
|
||||
} else if (nodep->isWide()
|
||||
&& nodep->lhsp()->castVarRef()
|
||||
&& !nodep->rhsp()->castCMath()
|
||||
&& !nodep->rhsp()->castVarRef()
|
||||
&& !nodep->rhsp()->castArraySel()) {
|
||||
// Wide functions assign into the array directly, don't need separate assign statement
|
||||
@@ -343,13 +344,11 @@ public:
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstFClose* nodep, AstNUser*) {
|
||||
puts("if (");
|
||||
puts("VL_FCLOSE_I(");
|
||||
nodep->filep()->iterateAndNext(*this);
|
||||
puts(") { fclose (VL_CVT_Q_FP(");
|
||||
nodep->filep()->iterateAndNext(*this);
|
||||
puts(")); ");
|
||||
puts("); ");
|
||||
nodep->filep()->iterateAndNext(*this); // For saftey, so user doesn't later WRITE with it.
|
||||
puts("=0; }\n");
|
||||
puts("=0;\n");
|
||||
}
|
||||
virtual void visit(AstFFlush* nodep, AstNUser*) {
|
||||
if (!nodep->filep()) {
|
||||
@@ -357,11 +356,35 @@ public:
|
||||
} else {
|
||||
puts("if (");
|
||||
nodep->filep()->iterateAndNext(*this);
|
||||
puts(") { fflush (VL_CVT_Q_FP(");
|
||||
puts(") { fflush (VL_CVT_I_FP(");
|
||||
nodep->filep()->iterateAndNext(*this);
|
||||
puts(")); }\n");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstSystemT* nodep, AstNUser*) {
|
||||
puts("(void)VL_SYSTEM_I");
|
||||
emitIQW(nodep->lhsp());
|
||||
puts("(");
|
||||
if (nodep->lhsp()->isWide()) {
|
||||
puts(cvtToStr(nodep->lhsp()->widthWords()));
|
||||
putbs(", ");
|
||||
}
|
||||
checkMaxWords(nodep->lhsp());
|
||||
nodep->lhsp()->iterateAndNext(*this);
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstSystemF* nodep, AstNUser*) {
|
||||
puts("VL_SYSTEM_I");
|
||||
emitIQW(nodep->lhsp());
|
||||
puts("(");
|
||||
if (nodep->lhsp()->isWide()) {
|
||||
puts(cvtToStr(nodep->lhsp()->widthWords()));
|
||||
putbs(", ");
|
||||
}
|
||||
checkMaxWords(nodep->lhsp());
|
||||
nodep->lhsp()->iterateAndNext(*this);
|
||||
puts(")");
|
||||
}
|
||||
virtual void visit(AstJumpGo* nodep, AstNUser*) {
|
||||
puts("goto __Vlabel"+cvtToStr(nodep->labelp()->labelNum())+";\n");
|
||||
}
|
||||
@@ -475,7 +498,7 @@ public:
|
||||
}
|
||||
visit(nodep->castNodeBiop(), vup);
|
||||
}
|
||||
virtual void visit(AstCast* nodep, AstNUser*) {
|
||||
virtual void visit(AstCCast* nodep, AstNUser*) {
|
||||
// Extending a value of the same word width is just a NOP.
|
||||
if (nodep->size()>VL_WORDSIZE) {
|
||||
puts("(QData)(");
|
||||
@@ -546,6 +569,8 @@ public:
|
||||
ofp()->printf(",0x%08" VL_PRI64 "x", (vluint64_t)(nodep->num().dataWord(word)));
|
||||
}
|
||||
ofp()->printf(",0x%08" VL_PRI64 "x)", (vluint64_t)(nodep->num().dataWord(0)));
|
||||
} else if (nodep->isDouble()) {
|
||||
ofp()->printf("%.17g", nodep->num().toDouble());
|
||||
} else if (nodep->isQuad()) {
|
||||
vluint64_t num = nodep->toUQuad();
|
||||
if (num<10) ofp()->printf("VL_ULL(%" VL_PRI64 "d)", num);
|
||||
@@ -829,6 +854,8 @@ class EmitCImp : EmitCStmts {
|
||||
public:
|
||||
EmitCImp() {
|
||||
m_modp = NULL;
|
||||
m_slow = false;
|
||||
m_fast = false;
|
||||
}
|
||||
virtual ~EmitCImp() {}
|
||||
void main(AstNodeModule* modp, bool slow, bool fast);
|
||||
@@ -1211,6 +1238,7 @@ void EmitCStmts::displayNode(AstNode* nodep, AstScopeName* scopenamep,
|
||||
switch (tolower(pos[0])) {
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
case '.':
|
||||
// Digits, like %5d, etc.
|
||||
vfmt += pos[0];
|
||||
inPct = true; // Get more digits
|
||||
@@ -1229,6 +1257,9 @@ void EmitCStmts::displayNode(AstNode* nodep, AstScopeName* scopenamep,
|
||||
case 'h':
|
||||
case 'x': displayArg(nodep,&elistp,isScan, vfmt,'x'); break;
|
||||
case 's': displayArg(nodep,&elistp,isScan, vfmt,'s'); break;
|
||||
case 'e': displayArg(nodep,&elistp,isScan, vfmt,'e'); break;
|
||||
case 'f': displayArg(nodep,&elistp,isScan, vfmt,'f'); break;
|
||||
case 'g': displayArg(nodep,&elistp,isScan, vfmt,'g'); break;
|
||||
case 'm': {
|
||||
if (!scopenamep) nodep->v3fatalSrc("Display with %m but no AstScopeName");
|
||||
string suffix = scopenamep->scopePrettyName();
|
||||
@@ -1419,6 +1450,7 @@ void EmitCImp::emitStaticDecl(AstNodeModule* modp) {
|
||||
// Need implementation here. Be careful of alignment code; needs to be uniquified
|
||||
// with module name to avoid multiple symbols.
|
||||
//emitVarList(modp->stmtsp(), EVL_ALL, modp->name());
|
||||
puts(""); // NOP for cppcheck, otherwise const function
|
||||
}
|
||||
|
||||
void EmitCImp::emitTextSection(AstType type) {
|
||||
@@ -1619,7 +1651,12 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
|
||||
if (v3Global.needHInlines()) { // Set by V3EmitCInlines; should have been called before us
|
||||
puts("#include \""+topClassName()+"__Inlines.h\"\n");
|
||||
}
|
||||
// No __Dpi.h needed, we've shimmed it all into the interface
|
||||
if (v3Global.dpi()) {
|
||||
// do this before including our main .h file so that any references to
|
||||
// types defined in svdpi.h are available
|
||||
puts("#include \""+ topClassName() +"__Dpi.h\"\n");
|
||||
puts("\n");
|
||||
}
|
||||
|
||||
// Declare foreign instances up front to make C++ happy
|
||||
puts("class "+symClassName()+";\n");
|
||||
@@ -1797,8 +1834,10 @@ void EmitCImp::emitImp(AstNodeModule* modp) {
|
||||
|
||||
// Us
|
||||
puts("#include \""+ symClassName() +".h\"\n");
|
||||
|
||||
if (v3Global.dpi()) {
|
||||
puts("#include \""+ topClassName() +"__Dpi.h\"\n");
|
||||
puts("\n");
|
||||
puts("#include \"verilated_dpi.h\"\n");
|
||||
}
|
||||
|
||||
if (optSystemPerl() && (splitFilenum() || !m_fast)) {
|
||||
@@ -2003,7 +2042,9 @@ class EmitCTrace : EmitCStmts {
|
||||
return varp->isSc() && varp->isScBv();
|
||||
}
|
||||
void emitTraceInitOne(AstTraceDecl* nodep) {
|
||||
if (nodep->isWide()) {
|
||||
if (nodep->isDouble()) {
|
||||
puts("vcdp->declDouble");
|
||||
} else if (nodep->isWide()) {
|
||||
puts("vcdp->declArray");
|
||||
} else if (nodep->isQuad()) {
|
||||
puts("vcdp->declQuad ");
|
||||
@@ -2032,7 +2073,9 @@ class EmitCTrace : EmitCStmts {
|
||||
string full = ((m_funcp->funcType() == AstCFuncType::TRACE_FULL
|
||||
|| m_funcp->funcType() == AstCFuncType::TRACE_FULL_SUB)
|
||||
? "full":"chg");
|
||||
if (nodep->isWide() || emitTraceIsScBv(nodep)) {
|
||||
if (nodep->isDouble()) {
|
||||
puts("vcdp->"+full+"Double");
|
||||
} else if (nodep->isWide() || emitTraceIsScBv(nodep)) {
|
||||
puts("vcdp->"+full+"Array");
|
||||
} else if (nodep->isQuad()) {
|
||||
puts("vcdp->"+full+"Quad ");
|
||||
|
||||
+4
-2
@@ -519,13 +519,15 @@ void EmitCSyms::emitDpiHdr() {
|
||||
puts("// Manually include this file where DPI .c import functions are declared to insure\n");
|
||||
puts("// the C functions match the expectations of the DPI imports.\n");
|
||||
puts("\n");
|
||||
puts("#include \"svdpi.h\"\n");
|
||||
puts("\n");
|
||||
puts("#ifdef __cplusplus\n");
|
||||
puts("extern \"C\" {\n");
|
||||
puts("#endif\n");
|
||||
puts("\n");
|
||||
|
||||
bool firstExp = false;
|
||||
bool firstImp = false;
|
||||
int firstExp = 0;
|
||||
int firstImp = 0;
|
||||
for (vector<AstCFunc*>::iterator it = m_dpis.begin(); it != m_dpis.end(); ++it) {
|
||||
AstCFunc* nodep = *it;
|
||||
if (nodep->dpiExportWrapper()) {
|
||||
|
||||
+9
-4
@@ -84,10 +84,15 @@ public:
|
||||
if (v3Global.opt.systemPerl()) {
|
||||
putMakeClassEntry(of, "Sp.cpp"); // Note Sp.cpp includes SpTraceVcdC
|
||||
}
|
||||
else if (v3Global.opt.trace()) {
|
||||
putMakeClassEntry(of, "verilated_vcd_c.cpp");
|
||||
if (v3Global.opt.systemC()) {
|
||||
putMakeClassEntry(of, "verilated_vcd_sc.cpp");
|
||||
else {
|
||||
if (v3Global.opt.coverage()) {
|
||||
putMakeClassEntry(of, "SpCoverage.cpp");
|
||||
}
|
||||
if (v3Global.opt.trace()) {
|
||||
putMakeClassEntry(of, "verilated_vcd_c.cpp");
|
||||
if (v3Global.opt.systemC()) {
|
||||
putMakeClassEntry(of, "verilated_vcd_sc.cpp");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,6 +217,9 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
}
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstDisable* nodep, AstNUser*) {
|
||||
putbs("disable "+nodep->name()+";\n");
|
||||
}
|
||||
virtual void visit(AstDisplay* nodep, AstNUser*) {
|
||||
visitNodeDisplay(nodep, nodep->filep(), nodep->fmtp()->text(), nodep->fmtp()->exprsp());
|
||||
}
|
||||
@@ -480,6 +483,10 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
putfs(nodep,nodep->prettyName());
|
||||
if (nodep->rangep()) { puts(" "); nodep->rangep()->iterateAndNext(*this); puts(" "); }
|
||||
}
|
||||
virtual void visit(AstConstDType* nodep, AstNUser*) {
|
||||
putfs(nodep,"const ");
|
||||
nodep->dtypep()->iterateAndNext(*this);
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
|
||||
if (nodep->dotted()!="") { putfs(nodep,nodep->dotted()); puts("."); puts(nodep->prettyName()); }
|
||||
else { putfs(nodep,nodep->prettyName()); }
|
||||
|
||||
+40
-7
@@ -34,8 +34,6 @@
|
||||
//======================================================================
|
||||
// Statics
|
||||
|
||||
FileLine FileLine::s_defaultFileLine = FileLine(EmptySecret());
|
||||
|
||||
int V3Error::s_errCount = 0;
|
||||
int V3Error::s_warnCount = 0;
|
||||
int V3Error::s_debugDefault = 0;
|
||||
@@ -66,12 +64,28 @@ V3ErrorCode::V3ErrorCode(const char* msgp) {
|
||||
m_e = V3ErrorCode::EC_ERROR;
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// FileLineSingleton class functions
|
||||
|
||||
int FileLineSingleton::nameToNumber(const string& filename) {
|
||||
// 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.
|
||||
map<string,int>::const_iterator iter = m_namemap.find(filename);
|
||||
if (VL_LIKELY(iter != m_namemap.end())) return iter->second;
|
||||
int num = m_names.size();
|
||||
m_names.push_back(filename);
|
||||
m_namemap.insert(make_pair(filename,num));
|
||||
return num;
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// FileLine class functions
|
||||
|
||||
FileLine::FileLine(FileLine::EmptySecret) {
|
||||
// Sort of a singleton
|
||||
m_lineno=0;
|
||||
m_filename="COMMAND_LINE";
|
||||
m_filenameno=singleton().nameToNumber("AstRoot");
|
||||
|
||||
m_warnOn=0;
|
||||
for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
|
||||
@@ -80,6 +94,19 @@ FileLine::FileLine(FileLine::EmptySecret) {
|
||||
}
|
||||
}
|
||||
|
||||
const string FileLine::filenameLetters() const {
|
||||
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 = m_filenameno;
|
||||
do {
|
||||
*--op = 'a'+num%26;
|
||||
num /= 26;
|
||||
} while (num);
|
||||
return op;
|
||||
}
|
||||
|
||||
string FileLine::lineDirectiveStrg(int enterExit) const {
|
||||
char numbuf[20]; sprintf(numbuf, "%d", lineno());
|
||||
char levelbuf[20]; sprintf(levelbuf, "%d", enterExit);
|
||||
@@ -262,6 +289,7 @@ void FileLine::deleteAllRemaining() {
|
||||
// Eventually the list will be empty and terminate the loop.
|
||||
}
|
||||
fileLineLeakChecks.clear();
|
||||
FileLineSingleton::clear();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -304,13 +332,18 @@ void V3Error::incErrors() {
|
||||
|
||||
void V3Error::abortIfErrors() {
|
||||
if (errorCount()) {
|
||||
v3fatal ("Exiting due to "<<dec<<errorOrWarnCount()<<" warning(s)\n");
|
||||
abortIfWarnings();
|
||||
}
|
||||
}
|
||||
|
||||
void V3Error::abortIfWarnings() {
|
||||
if (errorOrWarnCount()) {
|
||||
v3fatal ("Exiting due to "<<dec<<errorOrWarnCount()<<" warning(s)\n");
|
||||
bool exwarn = v3Global.opt.warnFatal() && warnCount();
|
||||
if (errorCount() && exwarn) {
|
||||
v3fatal ("Exiting due to "<<dec<<errorCount()<<" error(s), "<<warnCount()<<" warning(s)\n");
|
||||
} else if (errorCount()) {
|
||||
v3fatal ("Exiting due to "<<dec<<errorCount()<<" error(s)\n");
|
||||
} else if (exwarn) {
|
||||
v3fatal ("Exiting due to "<<dec<<warnCount()<<" warning(s)\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,7 +403,7 @@ void V3Error::suppressThisWarning() {
|
||||
}
|
||||
|
||||
void V3Error::v3errorEnd (ostringstream& sstr) {
|
||||
#ifdef __COVERITY__
|
||||
#if defined(__COVERITY__) || defined(__cppcheck__)
|
||||
if (s_errorCode==V3ErrorCode::EC_FATAL) __coverity_panic__(x);
|
||||
#endif
|
||||
if (!s_errorSuppressed
|
||||
|
||||
+62
-19
@@ -28,6 +28,8 @@
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <bitset>
|
||||
#include <map>
|
||||
#include <deque>
|
||||
|
||||
//######################################################################
|
||||
|
||||
@@ -46,13 +48,15 @@ public:
|
||||
I_LINT, // All lint messages
|
||||
I_DEF_NETTYPE_WIRE, // `default_nettype is WIRE (false=NONE)
|
||||
// Error codes:
|
||||
E_BLKLOOPINIT, // Error: Delayed assignment to array inside for loops
|
||||
E_MULTITOP, // Error: Multiple top level modules
|
||||
E_TASKNSVAR, // Error: Task I/O not simple
|
||||
E_BLKLOOPINIT, // Error: Delayed assignment to array inside for loops
|
||||
//
|
||||
// Warning codes:
|
||||
EC_FIRST_WARN, // Just a code so the program knows where to start warnings
|
||||
//
|
||||
ASSIGNDLY, // Assignment delays
|
||||
ASSIGNIN, // Assigning to input
|
||||
BLKANDNBLK, // Blocked and non-blocking assignments to same variable
|
||||
BLKSEQ, // Blocking assignments in sequential block
|
||||
CASEINCOMPLETE, // Case statement has missing values
|
||||
@@ -73,6 +77,7 @@ public:
|
||||
LITENDIAN, // Little bit endian vector
|
||||
MODDUP, // Duplicate module
|
||||
MULTIDRIVEN, // Driven from multiple blocks
|
||||
REALCVT, // Real conversion
|
||||
REDEFMACRO, // Redefining existing define macro
|
||||
STMTDLY, // Delayed statement
|
||||
SYMRSVDWORD, // Symbol is Reserved Word
|
||||
@@ -89,7 +94,7 @@ public:
|
||||
// ***Add new elements below also***
|
||||
};
|
||||
enum en m_e;
|
||||
inline V3ErrorCode () {}
|
||||
inline V3ErrorCode () : m_e(EC_MIN) {}
|
||||
inline V3ErrorCode (en _e) : m_e(_e) {}
|
||||
V3ErrorCode (const char* msgp); // Matching code or ERROR
|
||||
explicit inline V3ErrorCode (int _e) : m_e(static_cast<en>(_e)) {}
|
||||
@@ -101,9 +106,10 @@ public:
|
||||
// Boolean
|
||||
" I_COVERAGE", " I_TRACING", " I_LINT", " I_DEF_NETTYPE_WIRE",
|
||||
// Errors
|
||||
"MULTITOP", "TASKNSVAR", "BLKLOOPINIT",
|
||||
"BLKLOOPINIT", "MULTITOP", "TASKNSVAR",
|
||||
// Warnings
|
||||
" EC_FIRST_WARN",
|
||||
"ASSIGNDLY", "ASSIGNIN",
|
||||
"BLKANDNBLK", "BLKSEQ",
|
||||
"CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CDCRSTLOGIC", "CMPCONST",
|
||||
"COMBDLY", "DEFPARAM", "DECLFILENAME",
|
||||
@@ -111,7 +117,7 @@ public:
|
||||
"IFDEPTH", "IMPERFECTSCH", "IMPLICIT", "IMPURE", "INCABSPATH",
|
||||
"LITENDIAN", "MODDUP",
|
||||
"MULTIDRIVEN",
|
||||
"REDEFMACRO",
|
||||
"REALCVT", "REDEFMACRO",
|
||||
"STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET",
|
||||
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNSIGNED", "UNUSED",
|
||||
"VARHIDDEN", "WIDTH", "WIDTHCONCAT",
|
||||
@@ -125,7 +131,8 @@ public:
|
||||
bool dangerous() const { return ( m_e==COMBDLY ); }
|
||||
// Warnings we'll present to the user as errors
|
||||
// Later -Werror- options may make more of these.
|
||||
bool pretendError() const { return ( m_e==BLKANDNBLK || m_e==IMPURE || m_e==MODDUP || m_e==SYMRSVDWORD); }
|
||||
bool pretendError() const { return ( m_e==ASSIGNIN || m_e==BLKANDNBLK
|
||||
|| m_e==IMPURE || m_e==MODDUP || m_e==SYMRSVDWORD); }
|
||||
// Warnings to mention manual
|
||||
bool mentionManual() const { return ( m_e==EC_FATALSRC || pretendError() ); }
|
||||
|
||||
@@ -135,10 +142,12 @@ public:
|
||||
|| m_e==CMPCONST
|
||||
|| m_e==IMPLICIT
|
||||
|| m_e==LITENDIAN
|
||||
|| m_e==REALCVT
|
||||
|| m_e==UNSIGNED
|
||||
|| m_e==WIDTH); }
|
||||
// Warnings that are style only
|
||||
bool styleError() const { return ( m_e==BLKSEQ
|
||||
bool styleError() const { return ( m_e==ASSIGNDLY // More than style, but for backward compatibility
|
||||
|| m_e==BLKSEQ
|
||||
|| m_e==DEFPARAM
|
||||
|| m_e==DECLFILENAME
|
||||
|| m_e==INCABSPATH
|
||||
@@ -242,29 +251,58 @@ inline uint32_t cvtToHash(void* vp) {
|
||||
|
||||
//######################################################################
|
||||
|
||||
class FileLine;
|
||||
|
||||
class FileLineSingleton {
|
||||
map<string,int> m_namemap; // filenameno for each filename
|
||||
deque<string> m_names; // filename text for each filenameno
|
||||
// COSNTRUCTORS
|
||||
FileLineSingleton() { }
|
||||
~FileLineSingleton() { }
|
||||
protected:
|
||||
friend class FileLine;
|
||||
// METHODS
|
||||
int nameToNumber(const string& filename);
|
||||
string numberToName(int filenameno) { return m_names[filenameno]; }
|
||||
void clear() { m_namemap.clear(); m_names.clear(); }
|
||||
};
|
||||
|
||||
class FileLine {
|
||||
// File and line number of an object, mostly for error reporting
|
||||
int m_lineno;
|
||||
string m_filename;
|
||||
int m_filenameno;
|
||||
bitset<V3ErrorCode::_ENUM_MAX> m_warnOn;
|
||||
// Consider moving opt.language() into here, so can know language per-node
|
||||
static FileLine s_defaultFileLine;
|
||||
|
||||
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 filename(const string& name) { m_filename = name; }
|
||||
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_filename = filename; m_warnOn=s_defaultFileLine.m_warnOn; }
|
||||
FileLine (FileLine* fromp) { m_lineno=fromp->lineno(); m_filename = fromp->filename(); m_warnOn=fromp->m_warnOn; }
|
||||
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); }
|
||||
@@ -277,7 +315,8 @@ public:
|
||||
|
||||
int lineno () const { return m_lineno; }
|
||||
string ascii() const;
|
||||
const string filename () const { return m_filename; }
|
||||
const string filename () const { return singleton().numberToName(m_filenameno); }
|
||||
const string filenameLetters() const;
|
||||
const string filebasename () const;
|
||||
const string filebasenameNoExt () const;
|
||||
const string profileFuncname() const;
|
||||
@@ -289,7 +328,7 @@ public:
|
||||
void warnLintOff(bool flag);
|
||||
void warnStyleOff(bool flag);
|
||||
void warnStateFrom(const FileLine& from) { m_warnOn=from.m_warnOn; }
|
||||
void warnResetDefault() { warnStateFrom(s_defaultFileLine); }
|
||||
void warnResetDefault() { warnStateFrom(defaultFileLine()); }
|
||||
|
||||
// Specific flag ACCESSORS/METHODS
|
||||
bool coverageOn() const { return m_warnOn.test(V3ErrorCode::I_COVERAGE); }
|
||||
@@ -298,10 +337,14 @@ public:
|
||||
void tracingOn(bool flag) { warnOn(V3ErrorCode::I_TRACING,flag); }
|
||||
|
||||
// METHODS - Global
|
||||
static void globalWarnLintOff(bool flag) { s_defaultFileLine.warnLintOff(flag); }
|
||||
static void globalWarnStyleOff(bool flag) { s_defaultFileLine.warnStyleOff(flag); }
|
||||
static void globalWarnOff(V3ErrorCode code, bool flag) { s_defaultFileLine.warnOff(code, flag); }
|
||||
static bool globalWarnOff(const string& code, bool flag) { return s_defaultFileLine.warnOff(code, flag); }
|
||||
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); }
|
||||
|
||||
// METHODS - Called from netlist
|
||||
// Merge warning disables from another fileline
|
||||
@@ -313,8 +356,8 @@ public:
|
||||
|
||||
// OPERATORS
|
||||
void v3errorEnd(ostringstream& str);
|
||||
inline bool operator==(FileLine rhs) {
|
||||
return (m_lineno==rhs.m_lineno && m_filename==rhs.m_filename && m_warnOn==rhs.m_warnOn);
|
||||
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);
|
||||
|
||||
+22
-23
@@ -127,18 +127,18 @@ private:
|
||||
} else if (nodep->isQuad() && word==0) {
|
||||
AstNode* quadfromp = nodep->cloneTree(true);
|
||||
quadfromp->width(VL_QUADSIZE,quadfromp->widthMin());
|
||||
return new AstCast (nodep->fileline(),
|
||||
quadfromp,
|
||||
VL_WORDSIZE);
|
||||
return new AstCCast (nodep->fileline(),
|
||||
quadfromp,
|
||||
VL_WORDSIZE);
|
||||
} else if (nodep->isQuad() && word==1) {
|
||||
AstNode* quadfromp = nodep->cloneTree(true);
|
||||
quadfromp->width(VL_QUADSIZE,quadfromp->widthMin());
|
||||
return new AstCast (nodep->fileline(),
|
||||
new AstShiftR (nodep->fileline(),
|
||||
quadfromp,
|
||||
new AstConst (nodep->fileline(), VL_WORDSIZE),
|
||||
VL_WORDSIZE),
|
||||
VL_WORDSIZE);
|
||||
return new AstCCast (nodep->fileline(),
|
||||
new AstShiftR (nodep->fileline(),
|
||||
quadfromp,
|
||||
new AstConst (nodep->fileline(), VL_WORDSIZE),
|
||||
VL_WORDSIZE),
|
||||
VL_WORDSIZE);
|
||||
} else if (!nodep->isWide() && !nodep->isQuad() && word==0) {
|
||||
return nodep->cloneTree(true);
|
||||
} else { // Out of bounds
|
||||
@@ -324,7 +324,7 @@ private:
|
||||
nodep->v3fatalSrc("extending larger thing into smaller?");
|
||||
} else {
|
||||
UINFO(8," EXTEND(q<-l) "<<nodep<<endl);
|
||||
newp = new AstCast (nodep->fileline(), lhsp, nodep);
|
||||
newp = new AstCCast (nodep->fileline(), lhsp, nodep);
|
||||
}
|
||||
} else { // Long
|
||||
if (lhsp->isQuad() || lhsp->isWide()) {
|
||||
@@ -366,7 +366,7 @@ private:
|
||||
AstNode* lowwordp = new AstWordSel (nodep->fromp()->fileline(),
|
||||
nodep->fromp()->cloneTree(true),
|
||||
newSelBitWord(nodep->lsbp(), 0));
|
||||
if (nodep->isQuad() && !lowwordp->isQuad()) lowwordp = new AstCast(nodep->fileline(), lowwordp, nodep);
|
||||
if (nodep->isQuad() && !lowwordp->isQuad()) lowwordp = new AstCCast(nodep->fileline(), lowwordp, nodep);
|
||||
AstNode* lowp = new AstShiftR (nodep->fileline(),
|
||||
lowwordp,
|
||||
newSelBitBit(nodep->lsbp()),
|
||||
@@ -379,7 +379,7 @@ private:
|
||||
new AstWordSel (nodep->fromp()->fileline(),
|
||||
nodep->fromp()->cloneTree(true),
|
||||
newSelBitWord(nodep->lsbp(), 1));
|
||||
if (nodep->isQuad() && !midwordp->isQuad()) midwordp = new AstCast(nodep->fileline(), midwordp, nodep);
|
||||
if (nodep->isQuad() && !midwordp->isQuad()) midwordp = new AstCCast(nodep->fileline(), midwordp, nodep);
|
||||
// If we're selecting bit zero, then all 32 bits in word 1 get shifted << by 32 bits
|
||||
// else we need to form the lower word, so we << by 31 or less
|
||||
// nbitsfromlow <= (lsb==0) ? 64-bitbit(lsb) : 32-bitbit(lsb)
|
||||
@@ -417,7 +417,7 @@ private:
|
||||
new AstWordSel (nodep->fromp()->fileline(),
|
||||
nodep->fromp()->cloneTree(true),
|
||||
newSelBitWord(nodep->lsbp(), 2));
|
||||
if (nodep->isQuad() && !hiwordp->isQuad()) hiwordp = new AstCast(nodep->fileline(), hiwordp, nodep);
|
||||
if (nodep->isQuad() && !hiwordp->isQuad()) hiwordp = new AstCCast(nodep->fileline(), hiwordp, nodep);
|
||||
AstNode* himayp =
|
||||
new AstShiftL (nodep->fileline(),
|
||||
hiwordp,
|
||||
@@ -445,14 +445,14 @@ private:
|
||||
UINFO(8," SEL->SHIFT "<<nodep<<endl);
|
||||
AstNode* fromp = nodep->fromp()->unlinkFrBack();
|
||||
AstNode* lsbp = nodep->lsbp()->unlinkFrBack();
|
||||
if (nodep->isQuad() && !fromp->isQuad()) fromp = new AstCast(nodep->fileline(), fromp, nodep);
|
||||
if (nodep->isQuad() && !fromp->isQuad()) fromp = new AstCCast(nodep->fileline(), fromp, nodep);
|
||||
AstNode* newp = new AstShiftR (nodep->fileline(),
|
||||
fromp,
|
||||
dropCondBound(lsbp),
|
||||
nodep->width());
|
||||
newp->widthSignedFrom(nodep);
|
||||
if (!nodep->isQuad() && fromp->isQuad()) {
|
||||
newp = new AstCast (newp->fileline(), newp, nodep);
|
||||
newp = new AstCCast (newp->fileline(), newp, nodep);
|
||||
}
|
||||
newp->widthSignedFrom(nodep);
|
||||
replaceWithDelete(nodep,newp); nodep=NULL;
|
||||
@@ -546,7 +546,7 @@ private:
|
||||
destp->deleteTree(); destp=NULL;
|
||||
} else {
|
||||
UINFO(8," ASSIGNSEL(const,narrow) "<<nodep<<endl);
|
||||
if (destp->isQuad() && !rhsp->isQuad()) rhsp = new AstCast(nodep->fileline(), rhsp, nodep);
|
||||
if (destp->isQuad() && !rhsp->isQuad()) rhsp = new AstCCast(nodep->fileline(), rhsp, nodep);
|
||||
AstNode* oldvalp = destp->cloneTree(true);
|
||||
fixCloneLvalue(oldvalp);
|
||||
if (!ones) oldvalp = new AstAnd (lhsp->fileline(),
|
||||
@@ -620,7 +620,7 @@ private:
|
||||
V3Number maskwidth (nodep->fileline(), destp->widthMin());
|
||||
for (int bit=0; bit<(int)lhsp->widthConst(); bit++) maskwidth.setBit(bit,1);
|
||||
|
||||
if (destp->isQuad() && !rhsp->isQuad()) rhsp = new AstCast(nodep->fileline(), rhsp, nodep);
|
||||
if (destp->isQuad() && !rhsp->isQuad()) rhsp = new AstCCast(nodep->fileline(), rhsp, nodep);
|
||||
if (!ones)
|
||||
oldvalp = new AstAnd (lhsp->fileline(),
|
||||
new AstNot (lhsp->fileline(),
|
||||
@@ -655,8 +655,8 @@ private:
|
||||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
int rhsshift = rhsp->widthMin();
|
||||
if (nodep->isQuad() && !lhsp->isQuad()) lhsp = new AstCast(nodep->fileline(), lhsp, nodep);
|
||||
if (nodep->isQuad() && !rhsp->isQuad()) rhsp = new AstCast(nodep->fileline(), rhsp, nodep);
|
||||
if (nodep->isQuad() && !lhsp->isQuad()) lhsp = new AstCCast(nodep->fileline(), lhsp, nodep);
|
||||
if (nodep->isQuad() && !rhsp->isQuad()) rhsp = new AstCCast(nodep->fileline(), rhsp, nodep);
|
||||
AstNode* newp = new AstOr (nodep->fileline(),
|
||||
new AstShiftL (nodep->fileline(),
|
||||
lhsp,
|
||||
@@ -696,14 +696,13 @@ private:
|
||||
int lhswidth = lhsp->widthMin();
|
||||
if (lhswidth==1) {
|
||||
UINFO(8," REPLICATE(w1) "<<nodep<<endl);
|
||||
newp = new AstUnaryMin (nodep->fileline(),
|
||||
lhsp);
|
||||
newp = new AstNegate (nodep->fileline(), lhsp);
|
||||
} else {
|
||||
UINFO(8," REPLICATE "<<nodep<<endl);
|
||||
AstConst* constp = nodep->rhsp()->castConst();
|
||||
if (!constp) nodep->v3fatalSrc("Replication value isn't a constant. Checked earlier!");
|
||||
uint32_t times = constp->toUInt();
|
||||
if (nodep->isQuad() && !lhsp->isQuad()) lhsp = new AstCast(nodep->fileline(), lhsp, nodep);
|
||||
if (nodep->isQuad() && !lhsp->isQuad()) lhsp = new AstCCast(nodep->fileline(), lhsp, nodep);
|
||||
newp = lhsp->cloneTree(true);
|
||||
for (unsigned repnum=1; repnum<times; repnum++) {
|
||||
int rhsshift = repnum*lhswidth;
|
||||
@@ -731,7 +730,7 @@ private:
|
||||
for (int w=0; w<rhsp->widthWords(); w++) {
|
||||
AstNode* newp;
|
||||
if (lhswidth==1) {
|
||||
newp = new AstUnaryMin (nodep->fileline(), lhsp->cloneTree(true));
|
||||
newp = new AstNegate (nodep->fileline(), lhsp->cloneTree(true));
|
||||
newp->width(VL_WORDSIZE,VL_WORDSIZE);
|
||||
} else {
|
||||
newp = newAstWordSelClone (lhsp, w);
|
||||
|
||||
@@ -327,6 +327,7 @@ private:
|
||||
#endif
|
||||
}
|
||||
|
||||
// cppcheck-suppress functionConst
|
||||
void checkFilter(bool hang) {
|
||||
#ifdef INFILTER_PIPE
|
||||
if (!m_pidExited && waitpid(m_pid, &m_pidStatus, hang?0:WNOHANG)) {
|
||||
@@ -355,6 +356,7 @@ private:
|
||||
|| errno == EWOULDBLOCK
|
||||
#endif
|
||||
) {
|
||||
// cppcheck-suppress obsoleteFunctionsusleep
|
||||
checkFilter(false); usleep(1000); continue;
|
||||
} else { m_readEof = true; break; }
|
||||
}
|
||||
@@ -390,6 +392,7 @@ private:
|
||||
|| errno == EWOULDBLOCK
|
||||
#endif
|
||||
) {
|
||||
// cppcheck-suppress obsoleteFunctionsusleep
|
||||
checkFilter(false); usleep(1000); continue;
|
||||
}
|
||||
else break;
|
||||
|
||||
+2
-2
@@ -535,7 +535,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
|
||||
AstNode* substp = okVisitor.substTree();
|
||||
if (debug()>=5) logicp->dumpTree(cout,"\telimVar: ");
|
||||
if (debug()>=5) substp->dumpTree(cout,"\t subst: ");
|
||||
m_statSigs++;
|
||||
++m_statSigs;
|
||||
while (V3GraphEdge* edgep = vvertexp->outBeginp()) {
|
||||
GateLogicVertex* consumeVertexp = dynamic_cast<GateLogicVertex*>(edgep->top());
|
||||
AstNode* consumerp = consumeVertexp->nodep();
|
||||
@@ -557,7 +557,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
|
||||
}
|
||||
// Remove the edge
|
||||
edgep->unlinkDelete(); edgep=NULL;
|
||||
m_statRefs++;
|
||||
++m_statRefs;
|
||||
}
|
||||
// Remove input links
|
||||
while (V3GraphEdge* edgep = vvertexp->inBeginp()) {
|
||||
|
||||
+4
-4
@@ -70,7 +70,7 @@ private:
|
||||
// MEMBERS
|
||||
uint32_t m_step; // Processing step, so we can avoid clearUser all the time
|
||||
HashMap m_hashMap; // Dfa Vertex for each set of NFA vertexes
|
||||
int debug() { return 0; }
|
||||
static int debug() { return 0; }
|
||||
|
||||
// METHODS
|
||||
DfaGraph* graphp() { return static_cast<DfaGraph*>(m_graphp); }
|
||||
@@ -94,7 +94,7 @@ private:
|
||||
}
|
||||
|
||||
// Hashing
|
||||
uint32_t hashVertex(V3GraphVertex* vertexp) {
|
||||
static uint32_t hashVertex(V3GraphVertex* vertexp) {
|
||||
union { void* up; struct {uint32_t upper; uint32_t lower;} l;} u;
|
||||
u.l.upper=0; u.l.lower=0; u.up=vertexp;
|
||||
return u.l.upper ^ u.l.lower;
|
||||
@@ -362,7 +362,7 @@ void DfaGraph::nfaToDfa() {
|
||||
class DfaGraphReduce : GraphAlg {
|
||||
private:
|
||||
// METHODS
|
||||
int debug() { return 0; }
|
||||
static int debug() { return 0; }
|
||||
DfaGraph* graphp() { return static_cast<DfaGraph*>(m_graphp); }
|
||||
|
||||
bool isDead(DfaVertex* vertexp) {
|
||||
@@ -507,7 +507,7 @@ private:
|
||||
DfaVertex* m_tempNewerReject;
|
||||
|
||||
// METHODS
|
||||
int debug() { return 9; }
|
||||
static int debug() { return 9; }
|
||||
DfaGraph* graphp() { return static_cast<DfaGraph*>(m_graphp); }
|
||||
|
||||
void add_complement_edges() {
|
||||
|
||||
@@ -326,6 +326,7 @@ public:
|
||||
|
||||
class V3GraphTestImport : public V3GraphTest {
|
||||
|
||||
// cppcheck-suppress functionConst
|
||||
void dotImport();
|
||||
|
||||
public:
|
||||
|
||||
+2
-2
@@ -106,7 +106,7 @@ private:
|
||||
if (m_cellp) nodep->v3error("Cloning should have already been done bottom-up");
|
||||
UINFO(5," Inline CELL "<<nodep<<endl);
|
||||
UINFO(5," To MOD "<<m_modp<<endl);
|
||||
m_statCells++;
|
||||
++m_statCells;
|
||||
|
||||
// Before cloning simplify pin assignments
|
||||
// Better off before, as if module has multiple instantiations
|
||||
@@ -184,7 +184,7 @@ private:
|
||||
// user2p is either a const or a var.
|
||||
AstConst* exprconstp = nodep->user2p()->castNode()->castConst();
|
||||
AstVarRef* exprvarrefp = nodep->user2p()->castNode()->castVarRef();
|
||||
UINFO(1,"connectto: "<<nodep->user2p()->castNode()<<endl);
|
||||
UINFO(8,"connectto: "<<nodep->user2p()->castNode()<<endl);
|
||||
if (!exprconstp && !exprvarrefp) {
|
||||
nodep->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up\n");
|
||||
}
|
||||
|
||||
@@ -293,6 +293,7 @@ private:
|
||||
// LIFE MAP
|
||||
// For each basic block, we'll make a new map of what variables that if/else is changing
|
||||
typedef std::map<AstVarScope*, LifeVarEntry> LifeMap;
|
||||
// cppcheck-suppress memleak // cppcheck bug - it is deleted
|
||||
LifeBlock* m_lifep; // Current active lifetime map for current scope
|
||||
|
||||
// METHODS
|
||||
@@ -455,6 +456,8 @@ public:
|
||||
m_sideEffect = false;
|
||||
m_noopt = false;
|
||||
{
|
||||
// Cpp check bug, it is deleted
|
||||
// cppcheck-suppress leak
|
||||
m_lifep = new LifeBlock (NULL, m_statep);
|
||||
nodep->accept(*this);
|
||||
delete m_lifep; m_lifep=NULL;
|
||||
|
||||
+1
-1
@@ -157,7 +157,7 @@ private:
|
||||
// Mark so LifePostElimVisitor will get it
|
||||
rhsp->varScopep()->user4p(lhsp->varScopep());
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
m_statAssnDel++;
|
||||
++m_statAssnDel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-3
@@ -134,7 +134,7 @@ private:
|
||||
nodep->packagep(packageFor(varp));
|
||||
}
|
||||
else if (AstEnumItem* valuep = foundp->castEnumItem()) {
|
||||
AstNode* newp = new AstEnumItemRef(nodep->fileline(), valuep);
|
||||
AstNode* newp = new AstEnumItemRef(nodep->fileline(), valuep, packageFor(valuep));
|
||||
nodep->replaceWith(newp);
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
return true; // Edited
|
||||
@@ -428,7 +428,7 @@ private:
|
||||
if (dtypep) dtypep->unlinkFrBack();
|
||||
else dtypep = new AstBasicDType(nodep->fileline(), AstBasicDTypeKwd::LOGIC);
|
||||
AstVar* newvarp = new AstVar(nodep->fileline(), AstVarType::OUTPUT, nodep->name(), dtypep);
|
||||
newvarp->isSigned(nodep->isSigned());
|
||||
if (nodep->isSigned()) newvarp->numeric(AstNumeric::SIGNED);
|
||||
newvarp->funcReturn(true);
|
||||
newvarp->trace(false); // Not user visible
|
||||
newvarp->attrIsolateAssign(nodep->attrIsolateAssign());
|
||||
@@ -563,8 +563,13 @@ private:
|
||||
nodep->v3fatalSrc("Cell has unlinked module"); // V3LinkCell should have errored out
|
||||
}
|
||||
else {
|
||||
if (nodep->modp()->castNotFoundModule()) {
|
||||
// Prevent warnings about missing pin connects
|
||||
if (nodep->pinsp()) nodep->pinsp()->unlinkFrBackWithNext()->deleteTree();
|
||||
if (nodep->paramsp()) nodep->paramsp()->unlinkFrBackWithNext()->deleteTree();
|
||||
}
|
||||
// Need to pass the module info to this cell, so we can link up the pin names
|
||||
if (m_idState==ID_RESOLVE) {
|
||||
else if (m_idState==ID_RESOLVE) {
|
||||
m_cellVarsp = nodep->modp()->user4p()->castSymTable();
|
||||
UINFO(4,"(Backto) Link Cell: "<<nodep<<endl);
|
||||
//if (debug()) { nodep->dumpTree(cout,"linkcell:"); }
|
||||
|
||||
+12
-2
@@ -135,7 +135,15 @@ private:
|
||||
AstNodeModule* modp = vvertexp->modp();
|
||||
modp->level(vvertexp->rank()+1);
|
||||
if (vvertexp == m_topVertexp && modp->level() != 2) {
|
||||
v3error("Specified --top-module '"<<v3Global.opt.topModule()<<"' isn't at the top level, it's under another cell.");
|
||||
AstNodeModule* abovep = NULL;
|
||||
if (V3GraphEdge* edgep = vvertexp->inBeginp()) {
|
||||
if (LinkCellsVertex* eFromVertexp = dynamic_cast<LinkCellsVertex*>(edgep->fromp())) {
|
||||
abovep = eFromVertexp->modp();
|
||||
}
|
||||
}
|
||||
v3error("Specified --top-module '"<<v3Global.opt.topModule()
|
||||
<<"' isn't at the top level, it's under another cell '"
|
||||
<<(abovep ? abovep->prettyName() : "UNKNOWN")<<"'");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,8 +184,10 @@ private:
|
||||
AstNodeModule* modp = m_mods.findIdUpward(nodep->modName())->castNodeModule();
|
||||
if (!modp) {
|
||||
// Read-subfile
|
||||
// If file not found, make AstNotFoundModule, rather than error out.
|
||||
// We'll throw the error when we know the module will really be needed.
|
||||
V3Parse parser (v3Global.rootp(), m_filterp);
|
||||
parser.parseFile(nodep->fileline(), nodep->modName(), false);
|
||||
parser.parseFile(nodep->fileline(), nodep->modName(), false, "");
|
||||
V3Error::abortIfErrors();
|
||||
// We've read new modules, grab new pointers to their names
|
||||
readModNames();
|
||||
|
||||
+31
-5
@@ -47,7 +47,7 @@ private:
|
||||
typedef vector<AstBegin*> BeginStack;
|
||||
|
||||
// STATE
|
||||
AstModule* m_modp; // Current module
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstNodeFTask* m_ftaskp; // Current function/task
|
||||
AstWhile* m_loopp; // Current loop
|
||||
bool m_loopInc; // In loop increment
|
||||
@@ -82,6 +82,11 @@ private:
|
||||
nodep->v3fatalSrc("Unknown jump point for break/disable/continue");
|
||||
return NULL;
|
||||
}
|
||||
// Skip over variables as we'll just move them in a momement
|
||||
// Also this would otherwise prevent us from using a label twice
|
||||
// see t_func_return test.
|
||||
while (underp && underp->castVar()) underp = underp->nextp();
|
||||
if (underp) UINFO(5," Underpoint is "<<underp<<endl);
|
||||
|
||||
if (!underp) {
|
||||
nodep->v3fatalSrc("Break/disable/continue not under expected statement");
|
||||
@@ -109,7 +114,7 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
||||
m_modp = nodep;
|
||||
m_repeatNum = 0;
|
||||
nodep->iterateChildren(*this);
|
||||
@@ -135,8 +140,8 @@ private:
|
||||
// Spec says value is integral, if negative is ignored
|
||||
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP, name,
|
||||
AstLogicPacked(), 32);
|
||||
varp->isSigned(true);
|
||||
varp->dtypep()->isSigned(true);
|
||||
varp->numeric(AstNumeric::SIGNED);
|
||||
varp->dtypep()->numeric(AstNumeric::SIGNED);
|
||||
varp->usedLoopIdx(true);
|
||||
m_modp->addStmtp(varp);
|
||||
AstNode* initsp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
|
||||
@@ -144,7 +149,7 @@ private:
|
||||
AstNode* decp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
|
||||
new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
|
||||
new AstConst(nodep->fileline(), 1)));
|
||||
AstNode* zerosp = new AstConst(nodep->fileline(), 0); zerosp->isSigned(true);
|
||||
AstNode* zerosp = new AstConst(nodep->fileline(), 0); zerosp->numeric(AstNumeric::SIGNED);
|
||||
AstNode* condp = new AstGtS(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
|
||||
zerosp);
|
||||
AstNode* bodysp = nodep->bodysp(); if (bodysp) bodysp->unlinkFrBackWithNext();
|
||||
@@ -211,6 +216,27 @@ private:
|
||||
}
|
||||
nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
virtual void visit(AstDisable* nodep, AstNUser*) {
|
||||
UINFO(8," DISABLE "<<nodep<<endl);
|
||||
nodep->iterateChildren(*this);
|
||||
AstBegin* beginp = NULL;
|
||||
for (BeginStack::reverse_iterator it = m_beginStack.rbegin(); it != m_beginStack.rend(); ++it) {
|
||||
UINFO(9," UNDERBLK "<<*it<<endl);
|
||||
if ((*it)->name() == nodep->name()) {
|
||||
beginp = *it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//if (debug()>=9) { UINFO(0,"\n"); beginp->dumpTree(cout," labeli: "); }
|
||||
if (!beginp) { nodep->v3error("disable isn't underneath a begin with name: "<<nodep->name()); }
|
||||
else {
|
||||
// Jump to the end of the named begin
|
||||
AstJumpLabel* labelp = findAddLabel(beginp, false);
|
||||
nodep->addNextHere(new AstJumpGo(nodep->fileline(), labelp));
|
||||
}
|
||||
nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL;
|
||||
//if (debug()>=9) { UINFO(0,"\n"); beginp->dumpTree(cout," labelo: "); }
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
if (m_loopInc && nodep->varp()) nodep->varp()->usedLoopIdx(true);
|
||||
}
|
||||
|
||||
+12
-1
@@ -45,6 +45,7 @@ private:
|
||||
|
||||
// STATE
|
||||
bool m_setRefLvalue; // Set VarRefs to lvalues for pin assignments
|
||||
AstInitial* m_initialp; // In an initial block
|
||||
AstNodeFTask* m_ftaskp; // Function or task we're inside
|
||||
|
||||
// METHODS
|
||||
@@ -64,9 +65,13 @@ private:
|
||||
if (nodep->varp()) {
|
||||
if (nodep->lvalue() && nodep->varp()->isInOnly()) {
|
||||
if (!m_ftaskp) {
|
||||
nodep->v3error("Assigning to input variable: "<<nodep->prettyName());
|
||||
nodep->v3warn(ASSIGNIN,"Assigning to input variable: "<<nodep->prettyName());
|
||||
}
|
||||
}
|
||||
if (nodep->lvalue() && nodep->varp()->isConst()
|
||||
&& !m_initialp) { // Too loose, but need to allow our generated first assignment
|
||||
nodep->v3error("Assigning to const variable: "<<nodep->prettyName());
|
||||
}
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
@@ -222,6 +227,11 @@ private:
|
||||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
virtual void visit(AstInitial* nodep, AstNUser*) {
|
||||
m_initialp = nodep;
|
||||
nodep->iterateChildren(*this);
|
||||
m_initialp = NULL;
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
||||
m_ftaskp = nodep;
|
||||
nodep->iterateChildren(*this);
|
||||
@@ -259,6 +269,7 @@ public:
|
||||
LinkLValueVisitor(AstNode* nodep, bool start) {
|
||||
m_setRefLvalue = start;
|
||||
m_ftaskp = NULL;
|
||||
m_initialp = NULL;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~LinkLValueVisitor() {}
|
||||
|
||||
@@ -326,6 +326,11 @@ private:
|
||||
m_varp->attrSFormat(true);
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_SC_BV) {
|
||||
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
|
||||
m_varp->attrScBv(true);
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
|
||||
|
||||
@@ -95,6 +95,9 @@ private:
|
||||
nodep->dtypeSkipRefp()->castArrayDType())) {
|
||||
nodep->v3error("Unsupported: Inputs and outputs must be simple data types");
|
||||
}
|
||||
if (nodep->dtypeSkipRefp()->castConstDType()) {
|
||||
nodep->isConst(true);
|
||||
}
|
||||
if (m_ftaskp) nodep->funcLocal(true);
|
||||
if (nodep->isSigModPublic()) {
|
||||
nodep->sigModPublic(false); // We're done with this attribute
|
||||
@@ -254,6 +257,7 @@ private:
|
||||
switch (tolower(ch)) {
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
case '.':
|
||||
inPct = true;
|
||||
break;
|
||||
case '%': break; // %% - just output a %
|
||||
|
||||
+7
-4
@@ -60,7 +60,7 @@ private:
|
||||
T m_nextp; // Pointer to next element, NULL=end
|
||||
T m_prevp; // Pointer to previous element, NULL=beginning
|
||||
friend class V3List<T>;
|
||||
static V3ListEnt* baseToListEnt(void* newbasep, uint32_t offset) {
|
||||
static V3ListEnt* baseToListEnt(void* newbasep, size_t offset) {
|
||||
// "this" must be a element inside of *basep
|
||||
// Use that to determine a structure offset, then apply to the new base
|
||||
// to get our new pointer information
|
||||
@@ -80,7 +80,8 @@ public:
|
||||
// METHODS
|
||||
void pushBack (V3List<T>& listr, T newp) {
|
||||
// "this" must be a element inside of *newp
|
||||
uint32_t offset = (vluint8_t*)(this) - (vluint8_t*)(newp);
|
||||
// cppcheck-suppress thisSubtraction
|
||||
size_t offset = (vluint8_t*)(this) - (vluint8_t*)(newp);
|
||||
m_nextp = NULL;
|
||||
if (!listr.m_headp) listr.m_headp = newp;
|
||||
m_prevp = listr.m_tailp;
|
||||
@@ -89,7 +90,8 @@ public:
|
||||
}
|
||||
void pushFront (V3List<T>& listr, T newp) {
|
||||
// "this" must be a element inside of *newp
|
||||
uint32_t offset = (vluint8_t*)(this) - (vluint8_t*)(newp);
|
||||
// cppcheck-suppress thisSubtraction
|
||||
size_t offset = (vluint8_t*)(this) - (vluint8_t*)(newp);
|
||||
m_nextp = listr.m_headp;
|
||||
if (m_nextp) baseToListEnt(m_nextp,offset)->m_prevp = newp;
|
||||
listr.m_headp = newp;
|
||||
@@ -99,7 +101,8 @@ public:
|
||||
// Unlink from side
|
||||
void unlink (V3List<T>& listr, T oldp) {
|
||||
// "this" must be a element inside of *oldp
|
||||
uint32_t offset = (vluint8_t*)(this) - (vluint8_t*)(oldp);
|
||||
// cppcheck-suppress thisSubtraction
|
||||
size_t offset = (vluint8_t*)(this) - (vluint8_t*)(oldp);
|
||||
if (m_nextp) baseToListEnt(m_nextp,offset)->m_prevp = m_prevp;
|
||||
else listr.m_tailp = m_prevp;
|
||||
if (m_prevp) baseToListEnt(m_prevp,offset)->m_nextp = m_nextp;
|
||||
|
||||
+1
-1
@@ -141,7 +141,7 @@ private:
|
||||
&& nodep->user1p()) { // Single cfunc
|
||||
// We don't need to test for tracing; it would be in the tracefunc if it was needed
|
||||
UINFO(4," ModVar->BlkVar "<<nodep<<endl);
|
||||
m_statLocVars++;
|
||||
++m_statLocVars;
|
||||
AstCFunc* newfuncp = nodep->user1p()->castNode()->castCFunc();
|
||||
nodep->unlinkFrBack();
|
||||
newfuncp->addInitsp(nodep);
|
||||
|
||||
+193
-39
@@ -25,33 +25,19 @@
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include "V3Number.h"
|
||||
|
||||
#define MAX_SPRINTF_DOUBLE_SIZE 100 // Maximum characters with a sprintf %e/%f/%g (probably < 30)
|
||||
|
||||
//######################################################################
|
||||
// Read class functions
|
||||
// CREATION
|
||||
|
||||
void V3Number::width(int width, bool sized) {
|
||||
// Set width. Only set m_width here, as we need to tweak vector size
|
||||
if (width) { m_sized = sized; m_width=width; }
|
||||
else { m_sized = false; m_width=1; }
|
||||
if (m_value.size() < (unsigned)(words()+1)) {
|
||||
m_value.resize(words()+1);
|
||||
m_valueX.resize(words()+1);
|
||||
}
|
||||
}
|
||||
|
||||
void V3Number::init (FileLine* fileline, int swidth) {
|
||||
m_fileline = fileline;
|
||||
m_signed = false;
|
||||
m_autoExtend = false;
|
||||
m_fromString = false;
|
||||
width(swidth);
|
||||
for (int i=0; i<words(); i++) m_value[i]=m_valueX[i] = 0;
|
||||
}
|
||||
|
||||
V3Number::V3Number(VerilogString, 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
|
||||
init(fileline, str.length()*8);
|
||||
m_fromString = true;
|
||||
for (unsigned pos=0; pos<str.length(); ++pos) {
|
||||
@@ -298,6 +284,24 @@ V3Number& V3Number::setLong(uint32_t value) {
|
||||
m_value[0] = value;
|
||||
return *this;
|
||||
}
|
||||
V3Number& V3Number::setLongS(vlsint32_t value) {
|
||||
for (int i=0; i<words(); i++) m_value[i]=m_valueX[i] = 0;
|
||||
union { uint32_t u; vlsint32_t s; } u;
|
||||
u.s = value;
|
||||
m_value[0] = u.u;
|
||||
return *this;
|
||||
}
|
||||
V3Number& V3Number::setDouble(double value) {
|
||||
if (VL_UNLIKELY(width()!=64)) {
|
||||
m_fileline->v3fatalSrc("Real operation on wrong sized number");
|
||||
}
|
||||
m_double = true;
|
||||
union { double d; uint32_t u[2]; } u;
|
||||
u.d = value;
|
||||
for (int i=2; i<words(); i++) m_value[i]=m_valueX[i] = 0;
|
||||
m_value[0] = u.u[0]; m_value[1] = u.u[1];
|
||||
return *this;
|
||||
}
|
||||
V3Number& V3Number::setSingleBits(char value) {
|
||||
for (int i=1/*upper*/; i<words(); i++) m_value[i]=m_valueX[i] = 0;
|
||||
m_value[0] = (value=='1'||value=='x'||value==1||value==3);
|
||||
@@ -306,12 +310,12 @@ V3Number& V3Number::setSingleBits(char value) {
|
||||
}
|
||||
|
||||
V3Number& V3Number::setAllBits0() {
|
||||
for (int i=0; i<words(); i++) { m_value[i] = m_valueX[i]=0; }
|
||||
return *this;
|
||||
for (int i=0; i<words(); i++) { m_value[i] = m_valueX[i]=0; }
|
||||
return *this;
|
||||
}
|
||||
V3Number& V3Number::setAllBits1() {
|
||||
for (int i=0; i<words(); i++) { m_value[i]= ~0; m_valueX[i] = 0; }
|
||||
return *this;
|
||||
for (int i=0; i<words(); i++) { m_value[i]= ~0; m_valueX[i] = 0; }
|
||||
return *this;
|
||||
}
|
||||
V3Number& V3Number::setAllBitsX() {
|
||||
for (int i=0; i<words(); i++) { m_value[i]=m_valueX[i] = ~0; }
|
||||
@@ -333,6 +337,11 @@ V3Number& V3Number::setMask(int nbits) {
|
||||
string V3Number::ascii(bool prefixed, bool cleanVerilog) const {
|
||||
ostringstream out;
|
||||
|
||||
if (isDouble()) {
|
||||
out.precision(17);
|
||||
out<<toDouble();
|
||||
return out.str();
|
||||
}
|
||||
if (prefixed) {
|
||||
if (sized()) {
|
||||
out<<width()<<"'";
|
||||
@@ -375,6 +384,9 @@ bool V3Number::displayedFmtLegal(char format) {
|
||||
case 'b': return true;
|
||||
case 'c': return true;
|
||||
case 'd': return true; // Unsigned decimal
|
||||
case 'e': return true;
|
||||
case 'f': return true;
|
||||
case 'g': return true;
|
||||
case 'h': return true;
|
||||
case 'o': return true;
|
||||
case 's': return true;
|
||||
@@ -388,9 +400,9 @@ bool V3Number::displayedFmtLegal(char format) {
|
||||
string V3Number::displayed(const string& vformat) const {
|
||||
string::const_iterator pos = vformat.begin();
|
||||
UASSERT(pos != vformat.end() && pos[0]=='%', "display with non format argument "<<*this);
|
||||
pos++;
|
||||
++pos;
|
||||
string fmtsize;
|
||||
for (; pos != vformat.end() && isdigit(pos[0]); pos++) {
|
||||
for (; pos != vformat.end() && (isdigit(pos[0]) || pos[0]=='.'); ++pos) {
|
||||
fmtsize += pos[0];
|
||||
}
|
||||
string str;
|
||||
@@ -472,9 +484,20 @@ string V3Number::displayed(const string& vformat) const {
|
||||
str = cvtToStr(toUQuad());
|
||||
}
|
||||
int intfmtsize = atoi(fmtsize.c_str());
|
||||
while ((int)(str.length()) < intfmtsize) str = " "+str;
|
||||
bool zeropad = fmtsize.length()>0 && fmtsize[0]=='0';
|
||||
while ((int)(str.length()) < intfmtsize) {
|
||||
if (zeropad) str = "0"+str;
|
||||
else str = " "+str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
case 'e':
|
||||
case 'f':
|
||||
case 'g': {
|
||||
char tmp[MAX_SPRINTF_DOUBLE_SIZE];
|
||||
sprintf(tmp, vformat.c_str(), toDouble());
|
||||
return tmp;
|
||||
}
|
||||
default:
|
||||
m_fileline->v3fatalSrc("Unknown $display format code for number: %"<<pos[0]);
|
||||
return "ERR";
|
||||
@@ -490,6 +513,18 @@ uint32_t V3Number::toUInt() const {
|
||||
return m_value[0];
|
||||
}
|
||||
|
||||
double V3Number::toDouble() const {
|
||||
if (VL_UNLIKELY(!isDouble())) {
|
||||
m_fileline->v3fatalSrc("Real conversion on non real number");
|
||||
}
|
||||
if (VL_UNLIKELY(width()!=64)) {
|
||||
m_fileline->v3fatalSrc("Real operation on wrong sized number");
|
||||
}
|
||||
union { double d; uint32_t u[2]; } u;
|
||||
u.u[0] = m_value[0]; u.u[1] = m_value[1];
|
||||
return u.d;
|
||||
}
|
||||
|
||||
vlsint32_t V3Number::toSInt() const {
|
||||
if (isSigned()) {
|
||||
uint32_t v = toUInt();
|
||||
@@ -555,6 +590,12 @@ bool V3Number::isNeqZero() const {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool V3Number::isBitsZero(int msb, int lsb) const {
|
||||
for (int i=lsb; i<=msb; i++) {
|
||||
if (VL_UNLIKELY(!bitIs0(i))) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool V3Number::isEqOne() const {
|
||||
if (m_value[0]!=1 || m_valueX[0]) return false;
|
||||
for (int i=1; i<words(); i++) {
|
||||
@@ -1005,6 +1046,30 @@ V3Number& V3Number::opLteS (const V3Number& lhs, const V3Number& rhs) {
|
||||
return opGteS(rhs,lhs);
|
||||
}
|
||||
|
||||
V3Number& V3Number::opRotR (const V3Number& lhs, const V3Number& rhs) {
|
||||
// L(lhs) bit return
|
||||
if (rhs.isFourState()) return setAllBitsX();
|
||||
setZero();
|
||||
uint32_t rhsval = rhs.toUInt();
|
||||
for (int bit=0; bit<this->width(); bit++) {
|
||||
setBit(bit,lhs.bitIs((bit + rhsval) % this->width()));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
V3Number& V3Number::opRotL (const V3Number& lhs, const V3Number& rhs) {
|
||||
// L(lhs) bit return
|
||||
if (rhs.isFourState()) return setAllBitsX();
|
||||
setZero();
|
||||
uint32_t rhsval = rhs.toUInt();
|
||||
for (int bit=0; bit<this->width(); bit++) {
|
||||
if (bit >= (int)rhsval) {
|
||||
setBit(bit,lhs.bitIs((bit - rhsval) % this->width()));
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
V3Number& V3Number::opShiftR (const V3Number& lhs, const V3Number& rhs) {
|
||||
// L(lhs) bit return
|
||||
if (rhs.isFourState()) return setAllBitsX();
|
||||
@@ -1019,7 +1084,7 @@ V3Number& V3Number::opShiftR (const V3Number& lhs, const V3Number& rhs) {
|
||||
V3Number& V3Number::opShiftRS (const V3Number& lhs, const V3Number& rhs) {
|
||||
// L(lhs) bit return
|
||||
// The spec says a unsigned >>> still acts as a normal >>.
|
||||
// We presume it is signed; as that's V3Signed's job to convert to opShiftR
|
||||
// We presume it is signed; as that's V3Width's job to convert to opShiftR
|
||||
if (rhs.isFourState()) return setAllBitsX();
|
||||
setZero();
|
||||
uint32_t rhsval = rhs.toUInt();
|
||||
@@ -1032,8 +1097,8 @@ V3Number& V3Number::opShiftRS (const V3Number& lhs, const V3Number& rhs) {
|
||||
V3Number& V3Number::opShiftL (const V3Number& lhs, const V3Number& rhs) {
|
||||
// L(lhs) bit return
|
||||
if (rhs.isFourState()) return setAllBitsX();
|
||||
uint32_t rhsval = rhs.toUInt();
|
||||
setZero();
|
||||
uint32_t rhsval = rhs.toUInt();
|
||||
for (int bit=0; bit<this->width(); bit++) {
|
||||
if (bit >= (int)rhsval) {
|
||||
setBit(bit,lhs.bitIs(bit - rhsval));
|
||||
@@ -1045,7 +1110,16 @@ V3Number& V3Number::opShiftL (const V3Number& lhs, const V3Number& rhs) {
|
||||
//======================================================================
|
||||
// Ops - Arithmetic
|
||||
|
||||
V3Number& V3Number::opUnaryMin (const V3Number& lhs) {
|
||||
V3Number& V3Number::opAbsS (const V3Number& lhs) {
|
||||
// op i, L(lhs) bit return
|
||||
if (lhs.isFourState()) return setAllBitsX();
|
||||
if (lhs.isNegative()) {
|
||||
return opNegate(lhs);
|
||||
} else {
|
||||
return opAssign(lhs);
|
||||
}
|
||||
}
|
||||
V3Number& V3Number::opNegate (const V3Number& lhs) {
|
||||
// op i, L(lhs) bit return
|
||||
if (lhs.isFourState()) return setAllBitsX();
|
||||
V3Number notlhs (lhs.m_fileline, width());
|
||||
@@ -1073,7 +1147,7 @@ V3Number& V3Number::opSub (const V3Number& lhs, const V3Number& rhs) {
|
||||
// i op j, max(L(lhs),L(rhs)) bit return, if any 4-state, 4-state return
|
||||
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
|
||||
V3Number negrhs (rhs.m_fileline, rhs.width());
|
||||
negrhs.opUnaryMin(rhs);
|
||||
negrhs.opNegate(rhs);
|
||||
return opAdd(lhs, negrhs);
|
||||
}
|
||||
V3Number& V3Number::opMul (const V3Number& lhs, const V3Number& rhs) {
|
||||
@@ -1101,12 +1175,12 @@ V3Number& V3Number::opMul (const V3Number& lhs, const V3Number& rhs) {
|
||||
V3Number& V3Number::opMulS (const V3Number& lhs, const V3Number& rhs) {
|
||||
// Signed multiply
|
||||
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
|
||||
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opUnaryMin(lhs);
|
||||
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opUnaryMin(rhs);
|
||||
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opNegate(lhs);
|
||||
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opNegate(rhs);
|
||||
V3Number qNoSign = opMul(lhsNoSign,rhsNoSign);
|
||||
if ((lhs.isNegative() && !rhs.isNegative())
|
||||
|| (!lhs.isNegative() && rhs.isNegative())) {
|
||||
opUnaryMin(qNoSign);
|
||||
opNegate(qNoSign);
|
||||
} else {
|
||||
opAssign(qNoSign);
|
||||
}
|
||||
@@ -1130,13 +1204,13 @@ V3Number& V3Number::opDivS (const V3Number& lhs, const V3Number& rhs) {
|
||||
//UINFO(9, ">>divs-start "<<lhs<<" "<<rhs<<endl);
|
||||
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
|
||||
if (rhs.isEqZero()) return setAllBitsX();
|
||||
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opUnaryMin(lhs);
|
||||
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opUnaryMin(rhs);
|
||||
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opNegate(lhs);
|
||||
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opNegate(rhs);
|
||||
V3Number qNoSign = opDiv(lhsNoSign,rhsNoSign);
|
||||
//UINFO(9, " >divs-mid "<<lhs<<" "<<rhs<<" "<<qNoSign<<endl);
|
||||
if ((lhs.isNegative() && !rhs.isNegative())
|
||||
|| (!lhs.isNegative() && rhs.isNegative())) {
|
||||
opUnaryMin(qNoSign);
|
||||
opNegate(qNoSign);
|
||||
} else {
|
||||
opAssign(qNoSign);
|
||||
}
|
||||
@@ -1159,11 +1233,11 @@ V3Number& V3Number::opModDivS (const V3Number& lhs, const V3Number& rhs) {
|
||||
// Signed moddiv
|
||||
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
|
||||
if (rhs.isEqZero()) return setAllBitsX();
|
||||
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opUnaryMin(lhs);
|
||||
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opUnaryMin(rhs);
|
||||
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opNegate(lhs);
|
||||
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opNegate(rhs);
|
||||
V3Number qNoSign = opModDiv(lhsNoSign,rhsNoSign);
|
||||
if (lhs.isNegative()) { // Just lhs' sign (*DIFFERENT FROM PERL, which uses rhs sign*)
|
||||
opUnaryMin(qNoSign);
|
||||
opNegate(qNoSign);
|
||||
} else {
|
||||
opAssign(qNoSign);
|
||||
}
|
||||
@@ -1318,6 +1392,15 @@ V3Number& V3Number::opPowS (const V3Number& lhs, const V3Number& rhs) {
|
||||
return setAllBitsX();
|
||||
}
|
||||
|
||||
V3Number& V3Number::opBufIf1 (const V3Number& ens, const V3Number& if1s) {
|
||||
setZero();
|
||||
for(int bit=0; bit<this->width(); bit++) {
|
||||
if (ens.bitIs1(bit)) { setBit(bit, if1s.bitIs(bit)); }
|
||||
else setBit(bit,'z');
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
V3Number& V3Number::opAssign (const V3Number& lhs) {
|
||||
// Note may be a width change during the assign
|
||||
setZero();
|
||||
@@ -1386,3 +1469,74 @@ V3Number& V3Number::opCond (const V3Number& lhs, const V3Number& if1s, const V3
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Ops - Floating point
|
||||
|
||||
V3Number& V3Number::opIToRD (const V3Number& lhs) {
|
||||
return setDouble(lhs.toSInt());
|
||||
}
|
||||
V3Number& V3Number::opRToIS (const V3Number& lhs) {
|
||||
double v = VL_TRUNC(lhs.toDouble());
|
||||
vlsint32_t i = (vlsint32_t)v; // C converts from double to vlsint32
|
||||
return setLongS(i);
|
||||
}
|
||||
V3Number& V3Number::opRToIRoundS (const V3Number& lhs) {
|
||||
double v = VL_ROUND(lhs.toDouble());
|
||||
vlsint32_t i = (vlsint32_t)v; // C converts from double to vlsint32
|
||||
return setLongS(i);
|
||||
}
|
||||
V3Number& V3Number::opRealToBits (const V3Number& lhs) {
|
||||
// Conveniently our internal format is identical so we can copy bits...
|
||||
if (lhs.width()!=64 || this->width()!=64) {
|
||||
m_fileline->v3fatalSrc("Real operation on wrong sized number");
|
||||
}
|
||||
return opAssign(lhs);
|
||||
}
|
||||
V3Number& V3Number::opBitsToRealD (const V3Number& lhs) {
|
||||
// Conveniently our internal format is identical so we can copy bits...
|
||||
if (lhs.width()!=64 || this->width()!=64) {
|
||||
m_fileline->v3fatalSrc("Real operation on wrong sized number");
|
||||
}
|
||||
return opAssign(lhs);
|
||||
}
|
||||
V3Number& V3Number::opNegateD (const V3Number& lhs) {
|
||||
return setDouble(- lhs.toDouble());
|
||||
}
|
||||
V3Number& V3Number::opAddD (const V3Number& lhs, const V3Number& rhs) {
|
||||
return setDouble(lhs.toDouble() + rhs.toDouble());
|
||||
}
|
||||
V3Number& V3Number::opSubD (const V3Number& lhs, const V3Number& rhs) {
|
||||
return setDouble(lhs.toDouble() - rhs.toDouble());
|
||||
}
|
||||
V3Number& V3Number::opMulD (const V3Number& lhs, const V3Number& rhs) {
|
||||
return setDouble(lhs.toDouble() * rhs.toDouble());
|
||||
}
|
||||
V3Number& V3Number::opDivD (const V3Number& lhs, const V3Number& rhs) {
|
||||
// On exceptions, we just generate 'inf' through floating point
|
||||
// IEEE says it's implementation defined what happens
|
||||
return setDouble(lhs.toDouble() / rhs.toDouble());
|
||||
}
|
||||
V3Number& V3Number::opPowD (const V3Number& lhs, const V3Number& rhs) {
|
||||
// On exceptions, we just generate 'inf' through floating point
|
||||
// IEEE says it's implementation defined what happens
|
||||
return setDouble(pow(lhs.toDouble(), rhs.toDouble()));
|
||||
}
|
||||
V3Number& V3Number::opEqD (const V3Number& lhs, const V3Number& rhs) {
|
||||
return setSingleBits(lhs.toDouble() == rhs.toDouble());
|
||||
}
|
||||
V3Number& V3Number::opNeqD (const V3Number& lhs, const V3Number& rhs) {
|
||||
return setSingleBits(lhs.toDouble() != rhs.toDouble());
|
||||
}
|
||||
V3Number& V3Number::opGtD (const V3Number& lhs, const V3Number& rhs) {
|
||||
return setSingleBits(lhs.toDouble() > rhs.toDouble());
|
||||
}
|
||||
V3Number& V3Number::opGteD (const V3Number& lhs, const V3Number& rhs) {
|
||||
return setSingleBits(lhs.toDouble() >= rhs.toDouble());
|
||||
}
|
||||
V3Number& V3Number::opLtD (const V3Number& lhs, const V3Number& rhs) {
|
||||
return setSingleBits(lhs.toDouble() < rhs.toDouble());
|
||||
}
|
||||
V3Number& V3Number::opLteD (const V3Number& lhs, const V3Number& rhs) {
|
||||
return setSingleBits(lhs.toDouble() <= rhs.toDouble());
|
||||
}
|
||||
|
||||
+51
-3
@@ -35,13 +35,13 @@ class V3Number {
|
||||
int m_width; // Width as specified/calculated.
|
||||
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_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
|
||||
// METHODS
|
||||
void init(FileLine* fileline, int width);
|
||||
V3Number& setSingleBits(char value);
|
||||
void opCleanThis();
|
||||
public:
|
||||
@@ -50,6 +50,8 @@ public:
|
||||
V3Number& setZero();
|
||||
V3Number& setQuad(vluint64_t value);
|
||||
V3Number& setLong(uint32_t value);
|
||||
V3Number& setLongS(vlsint32_t value);
|
||||
V3Number& setDouble(double value);
|
||||
void setBit (int bit, char value) { // Note must be pre-zeroed!
|
||||
if (bit>=m_width) return;
|
||||
if (value=='0'||value==0) m_value [bit/32] &= ~(1UL<<(bit&31));
|
||||
@@ -115,6 +117,27 @@ public:
|
||||
V3Number(FileLine* fileline, const char* source); // Create from a verilog 32'hxxxx number.
|
||||
V3Number(VerilogString, FileLine* fileline, const string& vvalue);
|
||||
|
||||
private:
|
||||
void init(FileLine* fileline, int swidth) {
|
||||
m_fileline = fileline;
|
||||
m_signed = false;
|
||||
m_double = false;
|
||||
m_autoExtend = false;
|
||||
m_fromString = false;
|
||||
width(swidth);
|
||||
for (int i=0; i<words(); i++) m_value[i]=m_valueX[i] = 0;
|
||||
}
|
||||
public:
|
||||
void width(int width, bool sized=true) {
|
||||
// Set width. Only set m_width here, as we need to tweak vector size
|
||||
if (width) { m_sized = sized; m_width=width; }
|
||||
else { m_sized = false; m_width=1; }
|
||||
if (VL_UNLIKELY(m_value.size() < (unsigned)(words()+1))) {
|
||||
m_value.resize(words()+1);
|
||||
m_valueX.resize(words()+1);
|
||||
}
|
||||
}
|
||||
|
||||
// SETTERS
|
||||
V3Number& setAllBitsX();
|
||||
V3Number& setAllBitsZ();
|
||||
@@ -132,17 +155,18 @@ public:
|
||||
bool autoExtend() const { return m_autoExtend; }
|
||||
bool isFromString() const { return m_fromString; }
|
||||
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())
|
||||
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;}
|
||||
bool isAllZ() const { for(int i=0;i<width();i++) { if(!bitIsZ(i)){return false;} } return true; }
|
||||
bool isEqZero() const;
|
||||
bool isNeqZero() const;
|
||||
bool isBitsZero(int msb, int lsb) const;
|
||||
bool isEqOne() const;
|
||||
bool isEqAllOnes(int optwidth=0) const;
|
||||
bool isCaseEq(const V3Number& rhsp) const; // operator==
|
||||
bool isLt(const V3Number& rhsp) const; // operator<
|
||||
void width(int width, bool sized=true);
|
||||
void isSigned(bool ssigned) { m_signed=ssigned; }
|
||||
bool isUnknown() const;
|
||||
uint32_t toUInt() const;
|
||||
@@ -150,6 +174,7 @@ public:
|
||||
vluint64_t toUQuad() const;
|
||||
vlsint64_t toSQuad() const;
|
||||
string toString() const;
|
||||
double toDouble() const;
|
||||
uint32_t toHash() const;
|
||||
uint32_t dataWord(int word) const;
|
||||
uint32_t countOnes() const;
|
||||
@@ -195,12 +220,14 @@ public:
|
||||
V3Number& opCaseNeq (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opWildEq (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opWildNeq (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opBufIf1 (const V3Number& lhs, const V3Number& rhs);
|
||||
// "standard" math
|
||||
V3Number& opNot (const V3Number& lhs);
|
||||
V3Number& opLogNot (const V3Number& lhs);
|
||||
V3Number& opLogAnd (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLogOr (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opUnaryMin(const V3Number& lhs);
|
||||
V3Number& opAbsS (const V3Number& lhs);
|
||||
V3Number& opNegate (const V3Number& lhs);
|
||||
V3Number& opAdd (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opSub (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opMul (const V3Number& lhs, const V3Number& rhs);
|
||||
@@ -216,6 +243,8 @@ public:
|
||||
V3Number& opXor (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opXnor (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opOr (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opRotR (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opRotL (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opShiftR (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opShiftRS (const V3Number& lhs, const V3Number& rhs); // Arithmetic w/carry
|
||||
V3Number& opShiftL (const V3Number& lhs, const V3Number& rhs);
|
||||
@@ -231,6 +260,25 @@ public:
|
||||
V3Number& opLte (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLteS (const V3Number& lhs, const V3Number& rhs); // Signed
|
||||
|
||||
// "D" - double (aka real) math
|
||||
V3Number& opIToRD (const V3Number& lhs);
|
||||
V3Number& opRToIS (const V3Number& lhs);
|
||||
V3Number& opRToIRoundS (const V3Number& lhs);
|
||||
V3Number& opRealToBits (const V3Number& lhs);
|
||||
V3Number& opBitsToRealD(const V3Number& lhs);
|
||||
V3Number& opNegateD (const V3Number& lhs);
|
||||
V3Number& opAddD (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opSubD (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opMulD (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opDivD (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opPowD (const V3Number& lhs, const V3Number& rhs);
|
||||
// Comparisons
|
||||
V3Number& opEqD (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opNeqD (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opGtD (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opGteD (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLtD (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLteD (const V3Number& lhs, const V3Number& rhs);
|
||||
};
|
||||
inline ostream& operator<<(ostream& os, V3Number rhs) { return os<<rhs.ascii(); }
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ void test(string lhss, string op, string rhss, string exps) {
|
||||
else if (op=="repl") gotnum.opRepl (lhnum,rhnum);
|
||||
else if (op=="~") gotnum.opNot (lhnum);
|
||||
else if (op=="!") gotnum.opLogNot (lhnum);
|
||||
else if (op=="unaryMin") gotnum.opUnaryMin (lhnum);
|
||||
else if (op=="negate") gotnum.opNegate (lhnum);
|
||||
else if (op=="+") gotnum.opAdd (lhnum,rhnum);
|
||||
else if (op=="-") gotnum.opSub (lhnum,rhnum);
|
||||
else if (op=="*") gotnum.opMul (lhnum,rhnum);
|
||||
@@ -96,8 +96,8 @@ int main() {
|
||||
test("32'b0x","|","32'b10","32'b1x");
|
||||
test("32'b10","&","32'b11","32'b10");
|
||||
test("32'b10","+","32'b10","32'b100");
|
||||
test("3'b000","unaryMin","","3'b000");
|
||||
test("3'b001","unaryMin","","3'b111");
|
||||
test("3'b000","negate","","3'b000");
|
||||
test("3'b001","negate","","3'b111");
|
||||
test("32'b11","-","32'b001","32'b10");
|
||||
test("3'b000","-","3'b111","3'b001");
|
||||
test("3'b000","-","3'b000","3'b000");
|
||||
|
||||
+128
-50
@@ -51,17 +51,29 @@ struct V3OptionsImp {
|
||||
|
||||
// STATE
|
||||
list<string> m_allArgs; // List of every argument encountered
|
||||
list<string> m_incDirs; // Include directories (ordered)
|
||||
set<string> m_incDirSet; // Include directories (for removing duplicates)
|
||||
list<string> m_incDirUsers; // Include directories (ordered)
|
||||
set<string> m_incDirUserSet; // Include directories (for removing duplicates)
|
||||
list<string> m_incDirFallbacks; // Include directories (ordered)
|
||||
set<string> m_incDirFallbackSet; // Include directories (for removing duplicates)
|
||||
list<string> m_libExts; // Library extensions (ordered)
|
||||
set<string> m_libExtSet; // Library extensions (for removing duplicates)
|
||||
DirMap m_dirMap; // Directory listing
|
||||
|
||||
// ACCESSOR METHODS
|
||||
void addIncDir(const string& incdir) {
|
||||
if (m_incDirSet.find(incdir) == m_incDirSet.end()) {
|
||||
m_incDirSet.insert(incdir);
|
||||
m_incDirs.push_back(incdir);
|
||||
void addIncDirUser(const string& incdir) {
|
||||
if (m_incDirUserSet.find(incdir) == m_incDirUserSet.end()) {
|
||||
m_incDirUserSet.insert(incdir);
|
||||
m_incDirUsers.push_back(incdir);
|
||||
m_incDirFallbacks.remove(incdir); // User has priority over Fallback
|
||||
m_incDirFallbackSet.erase(incdir); // User has priority over Fallback
|
||||
}
|
||||
}
|
||||
void addIncDirFallback(const string& incdir) {
|
||||
if (m_incDirUserSet.find(incdir) == m_incDirUserSet.end()) { // User has priority over Fallback
|
||||
if (m_incDirFallbackSet.find(incdir) == m_incDirFallbackSet.end()) {
|
||||
m_incDirFallbackSet.insert(incdir);
|
||||
m_incDirFallbacks.push_back(incdir);
|
||||
}
|
||||
}
|
||||
}
|
||||
void addLibExt(const string& libext) {
|
||||
@@ -73,8 +85,11 @@ struct V3OptionsImp {
|
||||
V3OptionsImp() {}
|
||||
};
|
||||
|
||||
void V3Options::addIncDir(const string& incdir) {
|
||||
m_impp->addIncDir(incdir);
|
||||
void V3Options::addIncDirUser(const string& incdir) {
|
||||
m_impp->addIncDirUser(incdir);
|
||||
}
|
||||
void V3Options::addIncDirFallback(const string& incdir) {
|
||||
m_impp->addIncDirFallback(incdir);
|
||||
}
|
||||
void V3Options::addLibExt(const string& libext) {
|
||||
m_impp->addLibExt(libext);
|
||||
@@ -194,18 +209,33 @@ string V3Options::filenameNonExt (const string& filename) {
|
||||
|
||||
string V3Options::filenameSubstitute (const string& filename) {
|
||||
string out;
|
||||
enum { NONE, PAREN, CURLY } brackets = NONE;
|
||||
for (string::size_type pos = 0; pos < filename.length(); ++pos) {
|
||||
if (filename[pos] == '$') {
|
||||
if ((filename[pos] == '$') && (pos+1 < filename.length())) {
|
||||
switch (filename[pos+1]) {
|
||||
case '{': brackets = CURLY; break;
|
||||
case '(': brackets = PAREN; break;
|
||||
default: brackets = NONE; break;
|
||||
}
|
||||
if (brackets != NONE) pos = pos+1;
|
||||
string::size_type endpos = pos+1;
|
||||
while ((endpos+1) < filename.length()
|
||||
&& (isalnum(filename[endpos+1]) || filename[endpos+1]=='_'))
|
||||
while (((endpos+1) < filename.length()) &&
|
||||
(((brackets==NONE) && (isalnum(filename[endpos+1]) || filename[endpos+1]=='_')) ||
|
||||
((brackets==CURLY) && (filename[endpos+1]!='}')) ||
|
||||
((brackets==PAREN) && (filename[endpos+1]!=')'))))
|
||||
++endpos;
|
||||
// Catch bracket errors
|
||||
if (((brackets==CURLY) && (filename[endpos+1]!='}')) ||
|
||||
((brackets==PAREN) && (filename[endpos+1]!=')'))) {
|
||||
v3fatal("Unmatched brackets in variable substitution in file: "+filename);
|
||||
}
|
||||
string envvar = filename.substr(pos+1,endpos-pos);
|
||||
const char* envvalue = NULL;
|
||||
if (envvar != "") envvalue = getenv(envvar.c_str());
|
||||
if (envvalue) {
|
||||
out += envvalue;
|
||||
pos = endpos;
|
||||
if (brackets==NONE) pos = endpos;
|
||||
else pos = endpos+1;
|
||||
} else {
|
||||
out += filename[pos]; // *pos == '$'
|
||||
}
|
||||
@@ -214,6 +244,7 @@ string V3Options::filenameSubstitute (const string& filename) {
|
||||
}
|
||||
}
|
||||
return out;
|
||||
|
||||
}
|
||||
|
||||
bool V3Options::filenameIsRel(const string& filename) {
|
||||
@@ -272,42 +303,68 @@ string V3Options::fileExists (const string& filename) {
|
||||
return filenameOut;
|
||||
}
|
||||
|
||||
string V3Options::filePath (FileLine* fl, const string& modname, const string& errmsg) {
|
||||
// Find a filename to read the specified module name,
|
||||
// using the incdir and libext's.
|
||||
// Return "" if not found.
|
||||
for (list<string>::iterator dirIter=m_impp->m_incDirs.begin(); dirIter!=m_impp->m_incDirs.end(); ++dirIter) {
|
||||
for (list<string>::iterator extIter=m_impp->m_libExts.begin(); extIter!=m_impp->m_libExts.end(); ++extIter) {
|
||||
string fn = filenameFromDirBase(*dirIter,modname+*extIter);
|
||||
string exists = fileExists(fn);
|
||||
if (exists!="") {
|
||||
// Strip ./, it just looks ugly
|
||||
if (exists.substr(0,2)=="./") exists.erase(0,2);
|
||||
return exists;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Warn and return not found
|
||||
fl->v3error(errmsg+modname);
|
||||
static bool shown_notfound_msg = false;
|
||||
if (!shown_notfound_msg) {
|
||||
shown_notfound_msg = true;
|
||||
if (m_impp->m_incDirs.empty()) {
|
||||
fl->v3error("This may be because there's no search path specified with -I<dir>."<<endl);
|
||||
} else {
|
||||
fl->v3error("Looked in:"<<endl);
|
||||
for (list<string>::iterator dirIter=m_impp->m_incDirs.begin(); dirIter!=m_impp->m_incDirs.end(); ++dirIter) {
|
||||
for (list<string>::iterator extIter=m_impp->m_libExts.begin(); extIter!=m_impp->m_libExts.end(); ++extIter) {
|
||||
string fn = filenameFromDirBase(*dirIter,modname+*extIter);
|
||||
fl->v3error(" "<<fn<<endl);
|
||||
}
|
||||
}
|
||||
string V3Options::filePathCheckOneDir(const string& modname, const string& dirname) {
|
||||
for (list<string>::iterator extIter=m_impp->m_libExts.begin(); extIter!=m_impp->m_libExts.end(); ++extIter) {
|
||||
string fn = filenameFromDirBase(dirname, modname+*extIter);
|
||||
string exists = fileExists(fn);
|
||||
if (exists!="") {
|
||||
// Strip ./, it just looks ugly
|
||||
if (exists.substr(0,2)=="./") exists.erase(0,2);
|
||||
return exists;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
string V3Options::filePath (FileLine* fl, const string& modname,
|
||||
const string& errmsg) { // Error prefix or "" to suppress error
|
||||
// Find a filename to read the specified module name,
|
||||
// using the incdir and libext's.
|
||||
// Return "" if not found.
|
||||
for (list<string>::iterator dirIter=m_impp->m_incDirUsers.begin();
|
||||
dirIter!=m_impp->m_incDirUsers.end(); ++dirIter) {
|
||||
string exists = filePathCheckOneDir(modname, *dirIter);
|
||||
if (exists!="") return exists;
|
||||
}
|
||||
for (list<string>::iterator dirIter=m_impp->m_incDirFallbacks.begin();
|
||||
dirIter!=m_impp->m_incDirFallbacks.end(); ++dirIter) {
|
||||
string exists = filePathCheckOneDir(modname, *dirIter);
|
||||
if (exists!="") return exists;
|
||||
}
|
||||
|
||||
// Warn and return not found
|
||||
if (errmsg != "") {
|
||||
fl->v3error(errmsg+modname);
|
||||
filePathLookedMsg(fl, modname);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void V3Options::filePathLookedMsg(FileLine* fl, const string& modname) {
|
||||
static bool shown_notfound_msg = false;
|
||||
if (!shown_notfound_msg) {
|
||||
shown_notfound_msg = true;
|
||||
if (m_impp->m_incDirUsers.empty()) {
|
||||
fl->v3error("This may be because there's no search path specified with -I<dir>."<<endl);
|
||||
}
|
||||
fl->v3error("Looked in:"<<endl);
|
||||
for (list<string>::iterator dirIter=m_impp->m_incDirUsers.begin();
|
||||
dirIter!=m_impp->m_incDirUsers.end(); ++dirIter) {
|
||||
for (list<string>::iterator extIter=m_impp->m_libExts.begin(); extIter!=m_impp->m_libExts.end(); ++extIter) {
|
||||
string fn = filenameFromDirBase(*dirIter,modname+*extIter);
|
||||
fl->v3error(" "<<fn<<endl);
|
||||
}
|
||||
}
|
||||
for (list<string>::iterator dirIter=m_impp->m_incDirFallbacks.begin();
|
||||
dirIter!=m_impp->m_incDirFallbacks.end(); ++dirIter) {
|
||||
for (list<string>::iterator extIter=m_impp->m_libExts.begin(); extIter!=m_impp->m_libExts.end(); ++extIter) {
|
||||
string fn = filenameFromDirBase(*dirIter,modname+*extIter);
|
||||
fl->v3error(" "<<fn<<endl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void V3Options::unlinkRegexp(const string& dir, const string& regexp) {
|
||||
if (DIR* dirp = opendir(dir.c_str())) {
|
||||
while (struct dirent* direntp = readdir(dirp)) {
|
||||
@@ -512,6 +569,11 @@ string V3Options::version() {
|
||||
return ver;
|
||||
}
|
||||
|
||||
void V3Options::throwSigsegv() {
|
||||
// cppcheck-suppress nullPointer
|
||||
char* zp=NULL; *zp=0;
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// V3 Options utilities
|
||||
|
||||
@@ -545,7 +607,7 @@ void V3Options::parseOpts (FileLine* fl, int argc, char** argv) {
|
||||
if (modPrefix()=="") m_modPrefix = prefix();
|
||||
|
||||
// Find files in makedir
|
||||
addIncDir(makeDir());
|
||||
addIncDirFallback(makeDir());
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
@@ -583,7 +645,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
||||
addDefine (string (sw+strlen("+define+")));
|
||||
}
|
||||
else if ( !strncmp (sw, "+incdir+", 8)) {
|
||||
addIncDir (parseFileArg(optdir, string (sw+strlen("+incdir+"))));
|
||||
addIncDirUser (parseFileArg(optdir, string (sw+strlen("+incdir+"))));
|
||||
}
|
||||
else if ( !strncmp (sw, "+libext+", 8)) {
|
||||
string exts = string(sw+strlen("+libext+"));
|
||||
@@ -627,7 +689,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
||||
else if ( onoff (sw, "-covsp", flag/*ref*/) ) { } // TBD
|
||||
else if ( !strcmp (sw, "-debug-abort") ) { abort(); } // Undocumented, see also --debug-sigsegv
|
||||
else if ( onoff (sw, "-debug-check", flag/*ref*/) ){ m_debugCheck = flag; }
|
||||
else if ( !strcmp (sw, "-debug-sigsegv") ) { char* zp=NULL; *zp=0; } // Undocumented, see also --debug-abort
|
||||
else if ( !strcmp (sw, "-debug-sigsegv") ) { throwSigsegv(); } // Undocumented, see also --debug-abort
|
||||
else if ( !strcmp (sw, "-debug-fatalsrc") ) { v3fatalSrc("--debug-fatal-src"); } // Undocumented, see also --debug-abort
|
||||
else if ( onoff (sw, "-dump-tree", flag/*ref*/) ) { m_dumpTree = flag; }
|
||||
else if ( onoff (sw, "-exe", flag/*ref*/) ) { m_exe = flag; }
|
||||
@@ -706,7 +768,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
||||
m_errorLimit = atoi(argv[i]);
|
||||
}
|
||||
else if ( !strncmp (sw, "-I", 2)) {
|
||||
addIncDir (parseFileArg(optdir, string (sw+strlen("-I"))));
|
||||
addIncDirUser (parseFileArg(optdir, string (sw+strlen("-I"))));
|
||||
}
|
||||
else if ( !strcmp (sw, "-if-depth") && (i+1)<argc ) {
|
||||
shift;
|
||||
@@ -731,7 +793,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
||||
}
|
||||
else if ( !strcmp (sw, "-Mdir") && (i+1)<argc ) {
|
||||
shift; m_makeDir = argv[i];
|
||||
addIncDir (string (m_makeDir)); // Need to find generated files there too
|
||||
addIncDirFallback (string (m_makeDir)); // Need to find generated files there too
|
||||
}
|
||||
else if ( !strcmp (sw, "-o") && (i+1)<argc ) {
|
||||
shift; m_exeName = argv[i];
|
||||
@@ -756,6 +818,14 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
||||
shift;
|
||||
m_traceDepth = atoi(argv[i]);
|
||||
}
|
||||
else if ( !strcmp (sw, "-trace-max-array") && (i+1)<argc ) {
|
||||
shift;
|
||||
m_traceMaxArray = atoi(argv[i]);
|
||||
}
|
||||
else if ( !strcmp (sw, "-trace-max-width") && (i+1)<argc ) {
|
||||
shift;
|
||||
m_traceMaxWidth = atoi(argv[i]);
|
||||
}
|
||||
else if ( !strncmp (sw, "-U", 2)) {
|
||||
V3PreShell::undef (string (sw+strlen("-U")));
|
||||
}
|
||||
@@ -807,6 +877,9 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
||||
else if (!strcmp (sw, "-Wno-style")) {
|
||||
FileLine::globalWarnStyleOff(true);
|
||||
}
|
||||
else if (!strcmp (sw, "-Wno-fatal")) {
|
||||
m_warnFatal = false;
|
||||
}
|
||||
else {
|
||||
string msg = sw+strlen("-Wno-");
|
||||
if (!(FileLine::globalWarnOff(msg, true))) {
|
||||
@@ -886,7 +959,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
||||
}
|
||||
}
|
||||
else if ( !strcmp (sw, "-y") && (i+1)<argc ) {
|
||||
shift; addIncDir (parseFileArg(optdir,string (argv[i])));
|
||||
shift; addIncDirUser (parseFileArg(optdir,string (argv[i])));
|
||||
}
|
||||
else {
|
||||
fl->v3fatal ("Invalid Option: "<<argv[i]);
|
||||
@@ -946,6 +1019,7 @@ void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) {
|
||||
break; // Ignore to EOL
|
||||
} else if (*pos=='/' && *(pos+1)=='*') {
|
||||
inCmt = true;
|
||||
// cppcheck-suppress StlMissingComparison
|
||||
++pos;
|
||||
} else {
|
||||
oline += *pos;
|
||||
@@ -1056,6 +1130,7 @@ V3Options::V3Options() {
|
||||
m_makeDepend = true;
|
||||
m_makePhony = false;
|
||||
m_outFormatOk = false;
|
||||
m_warnFatal = true;
|
||||
m_pinsBv = 65;
|
||||
m_profileCFuncs = false;
|
||||
m_preprocOnly = false;
|
||||
@@ -1077,6 +1152,8 @@ V3Options::V3Options() {
|
||||
m_outputSplitCFuncs = 0;
|
||||
m_outputSplitCTrace = 0;
|
||||
m_traceDepth = 0;
|
||||
m_traceMaxArray = 32;
|
||||
m_traceMaxWidth = 256;
|
||||
m_unrollCount = 64;
|
||||
m_unrollStmts = 30000;
|
||||
|
||||
@@ -1095,8 +1172,9 @@ V3Options::V3Options() {
|
||||
// Default +libext+
|
||||
addLibExt(""); // So include "filename.v" will find the same file
|
||||
addLibExt(".v");
|
||||
addLibExt(".sv");
|
||||
// Default -I
|
||||
addIncDir("."); // Looks better than {long_cwd_path}/...
|
||||
addIncDirFallback("."); // Looks better than {long_cwd_path}/...
|
||||
}
|
||||
|
||||
V3Options::~V3Options() {
|
||||
|
||||
+14
-2
@@ -113,6 +113,7 @@ class V3Options {
|
||||
bool m_l2Name; // main switch: --l2name
|
||||
bool m_lintOnly; // main switch: --lint-only
|
||||
bool m_outFormatOk; // main switch: --cc, --sc or --sp was specified
|
||||
bool m_warnFatal; // main switch: --warnFatal
|
||||
bool m_pinsUint8; // main switch: --pins-uint8
|
||||
bool m_profileCFuncs;// main switch: --profile-cfuncs
|
||||
bool m_psl; // main switch: --psl
|
||||
@@ -134,6 +135,8 @@ class V3Options {
|
||||
int m_outputSplitCTrace;// main switch: --output-split-ctrace
|
||||
int m_pinsBv; // main switch: --pins-bv
|
||||
int m_traceDepth; // main switch: --trace-depth
|
||||
int m_traceMaxArray;// main switch: --trace-max-array
|
||||
int m_traceMaxWidth;// main switch: --trace-max-width
|
||||
int m_unrollCount; // main switch: --unroll-count
|
||||
int m_unrollStmts; // main switch: --unroll-stmts
|
||||
|
||||
@@ -175,10 +178,11 @@ class V3Options {
|
||||
|
||||
private:
|
||||
// METHODS
|
||||
void addArg(const string& incdir);
|
||||
void addArg(const string& flag);
|
||||
void addDefine(const string& defline);
|
||||
void addFuture(const string& flag);
|
||||
void addIncDir(const string& incdir);
|
||||
void addIncDirUser(const string& incdir); // User requested
|
||||
void addIncDirFallback(const string& incdir); // Low priority if not found otherwise
|
||||
void addLibExt(const string& libext);
|
||||
void optimize(int level);
|
||||
void showVersion(bool verbose);
|
||||
@@ -186,6 +190,7 @@ class V3Options {
|
||||
bool onoff(const char* sw, const char* arg, bool& flag);
|
||||
bool suffixed(const char* sw, const char* arg);
|
||||
string parseFileArg(const string& optdir, const string& relfilename);
|
||||
string filePathCheckOneDir(const string& modname, const string& dirname);
|
||||
|
||||
static bool wildmatchi(const char* s, const char* p);
|
||||
static string getenvStr(const string& envvar, const string& defaultValue);
|
||||
@@ -238,6 +243,7 @@ class V3Options {
|
||||
bool traceUnderscore() const { return m_traceUnderscore; }
|
||||
bool outFormatOk() const { return m_outFormatOk; }
|
||||
bool keepTempFiles() const { return (V3Error::debugDefault()!=0); }
|
||||
bool warnFatal() const { return m_warnFatal; }
|
||||
bool pinsUint8() const { return m_pinsUint8; }
|
||||
bool profileCFuncs() const { return m_profileCFuncs; }
|
||||
bool psl() const { return m_psl; }
|
||||
@@ -255,6 +261,8 @@ class V3Options {
|
||||
int outputSplitCTrace() const { return m_outputSplitCTrace; }
|
||||
int pinsBv() const { return m_pinsBv; }
|
||||
int traceDepth() const { return m_traceDepth; }
|
||||
int traceMaxArray() const { return m_traceMaxArray; }
|
||||
int traceMaxWidth() const { return m_traceMaxWidth; }
|
||||
int unrollCount() const { return m_unrollCount; }
|
||||
int unrollStmts() const { return m_unrollStmts; }
|
||||
|
||||
@@ -339,8 +347,12 @@ class V3Options {
|
||||
// METHODS (file utilities using these options)
|
||||
string fileExists (const string& filename);
|
||||
string filePath (FileLine* fl, const string& modname, const string& errmsg);
|
||||
void filePathLookedMsg(FileLine* fl, const string& modname);
|
||||
static bool fileStatDir (const string& filename);
|
||||
static bool fileStatNormal (const string& filename);
|
||||
|
||||
// METHODS (other OS)
|
||||
static void throwSigsegv();
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
+6
-3
@@ -148,7 +148,7 @@ private:
|
||||
|
||||
public:
|
||||
OrderMoveDomScope(OrderLoopId inLoop, AstSenTree* domainp, AstScope* scopep)
|
||||
: m_onReadyList(false), m_domainp(domainp), m_inLoop(inLoop) {}
|
||||
: m_onReadyList(false), m_domainp(domainp), m_scopep(scopep), m_inLoop(inLoop) {}
|
||||
OrderMoveDomScope* readyDomScopeNextp() const { return m_readyDomScopeE.nextp(); }
|
||||
OrderLoopId inLoop() const { return m_inLoop; }
|
||||
AstSenTree* domainp() const { return m_domainp; }
|
||||
@@ -391,8 +391,8 @@ private:
|
||||
void nodeMarkCircular(OrderVarVertex* vertexp, OrderEdge* edgep) {
|
||||
AstVarScope* nodep = vertexp->varScp();
|
||||
nodep->circular(true);
|
||||
m_statCut[vertexp->type()]++;
|
||||
if (edgep) m_statCut[edgep->type()]++;
|
||||
++m_statCut[vertexp->type()];
|
||||
if (edgep) ++m_statCut[edgep->type()];
|
||||
if (vertexp->isClock()) {
|
||||
// Seems obvious; no warning yet
|
||||
//nodep->v3warn(GENCLK,"Signal unoptimizable: Generated clock: "<<nodep->prettyName());
|
||||
@@ -715,6 +715,9 @@ public:
|
||||
m_settleDomainp = NULL;
|
||||
m_settleVxp = NULL;
|
||||
m_inputsVxp = NULL;
|
||||
m_activeSenVxp = NULL;
|
||||
m_logicVxp = NULL;
|
||||
m_pomNewFuncp = NULL;
|
||||
m_loopIdMax = LOOPID_FIRST;
|
||||
m_pomNewStmts = 0;
|
||||
if (debug()) m_graph.debug(5); // 3 is default if global debug; we want acyc debugging
|
||||
|
||||
+1
-1
@@ -105,7 +105,7 @@ struct OrderVEdgeType {
|
||||
return names[m_e];
|
||||
}
|
||||
enum en m_e;
|
||||
inline OrderVEdgeType () {}
|
||||
inline OrderVEdgeType () : m_e(VERTEX_UNKNOWN) {}
|
||||
inline OrderVEdgeType (en _e) : m_e(_e) {}
|
||||
explicit inline OrderVEdgeType (int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en () const { return m_e; }
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
#include "V3Case.h"
|
||||
#include "V3Const.h"
|
||||
#include "V3Width.h"
|
||||
#include "V3Signed.h"
|
||||
#include "V3Unroll.h"
|
||||
|
||||
//######################################################################
|
||||
|
||||
+2
-1
@@ -45,7 +45,8 @@ public:
|
||||
|
||||
// METHODS
|
||||
// Preprocess and read the Verilog file specified into the netlist database
|
||||
void parseFile(FileLine* fileline, const string& modname, bool inLibrary);
|
||||
void parseFile(FileLine* fileline, const string& modname, bool inLibrary,
|
||||
const string& errmsg);
|
||||
|
||||
// Push preprocessed text to the lexer
|
||||
static void ppPushText(V3ParseImp* impp, const string& text);
|
||||
|
||||
+13
-4
@@ -89,7 +89,8 @@ size_t V3ParseImp::ppInputToLex(char* buf, size_t max_size) {
|
||||
return got;
|
||||
}
|
||||
|
||||
void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool inLibrary) {
|
||||
void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool inLibrary,
|
||||
const string& errmsg) { // "" for no error, make fake node
|
||||
string modname = V3Options::filenameNonExt(modfilename);
|
||||
|
||||
UINFO(2,__FUNCTION__<<": "<<modname<<(inLibrary?" [LIB]":"")<<endl);
|
||||
@@ -104,7 +105,14 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i
|
||||
}
|
||||
|
||||
// Preprocess into m_ppBuffer
|
||||
V3PreShell::preproc(fileline, modfilename, m_filterp, this);
|
||||
bool ok = V3PreShell::preproc(fileline, modfilename, m_filterp, this, errmsg);
|
||||
if (!ok) {
|
||||
if (errmsg != "") return; // Threw error already
|
||||
// Create fake node for later error reporting
|
||||
AstNodeModule* nodep = new AstNotFoundModule(fileline, modname);
|
||||
v3Global.rootp()->addModulep(nodep);
|
||||
return;
|
||||
}
|
||||
|
||||
if (v3Global.opt.preprocOnly() || v3Global.opt.keepTempFiles()) {
|
||||
// Create output file with all the preprocessor output we buffered up
|
||||
@@ -157,8 +165,9 @@ V3Parse::V3Parse(AstNetlist* rootp, V3InFilter* filterp) {
|
||||
V3Parse::~V3Parse() {
|
||||
delete m_impp; m_impp = NULL;
|
||||
}
|
||||
void V3Parse::parseFile(FileLine* fileline, const string& modname, bool inLibrary) {
|
||||
m_impp->parseFile(fileline, modname, inLibrary);
|
||||
void V3Parse::parseFile(FileLine* fileline, const string& modname, bool inLibrary,
|
||||
const string& errmsg) {
|
||||
m_impp->parseFile(fileline, modname, inLibrary, errmsg);
|
||||
}
|
||||
void V3Parse::ppPushText(V3ParseImp* impp, const string& text) {
|
||||
impp->ppPushText(text);
|
||||
|
||||
+12
-9
@@ -254,9 +254,10 @@ public:
|
||||
void verilatorCmtLintSave();
|
||||
void verilatorCmtLintRestore();
|
||||
void verilatorCmtBad(const char* text);
|
||||
double parseDouble(const char* text, size_t length);
|
||||
void pushBeginKeywords(int state) { m_inBeginKwd++; m_lastVerilogState=state; }
|
||||
bool popBeginKeywords() { if (m_inBeginKwd) { m_inBeginKwd--; return true; } else return false; }
|
||||
int lastVerilogState() { return m_lastVerilogState; }
|
||||
int lastVerilogState() const { return m_lastVerilogState; }
|
||||
static const char* tokenName(int tok);
|
||||
|
||||
void ppPushText(const string& text) { m_ppBuffers.push_back(text); }
|
||||
@@ -290,12 +291,12 @@ public:
|
||||
}
|
||||
|
||||
// Return next token, for bison, since bison isn't class based, use a global THIS
|
||||
FileLine* fileline() { return m_fileline; }
|
||||
AstNetlist* rootp() { return m_rootp; }
|
||||
FileLine* fileline() const { return m_fileline; }
|
||||
AstNetlist* rootp() const { return m_rootp; }
|
||||
FileLine* copyOrSameFileLine() { return fileline()->copyOrSameFileLine(); }
|
||||
bool inCellDefine() { return m_inCellDefine; }
|
||||
bool inCellDefine() const { return m_inCellDefine; }
|
||||
void inCellDefine(bool flag) { m_inCellDefine = flag; }
|
||||
bool inLibrary() { return m_inLibrary; }
|
||||
bool inLibrary() const { return m_inLibrary; }
|
||||
|
||||
// Interactions with parser
|
||||
int bisonParse();
|
||||
@@ -305,8 +306,8 @@ public:
|
||||
void lexDestroy();
|
||||
void stateExitPsl(); // Parser -> lexer communication
|
||||
void statePushVlg(); // Parser -> lexer communication
|
||||
void statePop(); // Parser -> lexer communication
|
||||
int stateVerilogRecent(); // Parser -> lexer communication
|
||||
void statePop(); // Parser -> lexer communication
|
||||
static int stateVerilogRecent(); // Parser -> lexer communication
|
||||
size_t flexPpInputToLex(char* buf, size_t max_size) { return ppInputToLex(buf,max_size); }
|
||||
|
||||
//==== Symbol tables
|
||||
@@ -315,7 +316,8 @@ public:
|
||||
public:
|
||||
// CREATORS
|
||||
V3ParseImp(AstNetlist* rootp, V3InFilter* filterp)
|
||||
: m_sym(rootp), m_filterp(filterp) {
|
||||
: m_filterp(filterp), m_sym(rootp) {
|
||||
m_fileline = NULL;
|
||||
m_rootp = rootp; m_lexerp = NULL;
|
||||
m_inCellDefine = false;
|
||||
m_inLibrary = false;
|
||||
@@ -331,7 +333,8 @@ public:
|
||||
// Preprocess and read the Verilog file specified into the netlist database
|
||||
int lexToBison(); // Pass token to bison
|
||||
|
||||
void parseFile(FileLine* fileline, const string& modfilename, bool inLibrary);
|
||||
void parseFile(FileLine* fileline, const string& modfilename, bool inLibrary,
|
||||
const string& errmsg);
|
||||
|
||||
private:
|
||||
void lexFile(const string& modname);
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@ public:
|
||||
void V3ParseImp::stateExitPsl() { parsep()->m_lexerp->stateExitPsl(); }
|
||||
void V3ParseImp::statePushVlg() { parsep()->m_lexerp->stateExitPsl(); }
|
||||
void V3ParseImp::statePop() { parsep()->m_lexerp->statePop(); }
|
||||
int V3ParseImp::yylexThis() { parsep()->m_lexerp->yylex(); }
|
||||
int V3ParseImp::yylexThis() { return parsep()->m_lexerp->yylex(); }
|
||||
|
||||
//######################################################################
|
||||
// Read class functions
|
||||
|
||||
+1
-1
@@ -203,7 +203,7 @@ class V3PreLex {
|
||||
/// Called by V3PreProc.cpp to get data from lexer
|
||||
YY_BUFFER_STATE currentBuffer();
|
||||
int lex();
|
||||
int currentStartState();
|
||||
int currentStartState() const;
|
||||
void dumpSummary();
|
||||
void dumpStack();
|
||||
void unused();
|
||||
|
||||
+2
-1
@@ -488,7 +488,7 @@ YY_BUFFER_STATE V3PreLex::currentBuffer() {
|
||||
return YY_CURRENT_BUFFER;
|
||||
}
|
||||
|
||||
int V3PreLex::currentStartState() {
|
||||
int V3PreLex::currentStartState() const {
|
||||
return YY_START;
|
||||
}
|
||||
|
||||
@@ -538,6 +538,7 @@ void V3PreLex::unused() {
|
||||
if (0) {
|
||||
// Prevent unused warnings
|
||||
yy_top_state();
|
||||
yyerror((char*)"");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-1
@@ -127,7 +127,7 @@ struct V3PreProcImp : public V3PreProc {
|
||||
ps_DEFNAME_IFDEF, ps_DEFNAME_IFNDEF, ps_DEFNAME_ELSIF,
|
||||
ps_DEFFORM, ps_DEFVALUE, ps_DEFPAREN, ps_DEFARG,
|
||||
ps_INCNAME, ps_ERRORNAME, ps_JOIN, ps_STRIFY };
|
||||
const char* procStateName(ProcState s) {
|
||||
static const char* procStateName(ProcState s) {
|
||||
static const char* states[]
|
||||
= {"ps_TOP",
|
||||
"ps_DEFNAME_UNDEF", "ps_DEFNAME_DEFINE",
|
||||
@@ -251,6 +251,10 @@ public:
|
||||
m_finAtBol = true;
|
||||
m_defDepth = 0;
|
||||
m_defPutJoin = false;
|
||||
m_finToken = 0;
|
||||
m_finFilelinep = NULL;
|
||||
m_lexp = NULL;
|
||||
m_preprocp = NULL;
|
||||
}
|
||||
void configure(FileLine* filelinep) {
|
||||
// configure() separate from constructor to avoid calling abstract functions
|
||||
@@ -393,6 +397,9 @@ void V3PreProcImp::comment(const string& text) {
|
||||
} else if (0==(strncmp(cp,"cadence",strlen("cadence")))) {
|
||||
cp+=strlen("cadence");
|
||||
synth = true;
|
||||
} else if (0==(strncmp(cp,"pragma",strlen("pragma")))) {
|
||||
cp+=strlen("pragma");
|
||||
synth = true;
|
||||
} else if (0==(strncmp(cp,"ambit synthesis",strlen("ambit synthesis")))) {
|
||||
cp+=strlen("ambit synthesis");
|
||||
synth = true;
|
||||
|
||||
+4
-4
@@ -67,10 +67,10 @@ public:
|
||||
|
||||
// CONTROL METHODS
|
||||
// These options control how the parsing proceeds
|
||||
int keepComments() { return 2; } // Return comments, 0=no, 1=yes, 2=callback
|
||||
bool keepWhitespace() { return false; }
|
||||
bool lineDirectives() { return true; } // Insert `line directives
|
||||
bool pedantic() { return false; } // Obey standard; Don't substitute `error
|
||||
static int keepComments() { return 2; } // Return comments, 0=no, 1=yes, 2=callback
|
||||
static bool keepWhitespace() { return false; }
|
||||
static bool lineDirectives() { return true; } // Insert `line directives
|
||||
static bool pedantic() { return false; } // Obey standard; Don't substitute `error
|
||||
static bool optPsl();
|
||||
|
||||
// CALLBACK METHODS
|
||||
|
||||
+14
-6
@@ -74,7 +74,8 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
void preproc (FileLine* fl, const string& modname, V3InFilter* filterp, V3ParseImp* parsep) {
|
||||
bool preproc (FileLine* fl, const string& modname, V3InFilter* filterp, V3ParseImp* parsep,
|
||||
const string& errmsg) { // "" for no error
|
||||
debug(true); // Recheck if debug on - first check was before command line passed
|
||||
|
||||
// Preprocess the given module, putting output in vppFilename
|
||||
@@ -82,11 +83,14 @@ protected:
|
||||
|
||||
// Preprocess
|
||||
s_filterp = filterp;
|
||||
preprocOpen(fl, s_filterp, modname, "Cannot find file containing module: ");
|
||||
bool ok = preprocOpen(fl, s_filterp, modname, errmsg);
|
||||
if (!ok) return false;
|
||||
|
||||
while (!s_preprocp->isEof()) {
|
||||
string line = s_preprocp->getline();
|
||||
V3Parse::ppPushText(parsep, line);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void preprocInclude (FileLine* fl, const string& modname) {
|
||||
@@ -96,17 +100,20 @@ protected:
|
||||
preprocOpen(fl, s_filterp, modname, "Cannot find include file: ");
|
||||
}
|
||||
|
||||
void preprocOpen (FileLine* fl, V3InFilter* filterp, const string& modname, const string& errmsg) {
|
||||
bool preprocOpen (FileLine* fl, V3InFilter* filterp, const string& modname,
|
||||
const string& errmsg) { // Error message or "" to suppress
|
||||
// Returns true if successful
|
||||
// Allow user to put `defined names on the command line instead of filenames,
|
||||
// then convert them properly.
|
||||
string ppmodname = s_preprocp->removeDefines (modname);
|
||||
|
||||
// Open include or master file
|
||||
string filename = v3Global.opt.filePath (fl, ppmodname, errmsg);
|
||||
if (filename=="") return; // Not found
|
||||
if (filename=="") return false; // Not found
|
||||
|
||||
UINFO(2," Reading "<<filename<<endl);
|
||||
s_preprocp->openFile(fl, filterp, filename);
|
||||
return true;
|
||||
}
|
||||
|
||||
// CONSTRUCTORS
|
||||
@@ -124,8 +131,9 @@ V3InFilter* V3PreShellImp::s_filterp = NULL;
|
||||
void V3PreShell::boot(char** env) {
|
||||
V3PreShellImp::s_preImp.boot(env);
|
||||
}
|
||||
void V3PreShell::preproc(FileLine* fl, const string& modname, V3InFilter* filterp, V3ParseImp* parsep) {
|
||||
V3PreShellImp::s_preImp.preproc(fl, modname, filterp, parsep);
|
||||
bool V3PreShell::preproc(FileLine* fl, const string& modname, V3InFilter* filterp,
|
||||
V3ParseImp* parsep, const string& errmsg) {
|
||||
return V3PreShellImp::s_preImp.preproc(fl, modname, filterp, parsep, errmsg);
|
||||
}
|
||||
void V3PreShell::preprocInclude(FileLine* fl, const string& modname) {
|
||||
V3PreShellImp::s_preImp.preprocInclude(fl, modname);
|
||||
|
||||
+2
-1
@@ -36,7 +36,8 @@ class V3PreShell {
|
||||
// Static class for calling preprocessor
|
||||
public:
|
||||
static void boot(char** env);
|
||||
static void preproc(FileLine* fileline, const string& module, V3InFilter* filterp, V3ParseImp* parsep);
|
||||
static bool preproc(FileLine* fileline, const string& module, V3InFilter* filterp,
|
||||
V3ParseImp* parsep, const string& errmsg);
|
||||
static void preprocInclude(FileLine* fileline, const string& module);
|
||||
static string dependFiles() { return ""; } // Perl only
|
||||
static void defineCmdLine(const string& name, const string& value);
|
||||
|
||||
+6
-6
@@ -208,12 +208,12 @@ private:
|
||||
// Then over shifting gives the sign bit, not all zeros
|
||||
// Note *NOT* clean output -- just like normal shift!
|
||||
// Create equivalent of VL_SIGNONES_(node_width)
|
||||
constzerop = new AstUnaryMin (nodep->fileline(),
|
||||
new AstShiftR(nodep->fileline(),
|
||||
nodep->lhsp()->cloneTree(false),
|
||||
new AstConst(nodep->fileline(),
|
||||
nodep->widthMin()-1),
|
||||
nodep->width()));
|
||||
constzerop = new AstNegate (nodep->fileline(),
|
||||
new AstShiftR(nodep->fileline(),
|
||||
nodep->lhsp()->cloneTree(false),
|
||||
new AstConst(nodep->fileline(),
|
||||
nodep->widthMin()-1),
|
||||
nodep->width()));
|
||||
} else {
|
||||
V3Number zeronum (nodep->fileline(), nodep->width(), 0);
|
||||
constzerop = new AstConst(nodep->fileline(), zeronum);
|
||||
|
||||
@@ -1,441 +0,0 @@
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Signed/unsigned resolution
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2005-2011 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.
|
||||
//
|
||||
//*************************************************************************
|
||||
// Signedness depends on:
|
||||
// Decimal numbers are signed
|
||||
// Based numbers are unsigned unless 's' prefix
|
||||
// Comparison results are unsigned
|
||||
// Bit&Part selects are unsigned, even if whole
|
||||
// Concatenates are unsigned
|
||||
// Ignore signedness of self-determined:
|
||||
// shift rhs, ** rhs, x?: lhs, concat and replicate members
|
||||
// Else, if any operand unsigned, output unsigned
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <unistd.h>
|
||||
#include <map>
|
||||
#include <iomanip>
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3Signed.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
//######################################################################
|
||||
// Signed class functions
|
||||
|
||||
class SignedVisitor : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE/TYPES
|
||||
// STATE
|
||||
int m_taskDepth; // Recursion check
|
||||
bool m_paramsOnly; // Computing parameter value; limit operation
|
||||
|
||||
// METHODS - special type detection
|
||||
bool backRequiresUnsigned(AstNode* nodep) {
|
||||
// The spec doesn't state this, but if you have an array select where the selection
|
||||
// index is NOT wide enough, you do not sign extend, but always zero extend.
|
||||
return (nodep->castArraySel()
|
||||
|| nodep->castSel());
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
//========
|
||||
// Signed: Output explicit by user, Lhs either
|
||||
virtual void visit(AstSigned* nodep, AstNUser*) { signed_Os_Ix(nodep); }
|
||||
virtual void visit(AstUnsigned* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
|
||||
//========
|
||||
// Signed: Output unsigned, Operands either
|
||||
virtual void visit(AstSel* nodep, AstNUser*) { signed_Ou_Ix(nodep); } //See backRequiresUnsigned
|
||||
virtual void visit(AstAttrOf* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstCountOnes* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstCLog2* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstPslBool* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstTime* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
//
|
||||
virtual void visit(AstRedAnd* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstRedOr* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstRedXnor* nodep, AstNUser*){ signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstRedXor* nodep,AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstIsUnknown* nodep,AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstOneHot* nodep,AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstOneHot0* nodep,AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstFEof* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstFGetC* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstFGetS* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstFScanF* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstSScanF* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstTestPlusArgs* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstValuePlusArgs* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
//
|
||||
virtual void visit(AstConcat* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstReplicate* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstRange* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
// ... One presumes these are unsigned out, though the spec doesn't say
|
||||
virtual void visit(AstLogNot* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstLogAnd* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstLogOr* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstLogIf* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstLogIff* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
// ... These shouldn't matter, just make unsigned
|
||||
virtual void visit(AstScopeName* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstText* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstUCFunc* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
// ... These comparisons don't care about inbound types
|
||||
// ... (Though they should match. We don't check.)
|
||||
virtual void visit(AstEq* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstEqCase* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstEqWild* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstNeq* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstNeqCase* nodep, AstNUser*){ signed_Ou_Ix(nodep); }
|
||||
virtual void visit(AstNeqWild* nodep, AstNUser*){ signed_Ou_Ix(nodep); }
|
||||
// ... Opaque returns, so arbitrary
|
||||
virtual void visit(AstCvtPackString* nodep, AstNUser*){ signed_Ou_Ix(nodep); }
|
||||
|
||||
//========
|
||||
// Signed: Output signed
|
||||
virtual void visit(AstRand* nodep, AstNUser*) { signed_Os_Ix(nodep); }
|
||||
|
||||
//=======
|
||||
// Signed: Output signed iff LHS signed; unary operator
|
||||
virtual void visit(AstNot* nodep, AstNUser*) { signed_Olhs(nodep); }
|
||||
virtual void visit(AstUnaryMin* nodep, AstNUser*) { signed_Olhs(nodep); }
|
||||
virtual void visit(AstShiftL* nodep, AstNUser*) { signed_Olhs(nodep); }
|
||||
virtual void visit(AstShiftR* nodep, AstNUser*) { signed_Olhs(nodep); }
|
||||
|
||||
// Signed: Output signed iff LHS signed; binary operator
|
||||
// Note by contrast, bit extract selects are unsigned
|
||||
virtual void visit(AstArraySel* nodep, AstNUser*) { signed_Olhs(nodep); } //See backRequiresUnsigned
|
||||
|
||||
//=======
|
||||
// Signed: Output signed iff LHS & RHS signed; binary operator
|
||||
virtual void visit(AstAnd* nodep, AstNUser*) { signed_OlhsAndRhs(nodep); }
|
||||
virtual void visit(AstOr* nodep, AstNUser*) { signed_OlhsAndRhs(nodep); }
|
||||
virtual void visit(AstXnor* nodep, AstNUser*) { signed_OlhsAndRhs(nodep); }
|
||||
virtual void visit(AstXor* nodep, AstNUser*) { signed_OlhsAndRhs(nodep); }
|
||||
virtual void visit(AstSub* nodep, AstNUser*) { signed_OlhsAndRhs(nodep); }
|
||||
virtual void visit(AstAdd* nodep, AstNUser*) { signed_OlhsAndRhs(nodep); }
|
||||
|
||||
//=======
|
||||
// Signed: Output signed iff RHS & THS signed
|
||||
virtual void visit(AstNodeCond* nodep, AstNUser*) { signed_OrhsAndThs(nodep); }
|
||||
|
||||
//=======
|
||||
// These have proper signedness set when they were created.
|
||||
virtual void visit(AstReturn* nodep, AstNUser*) { nodep->iterateChildren(*this); }
|
||||
virtual void visit(AstNodeDType* nodep, AstNUser*) { nodep->iterateChildren(*this); }
|
||||
|
||||
// Inherit from others
|
||||
virtual void visit(AstVar* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->signedFrom(nodep->dtypep());
|
||||
}
|
||||
virtual void visit(AstNodeVarRef* nodep, AstNUser*) {
|
||||
nodep->varp()->iterate(*this);
|
||||
nodep->signedFrom(nodep->varp());
|
||||
}
|
||||
virtual void visit(AstEnumItemRef* nodep, AstNUser*) {
|
||||
nodep->itemp()->iterate(*this);
|
||||
nodep->signedFrom(nodep->itemp());
|
||||
}
|
||||
virtual void visit(AstConst* nodep, AstNUser*) {
|
||||
// The node got setup with the signed state of the node.
|
||||
// However a later operation may have changed the node->signed w/o changing
|
||||
// the number's sign. So we don't: nodep->isSigned(nodep->num().isSigned());
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
||||
// Avoid recursion; can't use user() as they're all full, and anyhow this is often called
|
||||
if (nodep->didSigning()) return;
|
||||
nodep->didSigning(true);
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->fvarp()) {
|
||||
nodep->signedFrom(nodep->fvarp()); // Which will get it from fvarp()->dtypep()
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->taskp()) nodep->taskp()->iterate(*this);
|
||||
nodep->signedFrom(nodep->taskp());
|
||||
}
|
||||
virtual void visit(AstRefDType* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->defp()) nodep->defp()->iterate(*this);
|
||||
nodep->signedFrom(nodep->skipRefp());
|
||||
}
|
||||
virtual void visit(AstNodeIf* nodep, AstNUser*) {
|
||||
if (!nodep->castGenIf()) { // for m_paramsOnly
|
||||
nodep->ifsp()->iterateAndNext(*this);
|
||||
nodep->elsesp()->iterateAndNext(*this);
|
||||
}
|
||||
nodep->condp()->iterateAndNext(*this);
|
||||
}
|
||||
virtual void visit(AstPin* nodep, AstNUser*) {
|
||||
// Same as above taskref argument.
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
// VISITORS - Special
|
||||
virtual void visit(AstSFormatF* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
//
|
||||
UINFO(9," Display in "<<nodep->text()<<endl);
|
||||
string dispout = "";
|
||||
bool inPct = false;
|
||||
AstNode* argp = nodep->exprsp();
|
||||
for (const char* inp = nodep->text().c_str(); *inp; inp++) {
|
||||
char ch = *inp; // Breaks with iterators...
|
||||
if (!inPct && ch=='%') {
|
||||
inPct = true;
|
||||
} else if (inPct && isdigit(ch)) {
|
||||
} else if (tolower(inPct)) {
|
||||
inPct = false;
|
||||
switch (tolower(ch)) {
|
||||
case '%': break; // %% - just output a %
|
||||
case 'm': break; // %m - auto insert "name"
|
||||
case 'd': { // Convert decimal to either 'd' or 'u'
|
||||
if (argp && argp->isSigned()) { // Convert it
|
||||
ch = '~';
|
||||
}
|
||||
if (argp) argp=argp->nextp();
|
||||
break;
|
||||
}
|
||||
default: // Most operators, just move to next argument
|
||||
if (argp) argp=argp->nextp();
|
||||
break;
|
||||
} // switch
|
||||
}
|
||||
dispout += ch;
|
||||
}
|
||||
nodep->text(dispout);
|
||||
UINFO(9," Display out "<<nodep->text()<<endl);
|
||||
}
|
||||
|
||||
// VISITORS - These need to be changed to different op types
|
||||
// Uniop
|
||||
virtual void visit(AstExtend* nodep, AstNUser*) {
|
||||
signed_Olhs(nodep);
|
||||
if (nodep->isSigned() && !backRequiresUnsigned(nodep->backp())) {
|
||||
replaceWithSignedVersion(nodep, new AstExtendS (nodep->fileline(), nodep->lhsp()->unlinkFrBack())); nodep=NULL;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstExtendS* nodep, AstNUser*) {
|
||||
signed_Olhs(nodep);
|
||||
if (!(nodep->isSigned() && !backRequiresUnsigned(nodep->backp()))) {
|
||||
replaceWithSignedVersion(nodep, new AstExtend (nodep->fileline(), nodep->lhsp()->unlinkFrBack())); nodep=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Biop
|
||||
virtual void visit(AstPow* nodep, AstNUser*) {
|
||||
// Pow is special, output sign only depends on LHS sign
|
||||
signed_Olhs(nodep);
|
||||
if (nodep->isSigned()) {
|
||||
replaceWithSignedVersion(nodep, new AstPowS (nodep->fileline(), nodep->lhsp()->unlinkFrBack(), nodep->rhsp()->unlinkFrBack())); nodep=NULL;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstPowS* nodep, AstNUser*) {
|
||||
// Pow is special, output sign only depends on LHS sign
|
||||
signed_Olhs(nodep);
|
||||
if (!nodep->isSigned()) {
|
||||
replaceWithSignedVersion(nodep, new AstPow (nodep->fileline(), nodep->lhsp()->unlinkFrBack(), nodep->rhsp()->unlinkFrBack())); nodep=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// These have different node types, as they operate differently
|
||||
// Must add to case statement below,
|
||||
virtual void visit(AstGt* nodep, AstNUser*) { checkReplace_Ou_FlavLhsAndRhs(nodep); }
|
||||
virtual void visit(AstGtS* nodep, AstNUser*) { checkReplace_Ou_FlavLhsAndRhs(nodep); }
|
||||
virtual void visit(AstGte* nodep, AstNUser*) { checkReplace_Ou_FlavLhsAndRhs(nodep); }
|
||||
virtual void visit(AstGteS* nodep, AstNUser*) { checkReplace_Ou_FlavLhsAndRhs(nodep); }
|
||||
virtual void visit(AstLt* nodep, AstNUser*) { checkReplace_Ou_FlavLhsAndRhs(nodep); }
|
||||
virtual void visit(AstLtS* nodep, AstNUser*) { checkReplace_Ou_FlavLhsAndRhs(nodep); }
|
||||
virtual void visit(AstLte* nodep, AstNUser*) { checkReplace_Ou_FlavLhsAndRhs(nodep); }
|
||||
virtual void visit(AstLteS* nodep, AstNUser*) { checkReplace_Ou_FlavLhsAndRhs(nodep); }
|
||||
// Need replacements; output matches input sign
|
||||
virtual void visit(AstDiv* nodep, AstNUser*) { checkReplace_OlhsAndRhs(nodep); }
|
||||
virtual void visit(AstDivS* nodep, AstNUser*) { checkReplace_OlhsAndRhs(nodep); }
|
||||
virtual void visit(AstModDiv* nodep, AstNUser*) { checkReplace_OlhsAndRhs(nodep); }
|
||||
virtual void visit(AstModDivS* nodep, AstNUser*) { checkReplace_OlhsAndRhs(nodep); }
|
||||
virtual void visit(AstMul* nodep, AstNUser*) { checkReplace_OlhsAndRhs(nodep); }
|
||||
virtual void visit(AstMulS* nodep, AstNUser*) { checkReplace_OlhsAndRhs(nodep); }
|
||||
// ShiftRS converts to ShiftR, but not vice-versa
|
||||
virtual void visit(AstShiftRS* nodep, AstNUser*) { checkReplace_Olhs(nodep); }
|
||||
|
||||
void checkReplace_Ou_FlavLhsAndRhs(AstNodeBiop* nodep) {
|
||||
// For compares, the output of the comparison is unsigned.
|
||||
// However, we need the appropriate type of compare selected by RHS & LHS
|
||||
signed_Ou_Ix(nodep);
|
||||
checkReplace(nodep, nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned());
|
||||
}
|
||||
void checkReplace_Olhs(AstNodeBiop* nodep) {
|
||||
signed_Olhs(nodep);
|
||||
checkReplace(nodep, nodep->isSigned());
|
||||
}
|
||||
void checkReplace_OlhsAndRhs(AstNodeBiop* nodep) {
|
||||
signed_OlhsAndRhs(nodep);
|
||||
checkReplace(nodep, nodep->isSigned());
|
||||
}
|
||||
|
||||
void checkReplace(AstNodeBiop* nodep, bool signedFlavorNeeded) {
|
||||
if (signedFlavorNeeded != nodep->signedFlavor()) {
|
||||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* newp = NULL;
|
||||
// Given a signed/unsigned node type, create the opposite type
|
||||
switch (nodep->type()) {
|
||||
case AstType::atGT: newp = new AstGtS (nodep->fileline(), lhsp, rhsp); break;
|
||||
case AstType::atGTS: newp = new AstGt (nodep->fileline(), lhsp, rhsp); break;
|
||||
case AstType::atGTE: newp = new AstGteS (nodep->fileline(), lhsp, rhsp); break;
|
||||
case AstType::atGTES: newp = new AstGte (nodep->fileline(), lhsp, rhsp); break;
|
||||
case AstType::atLT: newp = new AstLtS (nodep->fileline(), lhsp, rhsp); break;
|
||||
case AstType::atLTS: newp = new AstLt (nodep->fileline(), lhsp, rhsp); break;
|
||||
case AstType::atLTE: newp = new AstLteS (nodep->fileline(), lhsp, rhsp); break;
|
||||
case AstType::atLTES: newp = new AstLte (nodep->fileline(), lhsp, rhsp); break;
|
||||
case AstType::atDIV: newp = new AstDivS (nodep->fileline(), lhsp, rhsp); break;
|
||||
case AstType::atDIVS: newp = new AstDiv (nodep->fileline(), lhsp, rhsp); break;
|
||||
case AstType::atMODDIV: newp = new AstModDivS (nodep->fileline(), lhsp, rhsp); break;
|
||||
case AstType::atMODDIVS: newp = new AstModDiv (nodep->fileline(), lhsp, rhsp); break;
|
||||
case AstType::atMUL: newp = new AstMulS (nodep->fileline(), lhsp, rhsp); break;
|
||||
case AstType::atMULS: newp = new AstMul (nodep->fileline(), lhsp, rhsp); break;
|
||||
case AstType::atSHIFTRS: newp = new AstShiftR (nodep->fileline(), lhsp, rhsp); break;
|
||||
default:
|
||||
nodep->v3fatalSrc("Node needs sign change, but bad case: "<<nodep<<endl);
|
||||
break;
|
||||
}
|
||||
replaceWithSignedVersion(nodep,newp);
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS - defaults
|
||||
virtual void visit(AstNodeMath* nodep, AstNUser*) {
|
||||
nodep->v3fatalSrc("Visit function missing? Signedness unknown for this node: "<<nodep);
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
// COMMON SCHEMES
|
||||
// Signed: Output signed, Lhs/Rhs/etc either
|
||||
void signed_Os_Ix(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->isSigned(true);
|
||||
}
|
||||
// Signed: Output unsigned, Lhs/Rhs/etx either
|
||||
void signed_Ou_Ix(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->isSigned(false);
|
||||
}
|
||||
// Signed: Output signed iff LHS signed; unary operator
|
||||
void signed_Olhs(AstNodeUniop* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->isSigned(nodep->lhsp()->isSigned());
|
||||
}
|
||||
// Signed: Output signed iff LHS signed; binary operator
|
||||
void signed_Olhs(AstNodeBiop* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->isSigned(nodep->lhsp()->isSigned());
|
||||
}
|
||||
// Signed: Output signed iff LHS signed; select operator
|
||||
void signed_Olhs(AstSel* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->isSigned(nodep->fromp()->isSigned());
|
||||
}
|
||||
// Signed: Output signed iff LHS & RHS signed; binary operator
|
||||
void signed_OlhsAndRhs(AstNodeBiop* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->isSigned(nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned());
|
||||
}
|
||||
// Signed: Output signed iff RHS & THS signed
|
||||
void signed_OrhsAndThs(AstNodeTriop* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->isSigned(nodep->rhsp()->isSigned() && nodep->thsp()->isSigned());
|
||||
}
|
||||
void replaceWithSignedVersion(AstNode* nodep, AstNode* newp) {
|
||||
UINFO(6," Replace "<<nodep<<" w/ "<<newp<<endl);
|
||||
nodep->replaceWith(newp);
|
||||
newp->widthSignedFrom(nodep);
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
SignedVisitor(bool paramsOnly) {
|
||||
m_paramsOnly = paramsOnly;
|
||||
m_taskDepth = 0;
|
||||
}
|
||||
virtual ~SignedVisitor() {}
|
||||
AstNode* mainAcceptEdit(AstNode* nodep) {
|
||||
return nodep->acceptSubtreeReturnEdits(*this);
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Signed class functions
|
||||
/// Remove all $signed, $unsigned, we're done with them.
|
||||
|
||||
class SignedRemoveVisitor : public AstNVisitor {
|
||||
private:
|
||||
// VISITORS
|
||||
virtual void visit(AstSigned* nodep, AstNUser*) {
|
||||
replaceWithSignedVersion(nodep, nodep->lhsp()->unlinkFrBack()); nodep=NULL;
|
||||
}
|
||||
virtual void visit(AstUnsigned* nodep, AstNUser*) {
|
||||
replaceWithSignedVersion(nodep, nodep->lhsp()->unlinkFrBack()); nodep=NULL;
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
void replaceWithSignedVersion(AstNode* nodep, AstNode* newp) {
|
||||
UINFO(6," Replace "<<nodep<<" w/ "<<newp<<endl);
|
||||
nodep->replaceWith(newp);
|
||||
newp->widthSignedFrom(nodep);
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
SignedRemoveVisitor() {}
|
||||
virtual ~SignedRemoveVisitor() {}
|
||||
AstNode* mainAcceptEdit(AstNode* nodep) {
|
||||
return nodep->acceptSubtreeReturnEdits(*this);
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Top Signed class
|
||||
|
||||
void V3Signed::signedAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
(void)signedParamsEdit(nodep);
|
||||
}
|
||||
|
||||
AstNode* V3Signed::signedParamsEdit(AstNode* nodep) {
|
||||
// Only called from V3Width::widthParamsEdit
|
||||
UINFO(4,__FUNCTION__<<": "<<endl);
|
||||
SignedVisitor visitor (true);
|
||||
nodep = visitor.mainAcceptEdit(nodep);
|
||||
SignedRemoveVisitor rvisitor;
|
||||
nodep = rvisitor.mainAcceptEdit(nodep);
|
||||
return nodep;
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Signed/unsigned resolution
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2005-2011 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 _V3SIGNED_H_
|
||||
#define _V3SIGNED_H_ 1
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3Error.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Signed {
|
||||
public:
|
||||
static void signedAll(AstNetlist* nodep);
|
||||
protected:
|
||||
friend class V3Width; // Use widthParamsEdit instead of signedParamsEdit
|
||||
static AstNode* signedParamsEdit(AstNode* nodep); // May replace nodep
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
+8
-4
@@ -53,6 +53,7 @@ class SliceCloneVisitor : public AstNVisitor {
|
||||
// Inputs:
|
||||
// AstArraySel::user1p() -> AstVarRef. The VarRef that the final ArraySel points to
|
||||
// AstNodeAssign::user2() -> int. The number of clones needed for this assign
|
||||
// AstArraySel::user3() -> bool. Error detected
|
||||
|
||||
// ENUMS
|
||||
enum RedOp { // The type of unary operation to be expanded
|
||||
@@ -221,6 +222,7 @@ class SliceVisitor : public AstNVisitor {
|
||||
// AstNode::user2() -> int. The number of clones needed for this node
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser3InUse m_inuser3;
|
||||
|
||||
// TYPEDEFS
|
||||
typedef pair<uint32_t, uint32_t> ArrayDimensions; // Array Dimensions (packed, unpacked)
|
||||
@@ -328,11 +330,11 @@ class SliceVisitor : public AstNVisitor {
|
||||
m_assignp->v3error("Unsupported: Assignment between a constant and an array slice");
|
||||
m_assignError = true;
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
virtual void visit(AstArraySel* nodep, AstNUser*) {
|
||||
if (!m_assignp) return;
|
||||
if (nodep->user3()) return; // Prevent recursion on just created nodes
|
||||
unsigned dim = explicitDimensions(nodep);
|
||||
AstVarRef* refp = nodep->user1p()->castNode()->castVarRef();
|
||||
pair<uint32_t,uint32_t> arrDim = refp->varp()->dimensions();
|
||||
@@ -340,16 +342,18 @@ class SliceVisitor : public AstNVisitor {
|
||||
if (implicit > 0) {
|
||||
AstArraySel* newp = insertImplicit(nodep->cloneTree(false), dim+1, implicit);
|
||||
nodep->replaceWith(newp); nodep = newp;
|
||||
nodep->user3(true);
|
||||
}
|
||||
int clones = countClones(nodep);
|
||||
if (m_assignp->user2() > 0 && m_assignp->user2() != clones) {
|
||||
m_assignp->v3error("Slices of arrays in assignments must have the same unpacked dimensions");
|
||||
} else if (m_assignp->user2() == 0 && !m_assignError) {
|
||||
if (m_extend && clones > 1) {
|
||||
} else if (!m_assignp->user2()) {
|
||||
if (m_extend && clones > 1 && !m_assignError) {
|
||||
m_assignp->v3error("Unsupported: Assignment between packed arrays of different dimensions");
|
||||
m_assignError = true;
|
||||
}
|
||||
if (clones > 1 && !refp->lvalue() && refp->varp() == m_lhsVarRefp->varp() && !m_assignp->castAssignDly()) {
|
||||
if (clones > 1 && !refp->lvalue() && refp->varp() == m_lhsVarRefp->varp()
|
||||
&& !m_assignp->castAssignDly() && !m_assignError) {
|
||||
// LHS Var != RHS Var for a non-delayed assignment
|
||||
m_assignp->v3error("Unsupported: Slices in a non-delayed assignment with the same Var on both sides");
|
||||
m_assignError = true;
|
||||
|
||||
+25
-9
@@ -229,6 +229,7 @@ private:
|
||||
|
||||
// STATE
|
||||
bool m_reorder; // Reorder statements vs. just splitting
|
||||
string m_noReorderWhy; // Reason we can't reorder
|
||||
VStack m_stmtStackps; // Current statements being tracked
|
||||
SplitPliVertex* m_pliVertexp; // Element specifying PLI ordering
|
||||
V3Graph m_graph; // Scoreboard of var usages/dependencies
|
||||
@@ -249,6 +250,7 @@ private:
|
||||
m_graph.clear();
|
||||
m_stmtStackps.clear();
|
||||
m_pliVertexp = NULL;
|
||||
m_noReorderWhy = "";
|
||||
AstNode::user1ClearTree();
|
||||
AstNode::user2ClearTree();
|
||||
AstNode::user3ClearTree();
|
||||
@@ -336,6 +338,7 @@ private:
|
||||
}
|
||||
|
||||
// Weak coloring to determine what needs to remain in order
|
||||
// This follows all step-relevant edges excluding PostEdges, which are done later
|
||||
m_graph.weaklyConnected(&SplitEdge::followScoreboard);
|
||||
|
||||
// Add hard orderings between all nodes of same color, in the order they appeared
|
||||
@@ -413,7 +416,7 @@ private:
|
||||
newListp = newListp->addNext(nextp);
|
||||
}
|
||||
if (splitAlwaysp) {
|
||||
m_statSplits++;
|
||||
++m_statSplits;
|
||||
AstAlways* alwaysp = new AstAlways(newListp->fileline(), NULL, NULL);
|
||||
addAfterp->addNextHere(alwaysp); addAfterp=alwaysp;
|
||||
alwaysp->addStmtp(newListp);
|
||||
@@ -445,14 +448,18 @@ private:
|
||||
UINFO(9," processBlock "<<nodep<<endl);
|
||||
// Process block and followers
|
||||
scanBlock(nodep);
|
||||
// Reorder statements in this block
|
||||
cleanupBlockGraph(nodep);
|
||||
reorderBlock(nodep);
|
||||
// Delete old vertexes and edges only applying to this block
|
||||
while (firstp->backp()->nextp()==firstp) firstp = firstp->backp(); // Walk back to first in list
|
||||
for (AstNode* nextp=firstp; nextp; nextp=nextp->nextp()) {
|
||||
SplitLogicVertex* vvertexp = (SplitLogicVertex*)nextp->user3p();
|
||||
vvertexp->unlinkDelete(&m_graph);
|
||||
if (m_noReorderWhy != "") { // Jump or something nasty
|
||||
UINFO(9," NoReorderBlock because "<<m_noReorderWhy<<endl);
|
||||
} else {
|
||||
// Reorder statements in this block
|
||||
cleanupBlockGraph(nodep);
|
||||
reorderBlock(nodep);
|
||||
// Delete old vertexes and edges only applying to this block
|
||||
while (firstp->backp()->nextp()==firstp) firstp = firstp->backp(); // Walk back to first in list
|
||||
for (AstNode* nextp=firstp; nextp; nextp=nextp->nextp()) {
|
||||
SplitLogicVertex* vvertexp = (SplitLogicVertex*)nextp->user3p();
|
||||
vvertexp->unlinkDelete(&m_graph);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Again, nodep may no longer be first.
|
||||
@@ -534,6 +541,15 @@ private:
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstJumpGo* nodep, AstNUser*) {
|
||||
// Jumps will disable reordering at all levels
|
||||
// This is overly pessimistic; we could treat jumps as barriers, and
|
||||
// reorder everything between jumps/labels, however jumps are rare
|
||||
// in always, so the performance gain probably isn't worth the work.
|
||||
UINFO(9," NoReordering "<<nodep<<endl);
|
||||
m_noReorderWhy = "JumpGo";
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
//--------------------
|
||||
// Default
|
||||
|
||||
+1
-1
@@ -185,7 +185,7 @@ private:
|
||||
// Now isolate the always
|
||||
if (m_splitVscp) {
|
||||
splitAlways(nodep);
|
||||
m_statSplits++;
|
||||
++m_statSplits;
|
||||
} else {
|
||||
nodep->user1(true);
|
||||
}
|
||||
|
||||
+2
-2
@@ -304,12 +304,12 @@ private:
|
||||
if (debug()>5) nodep->dumpTree(cout," substw_old: ");
|
||||
AstNode* newp = substp->cloneTree(true);
|
||||
if (!nodep->isQuad() && newp->isQuad()) {
|
||||
newp = new AstCast (newp->fileline(), newp, nodep);
|
||||
newp = new AstCCast (newp->fileline(), newp, nodep);
|
||||
}
|
||||
if (debug()>5) newp->dumpTree(cout," w_new: ");
|
||||
nodep->replaceWith(newp);
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
m_statSubsts++;
|
||||
++m_statSubsts;
|
||||
}
|
||||
virtual void visit(AstWordSel* nodep, AstNUser*) {
|
||||
nodep->rhsp()->accept(*this);
|
||||
|
||||
+2
-2
@@ -176,8 +176,8 @@ public:
|
||||
private:
|
||||
void createTable(AstAlways* nodep) {
|
||||
// We've determined this table of nodes is optimizable, do it.
|
||||
m_modTables++;
|
||||
m_statTablesCre++;
|
||||
++m_modTables;
|
||||
++m_statTablesCre;
|
||||
|
||||
// Index into our table
|
||||
AstVar* indexVarp = new AstVar (nodep->fileline(), AstVarType::BLOCKTEMP,
|
||||
|
||||
+20
-5
@@ -408,6 +408,7 @@ private:
|
||||
AstAssign* assp = new AstAssign (pinp->fileline(),
|
||||
pinp,
|
||||
new AstVarRef(outvscp->fileline(), outvscp, false));
|
||||
assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); // Ok if in <= block
|
||||
// Put assignment BEHIND of all other statements
|
||||
beginp->addNext(assp);
|
||||
}
|
||||
@@ -418,6 +419,7 @@ private:
|
||||
AstAssign* assp = new AstAssign (pinp->fileline(),
|
||||
new AstVarRef(inVscp->fileline(), inVscp, true),
|
||||
pinp);
|
||||
assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); // Ok if in <= block
|
||||
// Put assignment in FRONT of all other statements
|
||||
if (AstNode* afterp = beginp->nextp()) {
|
||||
afterp->unlinkFrBackWithNext();
|
||||
@@ -507,6 +509,7 @@ private:
|
||||
AstAssign* assp = new AstAssign (pinp->fileline(),
|
||||
pinp,
|
||||
new AstVarRef(outvscp->fileline(), outvscp, false));
|
||||
assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); // Ok if in <= block
|
||||
// Put assignment BEHIND of all other statements
|
||||
beginp->addNext(assp);
|
||||
}
|
||||
@@ -587,8 +590,12 @@ private:
|
||||
// Someday we'll have better type support, and this can make variables and casts.
|
||||
// But for now, we'll just text-bash it.
|
||||
if (bitvec) {
|
||||
// We only support quads, so don't need to sweat longer stuff
|
||||
stmt += "VL_SET_WQ("+portp->name()+toSuffix+", "+portp->name()+frSuffix+")";
|
||||
if (portp->isWide()) {
|
||||
stmt += ("VL_SET_SVBV_W("+cvtToStr(portp->width())
|
||||
+", "+portp->name()+toSuffix+", "+portp->name()+frSuffix+")");
|
||||
} else {
|
||||
stmt += "VL_SET_WQ("+portp->name()+toSuffix+", "+portp->name()+frSuffix+")";
|
||||
}
|
||||
} else {
|
||||
if (isPtr) stmt += "*"; // DPI outputs are pointers
|
||||
stmt += portp->name()+toSuffix+" = ";
|
||||
@@ -605,7 +612,7 @@ private:
|
||||
return new AstCStmt(portp->fileline(), stmt);
|
||||
}
|
||||
|
||||
AstNode* createAssignDpiToInternal(AstVarScope* portvscp, const string& frName) {
|
||||
AstNode* createAssignDpiToInternal(AstVarScope* portvscp, const string& frName, bool cvt) {
|
||||
// Create assignment from DPI temporary into internal format
|
||||
AstVar* portp = portvscp->varp();
|
||||
string stmt;
|
||||
@@ -614,6 +621,14 @@ private:
|
||||
stmt += "VL_CVT_VP_Q(";
|
||||
ket += ")";
|
||||
}
|
||||
else if (portp->basicp() && portp->basicp()->isBitLogic() && portp->widthMin() != 1 && portp->isQuad()) {
|
||||
// SV is vector, Verilator isn't
|
||||
stmt += "VL_SET_QW(";
|
||||
ket += ")";
|
||||
}
|
||||
if (!cvt
|
||||
&& portp->basicp() && portp->basicp()->isBitLogic() && portp->widthMin() != 1 && !portp->isWide())
|
||||
stmt += "*"; // it's a svBitVecVal, which other code won't think is arrayed (as WData aren't), but really is
|
||||
stmt += frName;
|
||||
stmt += ket;
|
||||
// Use a AstCMath, as we want V3Clean to mask off bits that don't make sense.
|
||||
@@ -680,7 +695,7 @@ private:
|
||||
argnodesp = argnodesp->addNextNull(refp);
|
||||
|
||||
if (portp->isInput()) {
|
||||
dpip->addStmtsp(createAssignDpiToInternal(outvscp, portp->name()));
|
||||
dpip->addStmtsp(createAssignDpiToInternal(outvscp, portp->name(), false));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -795,7 +810,7 @@ private:
|
||||
if (AstVar* portp = stmtp->castVar()) {
|
||||
if (portp->isIO() && (portp->isOutput() || portp->isFuncReturn())) {
|
||||
AstVarScope* portvscp = portp->user2p()->castNode()->castVarScope(); // Remembered when we created it earlier
|
||||
cfuncp->addStmtsp(createAssignDpiToInternal(portvscp,portp->name()+"__Vcvt"));
|
||||
cfuncp->addStmtsp(createAssignDpiToInternal(portvscp,portp->name()+"__Vcvt",true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -71,19 +71,19 @@ class TraceActivityVertex : public V3GraphVertex {
|
||||
bool m_activityCodeValid;
|
||||
bool m_slow; // If always slow, we can use the same code
|
||||
public:
|
||||
enum { ACTIVITY_NEVER =((1UL<<31) - 1) };
|
||||
enum { ACTIVITY_ALWAYS=((1UL<<31) - 2) };
|
||||
enum { ACTIVITY_SLOW=0 };
|
||||
TraceActivityVertex(V3Graph* graphp, AstNode* nodep, bool slow)
|
||||
: V3GraphVertex(graphp), m_insertp(nodep) {
|
||||
m_activityCode = 0;
|
||||
m_activityCodeValid = false;
|
||||
m_slow = slow;
|
||||
}
|
||||
enum { ACTIVITY_NEVER =((1UL<<31) - 1) };
|
||||
enum { ACTIVITY_ALWAYS=((1UL<<31) - 2) };
|
||||
enum { ACTIVITY_SLOW=0 };
|
||||
class ActivityAlways {};
|
||||
TraceActivityVertex(V3Graph* graphp, vlsint32_t code)
|
||||
: V3GraphVertex(graphp) {
|
||||
activityCode(code);
|
||||
: V3GraphVertex(graphp), m_insertp(NULL) {
|
||||
m_activityCode = code;
|
||||
m_activityCodeValid = true;
|
||||
m_slow = false;
|
||||
}
|
||||
virtual ~TraceActivityVertex() {}
|
||||
@@ -484,7 +484,7 @@ private:
|
||||
nodep->code(m_code);
|
||||
m_code += nodep->codeInc();
|
||||
m_statUniqCodes += nodep->codeInc();
|
||||
m_statUniqSigs++;
|
||||
++m_statUniqSigs;
|
||||
}
|
||||
return nodep->code();
|
||||
}
|
||||
@@ -517,7 +517,7 @@ private:
|
||||
if (!codePreassigned) {
|
||||
// Add to trace cfuncs
|
||||
if (needChg) {
|
||||
m_statChgSigs++;
|
||||
++m_statChgSigs;
|
||||
incAddp = nodep->cloneTree(true);
|
||||
}
|
||||
|
||||
|
||||
+5
-4
@@ -75,8 +75,8 @@ private:
|
||||
if (prettyName.find("._") != string::npos)
|
||||
return "Inlined leading underscore";
|
||||
}
|
||||
if (nodep->width() > 256) return "Wide bus > 256 bits";
|
||||
if (nodep->arrayElements() > 32) return "Wide memory > 32 ents";
|
||||
if ((int)nodep->width() > v3Global.opt.traceMaxWidth()) return "Wide bus > --trace-max-width bits";
|
||||
if ((int)nodep->arrayElements() > v3Global.opt.traceMaxArray()) return "Wide memory > --trace-max-array ents";
|
||||
if (!(nodep->dtypeSkipRefp()->castBasicDType()
|
||||
|| (nodep->dtypeSkipRefp()->castArrayDType()
|
||||
&& nodep->dtypeSkipRefp()->castArrayDType()->dtypeSkipRefp()->castBasicDType()))) {
|
||||
@@ -103,6 +103,7 @@ private:
|
||||
} else {
|
||||
basep->v3fatalSrc("Strange base function type");
|
||||
}
|
||||
// cppcheck-suppress nullPointer // above fatal prevents it
|
||||
AstCCall* callp = new AstCCall(funcp->fileline(), funcp);
|
||||
callp->argTypes("vlSymsp, vcdp, code");
|
||||
basep->addStmtsp(callp);
|
||||
@@ -137,12 +138,12 @@ private:
|
||||
if (showname.substr(0,4) == "TOP ") showname.replace(0,4,"");
|
||||
if (!m_initSubFuncp) nodep->v3fatalSrc("NULL");
|
||||
if (varIgnoreTrace(varp)) {
|
||||
m_statIgnSigs++;
|
||||
++m_statIgnSigs;
|
||||
m_initSubFuncp->addStmtsp(
|
||||
new AstComment(nodep->fileline(),
|
||||
"Tracing: "+showname+" // Ignored: "+varIgnoreTrace(varp)));
|
||||
} else {
|
||||
m_statSigs++;
|
||||
++m_statSigs;
|
||||
AstNode* valuep = NULL;
|
||||
if (nodep->valuep()) valuep=nodep->valuep()->cloneTree(true);
|
||||
else valuep = new AstVarRef(nodep->fileline(), nodep, false);
|
||||
|
||||
+38
-7
@@ -159,8 +159,8 @@ private:
|
||||
// assign x = (OE) ? 'hz : y;
|
||||
|
||||
// see if this a COND and separate out the __en logic from the output logic if it is
|
||||
if (nodep->rhsp()->castCond()) {
|
||||
AstCond* condp = nodep->rhsp()->castCond();
|
||||
if (AstCond* condp = nodep->rhsp()->castCond()) {
|
||||
//if (debug()>=9) nodep->dumpTree(cout,"- cond-in: ");
|
||||
AstNode* oep = condp->condp();
|
||||
AstNode* expr1p = condp->expr1p();
|
||||
AstNode* expr2p = condp->expr2p();
|
||||
@@ -192,17 +192,44 @@ private:
|
||||
|
||||
// replace the old assign logic with the new one
|
||||
AstAssignW* newassp = new AstAssignW(nodep->fileline(), outp,outrhsp);
|
||||
//if (debug()>=9) newassp->dumpTreeAndNext(cout,"- cond-out: ");
|
||||
nodep->replaceWith(newassp);
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
newassp->iterateChildren(*this);
|
||||
|
||||
} else {
|
||||
}
|
||||
// How about a tri gate?
|
||||
else if (AstBufIf1* bufp = nodep->rhsp()->castBufIf1()) {
|
||||
//if (debug()>=9) nodep->dumpTree(cout,"- tri-in : ");
|
||||
AstNode* enrhsp = bufp->lhsp()->unlinkFrBack();
|
||||
AstNode* outrhsp = bufp->rhsp()->unlinkFrBack();
|
||||
|
||||
AstNode* outp = nodep->lhsp()->unlinkFrBack();;
|
||||
AstVarRef* outrefp = NULL;
|
||||
if (outp->castVarRef()) {
|
||||
outrefp = outp->castVarRef();
|
||||
} else if (outp->castSel()) {
|
||||
outrefp = outp->castSel()->fromp()->castVarRef();
|
||||
} else {
|
||||
nodep->v3error("Can't find LHS varref");
|
||||
}
|
||||
|
||||
createEnableVar(outp, outrefp, enrhsp, outrhsp->width());
|
||||
|
||||
// replace the old assign logic with the new one
|
||||
AstAssignW* newassp = new AstAssignW(nodep->fileline(), outp,outrhsp);
|
||||
//if (debug()>=9) newassp->dumpTreeAndNext(cout,"- tri-out: ");
|
||||
nodep->replaceWith(newassp);
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
newassp->iterateChildren(*this);
|
||||
}
|
||||
else {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
}
|
||||
|
||||
AstVar* createEnableVar(AstNode* outp, AstVarRef* outrefp, AstNode* enrhsp, int width, string suffix="") {
|
||||
// this function creates an __en Var that cooresponds to
|
||||
// this function creates an __en Var that corresponds to
|
||||
// the outp and outrefp and creates an assignw to enrhsp
|
||||
AstVar* enp = new AstVar (outrefp->varp()->fileline(),
|
||||
AstVarType::MODULETEMP,
|
||||
@@ -218,10 +245,14 @@ private:
|
||||
enrhsp->v3error("Don't know how to deal with selection logic wider than 1 bit");
|
||||
}
|
||||
}
|
||||
|
||||
AstNode* newassp = new AstAssignW (enp->fileline(),
|
||||
new AstVarRef (enp->fileline(), enp, true),
|
||||
enrhsp);
|
||||
if (debug()>=9) enp->dumpTreeAndNext(cout,"- cev-out: ");
|
||||
if (debug()>=9) newassp->dumpTreeAndNext(cout,"- cev-out: ");
|
||||
m_modp->addStmtp(enp);
|
||||
m_modp->addStmtp(new AstAssignW (enp->fileline(),
|
||||
new AstVarRef (enp->fileline(), enp, true),
|
||||
enrhsp));
|
||||
m_modp->addStmtp(newassp);
|
||||
|
||||
outrefp->user1p(enp); // put __en signal into varref for later usage
|
||||
outrefp->varp()->user1p(enp); // put __en signal into var as well in the event this is a single lhs driver and this needs passed up one level
|
||||
|
||||
+15
-4
@@ -76,8 +76,8 @@ public:
|
||||
private:
|
||||
// METHODS
|
||||
inline bool bitNumOk(int bit) const { return (bit*FLAGS_PER_BIT < (int)m_flags.size()); }
|
||||
inline bool usedFlag(int bit) { return m_usedWhole || m_flags[bit*FLAGS_PER_BIT + FLAG_USED]; }
|
||||
inline bool drivenFlag(int bit) { return m_drivenWhole || m_flags[bit*FLAGS_PER_BIT + FLAG_DRIVEN]; }
|
||||
inline bool usedFlag(int bit) const { return m_usedWhole || m_flags[bit*FLAGS_PER_BIT + FLAG_USED]; }
|
||||
inline bool drivenFlag(int bit) const { return m_drivenWhole || m_flags[bit*FLAGS_PER_BIT + FLAG_DRIVEN]; }
|
||||
enum BitNamesWhich { BN_UNUSED, BN_UNDRIVEN, BN_BOTH };
|
||||
string bitNames(BitNamesWhich which) {
|
||||
string bits="";
|
||||
@@ -217,6 +217,7 @@ private:
|
||||
// STATE
|
||||
vector<UndrivenVarEntry*> m_entryps; // Nodes to delete when we are finished
|
||||
bool m_markBoth; // Mark as driven+used
|
||||
AstNodeFTask* m_taskp; // Current task
|
||||
|
||||
// METHODS
|
||||
static int debug() {
|
||||
@@ -241,12 +242,14 @@ private:
|
||||
virtual void visit(AstVar* nodep, AstNUser*) {
|
||||
UndrivenVarEntry* entryp = getEntryp (nodep);
|
||||
if (nodep->isInput()
|
||||
|| nodep->isSigPublic() || nodep->isSigUserRWPublic()) {
|
||||
|| nodep->isSigPublic() || nodep->isSigUserRWPublic()
|
||||
|| (m_taskp && (m_taskp->dpiImport() || m_taskp->dpiExport()))) {
|
||||
entryp->drivenWhole();
|
||||
}
|
||||
if (nodep->isOutput()
|
||||
|| nodep->isSigPublic() || nodep->isSigUserRWPublic()
|
||||
|| nodep->isSigUserRdPublic()) {
|
||||
|| nodep->isSigUserRdPublic()
|
||||
|| (m_taskp && (m_taskp->dpiImport() || m_taskp->dpiExport()))) {
|
||||
entryp->usedWhole();
|
||||
}
|
||||
// Discover variables used in bit definitions, etc
|
||||
@@ -284,6 +287,13 @@ private:
|
||||
m_markBoth = prevMark;
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
||||
AstNodeFTask* prevTaskp = m_taskp;
|
||||
m_taskp = nodep;
|
||||
nodep->iterateChildren(*this);
|
||||
m_taskp = prevTaskp;
|
||||
}
|
||||
|
||||
// Until we support tables, primitives will have undriven and unused I/Os
|
||||
virtual void visit(AstPrimitive* nodep, AstNUser*) {}
|
||||
|
||||
@@ -303,6 +313,7 @@ public:
|
||||
// CONSTUCTORS
|
||||
UndrivenVisitor(AstNetlist* nodep) {
|
||||
m_markBoth = false;
|
||||
m_taskp = NULL;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~UndrivenVisitor() {
|
||||
|
||||
+1
-1
@@ -289,7 +289,7 @@ private:
|
||||
AstVar* newvarp
|
||||
= new AstVar (nodep->fileline(), AstVarType::XTEMP, newvarname,
|
||||
AstLogicPacked(), nodep->width());
|
||||
m_statUnkVars++;
|
||||
++m_statUnkVars;
|
||||
AstNRelinker replaceHandle;
|
||||
nodep->unlinkFrBack(&replaceHandle);
|
||||
AstNodeVarRef* newref1p = new AstVarRef(nodep->fileline(), newvarp, false);
|
||||
|
||||
+7
-3
@@ -187,8 +187,9 @@ private:
|
||||
UINFO(8," In Numbers: for (v="<<valInit<<"; v<"<<valStop<<"; v=v+"<<valInc<<")\n");
|
||||
//
|
||||
if (!m_generate) {
|
||||
UINFO(8, " ~Iters: "<<((valStop - valInit)/valInc)<<" c="<<unrollCount()<<endl);
|
||||
int loops = ((valStop - valInit)/valInc);
|
||||
if (loops < 0) { loops += (1ULL<<constStopp->width()); } // Will roll around
|
||||
UINFO(8, " ~Iters: "<<loops<<" c="<<unrollCount()<<endl);
|
||||
if (loops > unrollCount())
|
||||
return cantUnroll(nodep, "too many iterations");
|
||||
|
||||
@@ -240,14 +241,17 @@ private:
|
||||
}
|
||||
if (precondsp) {
|
||||
precondsp->unlinkFrBackWithNext();
|
||||
// cppcheck-suppress nullPointer // addNextNull deals with it
|
||||
stmtsp = stmtsp->addNextNull(precondsp);
|
||||
}
|
||||
if (bodysp) {
|
||||
bodysp->unlinkFrBackWithNext();
|
||||
// cppcheck-suppress nullPointer // addNextNull deals with it
|
||||
stmtsp = stmtsp->addNextNull(bodysp); // Maybe null if no body
|
||||
}
|
||||
if (incp && !nodep->castGenFor()) { // Generates don't need to increment loop index
|
||||
incp->unlinkFrBackWithNext();
|
||||
// cppcheck-suppress nullPointer // addNextNull deals with it
|
||||
stmtsp = stmtsp->addNextNull(incp); // Maybe null if no body
|
||||
}
|
||||
// Mark variable to disable some later warnings
|
||||
@@ -258,7 +262,7 @@ private:
|
||||
loopValue.opAssign(numInit);
|
||||
|
||||
AstNode* newbodysp = NULL;
|
||||
m_statLoops++;
|
||||
++m_statLoops;
|
||||
if (stmtsp) {
|
||||
int times = 0;
|
||||
while (1) {
|
||||
@@ -286,7 +290,7 @@ private:
|
||||
if (newbodysp) newbodysp->addNext(oneloopp);
|
||||
else newbodysp = oneloopp;
|
||||
|
||||
m_statIters++;
|
||||
++m_statIters;
|
||||
if (++times > unrollCount()*3) {
|
||||
nodep->v3error("Loop unrolling took too long; probably this is an infinite loop, or set --unroll-count above "<<unrollCount());
|
||||
break;
|
||||
|
||||
+1107
-546
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user