'Merge from master for release.'

This commit is contained in:
Wilson Snyder 2020-07-11 09:16:56 -04:00
commit dd03d0f3c9
291 changed files with 7528 additions and 3829 deletions

View File

@ -41,12 +41,21 @@ install:
before_script:
# ccache maintenance
- ./ci/travis-ccache-maint.bash
# Don't produce core dumps (esp. on FreeBSD)
- ulimit -c 0
# On Focal, set the SystemC installation location
- |
if [ "$TRAVIS_DIST" = "focal" ]; then
if [ "$TRAVIS_DIST" = "focal" ] && [ "$M32" != "1" ]; then
export SYSTEMC_INCLUDE=/usr/include
export SYSTEMC_LIBDIR=/usr/lib/x86_64-linux-gnu
fi
# Override compiler for M32
- |
if [ "$M32" = "1" ]; then
export CC="$CC -m32"
export CXX="$CXX -m32"
unset M32 # verilated.mk actually references $(M32) so unset
fi
before_cache:
- ccache -s -z
@ -70,6 +79,12 @@ jobs:
- {stage: build, os: linux, dist: focal, compiler: clang, workspaces: {create: {name: focal-clang, paths: .}}}
# Coverage build
- {stage: build, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {create: {name: coverage, paths: .}}, env: COVERAGE=1}
# 32-bit build
- {stage: build, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {create: {name: focal-gcc-m32, paths: .}}, env: M32=1}
# OS X build
- {stage: build, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {create: {name: osx-xcode11.6, paths: .}}}
# FreeBSD build
- {stage: build, if: type = cron, os: freebsd, compiler: clang, workspaces: {create: {name: freebsd, paths: .}}}
############################################################################
# Jobs in the 'test' stage
############################################################################
@ -109,6 +124,21 @@ jobs:
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-1}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-2}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-3}
# 32-bit tests
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=dist-vlt-0]}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=dist-vlt-1]}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=vltmt-0]}
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=vltmt-1]}
# OS X tests
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=dist-vlt-0}
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=dist-vlt-1}
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=vltmt-0}
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=vltmt-1}
# FreeBSD tests
- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-0}
- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-1}
- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-0}
- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-1}
notifications:
email:

28
Changes
View File

@ -3,6 +3,34 @@ Revision history for Verilator
The contributors that suggested a given feature are shown in []. Thanks!
* Verilator 4.038 2020-07-11
** Versions 4.038 and 4.040 are planned to be the final versions that will
support pre-C++11 compilers. Please move to C++11 or newer compilers.
*** Support VPI access to parameters and localparam. [Ludwig Rogiers]
*** Support parsing (not elaboration, yet) of UVM.
**** Add new UNSUPPORTED error code to replace most previous Unsupported: messages.
**** With --bbox-unsup continue parsing on many (not all) UVM constructs.
**** Support for-loop increments with commas.
**** Support $swrite with arbitrary arguments.
**** Support $writememb (#2450). [Fan Shupei]
**** Fix OS X, Free BSD, and -m32 portability issues. [Geza Lore]
**** Fix to flush FST trace on termination due to $stop or assertion failure.
**** Fix part select error when multipling by power-of-two (#2413). [Conor McCullough]
**** Fix division exception (#2460) [Kuoping Hsu]
* Verilator 4.036 2020-06-06
** OPT_FAST is now -Os by default. See the BENCHMARKING & OPTIMIZATION part

View File

@ -425,6 +425,9 @@ CPPCHECK_CPP = $(wildcard \
CPPCHECK_H = $(wildcard \
$(srcdir)/include/*.h \
$(srcdir)/src/*.h )
CPPCHECK_YL = $(wildcard \
$(srcdir)/src/*.y \
$(srcdir)/src/*.l )
CPPCHECK = src/cppcheck_filtered
CPPCHECK_FLAGS = --enable=all --inline-suppr \
--suppress=unusedScopedObject --suppress=cstyleCast --suppress=useInitializationList \
@ -462,7 +465,7 @@ CLANGFORMAT_FLAGS = -i
clang-format:
@$(CLANGFORMAT) --version | egrep 10.0 > /dev/null \
|| echo "*** You are not using clang-format 10.0, indents may differ from master's ***"
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CPPCHECK_CPP) $(CPPCHECK_H)
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL)
ftp: info

File diff suppressed because it is too large Load Diff

View File

@ -25,11 +25,21 @@ fatal() {
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
}
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
MAKE=make
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
MAKE=make
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
MAKE=gmake
else
fatal "Unknown os: '$TRAVIS_OS_NAME'"
fi
install-vcddiff() {
TMP_DIR="$(mktemp -d)"
git clone https://github.com/veripool/vcddiff "$TMP_DIR"
git -C "${TMP_DIR}" checkout 5112f88b7ba8818dce9dfb72619e64a1fc19542c
make -C "${TMP_DIR}"
"$MAKE" -C "${TMP_DIR}"
sudo cp "${TMP_DIR}/vcddiff" /usr/local/bin
}
@ -39,12 +49,20 @@ if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then
# build Verilator
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
time sudo apt-get update
sudo apt-get update
sudo apt-get install libfl-dev
sudo apt-get install libgoogle-perftools-dev
if [ "$COVERAGE" = 1 ]; then
yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
fi
if [ "$M32" = 1 ]; then
sudo apt-get install gcc-multilib g++-multilib
fi
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
brew update
brew install ccache perl gperftools
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
sudo pkg install -y autoconf bison ccache gmake perl5
else
fatal "Unknown os: '$TRAVIS_OS_NAME'"
fi
@ -59,9 +77,23 @@ elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
if [ "$TRAVIS_DIST" = "focal" ]; then
sudo apt-get install libsystemc-dev
fi
if [ "$M32" = 1 ]; then
sudo apt-get install lib32z1-dev gcc-multilib g++-multilib
fi
yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
# Not listing Bit::Vector as slow to install, and only skips one test
install-vcddiff
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
brew update
# brew cask install gtkwave # fst2vcd hangs at launch, so don't bother
brew install ccache perl
yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
install-vcddiff
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
# fst2vcd fails with "Could not open '<input file>', exiting."
sudo pkg install -y ccache gmake perl5 python3
yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
install-vcddiff
else
fatal "Unknown os: '$TRAVIS_OS_NAME'"
fi

View File

@ -22,77 +22,110 @@ fatal() {
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
}
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
export MAKE=make
NPROC=$(nproc)
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
export MAKE=make
NPROC=$(sysctl -n hw.logicalcpu)
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
export MAKE=gmake
NPROC=$(sysctl -n hw.ncpu)
else
fatal "Unknown os: '$TRAVIS_OS_NAME'"
fi
if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then
##############################################################################
# Build verilator
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
if [ "$COVERAGE" != 1 ]; then
autoconf
./configure --enable-longtests --enable-ccwarn
make -j $(nproc)
else
nodist/code_coverage --stages 1-2
if [ "$COVERAGE" != 1 ]; then
autoconf
./configure --enable-longtests --enable-ccwarn
"$MAKE" -j "$NPROC"
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
file bin/verilator_bin
file bin/verilator_bin_dbg
md5 bin/verilator_bin
md5 bin/verilator_bin_dbg
stat bin/verilator_bin
stat bin/verilator_bin_dbg
fi
else
fatal "Unknown os: '$TRAVIS_OS_NAME'"
nodist/code_coverage --stages 1-2
fi
elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
##############################################################################
# Run tests
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
# Run the specified test
case $TESTS in
dist-vlt-0)
make -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=0/2
;;
dist-vlt-1)
make -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=1/2
;;
vltmt-0)
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2
;;
vltmt-1)
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2
;;
coverage-dist)
nodist/code_coverage --stages 3- --scenarios=--dist
;;
coverage-vlt-0)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=0/4
;;
coverage-vlt-1)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=1/4
;;
coverage-vlt-2)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=2/4
;;
coverage-vlt-3)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=3/4
;;
coverage-vltmt-0)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=0/4
;;
coverage-vltmt-1)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=1/4
;;
coverage-vltmt-2)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=2/4
;;
coverage-vltmt-3)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=3/4
;;
*)
fatal "Unknown test: $TESTS"
;;
esac
# Upload coverage data to codecov.io
if [[ $TESTS == coverage-* ]]; then
bash <(curl -s https://codecov.io/bash) -f nodist/obj_dir/coverage/app_total.info
fi
else
fatal "Unknown os: '$TRAVIS_OS_NAME'"
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
export VERILATOR_TEST_NO_GDB=1 # Pain to get GDB to work on OS X
export VERILATOR_TEST_NO_GPROF=1 # Apple Clang has no -pg
# export PATH="/Applications/gtkwave.app/Contents/Resources/bin:$PATH" # fst2vcd
file bin/verilator_bin
file bin/verilator_bin_dbg
md5 bin/verilator_bin
md5 bin/verilator_bin_dbg
stat bin/verilator_bin
stat bin/verilator_bin_dbg
# For some reason, the dbg exe is corrupted by this point ('file' reports
# it as data rather than a Mach-O). Unclear if this is an OS X issue or
# one for Travis. Remove the file and re-link...
rm bin/verilator_bin_dbg
"$MAKE" -j "$NPROC"
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
export VERILATOR_TEST_NO_GDB=1 # Disable for now, ideally should run
export VERILATOR_TEST_NO_GPROF=1 # gprof is a bit different on FreeBSD, disable
fi
# Run the specified test
case $TESTS in
dist-vlt-0)
"$MAKE" -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=0/2
;;
dist-vlt-1)
"$MAKE" -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=1/2
;;
vltmt-0)
"$MAKE" -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2
;;
vltmt-1)
"$MAKE" -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2
;;
coverage-dist)
nodist/code_coverage --stages 3- --scenarios=--dist
;;
coverage-vlt-0)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=0/4
;;
coverage-vlt-1)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=1/4
;;
coverage-vlt-2)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=2/4
;;
coverage-vlt-3)
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=3/4
;;
coverage-vltmt-0)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=0/4
;;
coverage-vltmt-1)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=1/4
;;
coverage-vltmt-2)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=2/4
;;
coverage-vltmt-3)
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=3/4
;;
*)
fatal "Unknown test: $TESTS"
;;
esac
# Upload coverage data to codecov.io
if [[ $TESTS == coverage-* ]]; then
bash <(curl -s https://codecov.io/bash) -f nodist/obj_dir/coverage/app_total.info
fi
else
##############################################################################

View File

@ -7,7 +7,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[4.036 2020-06-06],
AC_INIT([Verilator],[4.038 2020-07-11],
[https://verilator.org],
[verilator],[https://verilator.org])
# When releasing, also update header of Changes file
@ -114,25 +114,25 @@ AC_MSG_RESULT($CFG_WITH_LONGTESTS)
# CFG_WITH_PREC11
AC_MSG_CHECKING(whether allow pre-C++11)
AC_ARG_ENABLE([prec11],
[AS_HELP_STRING([--enable-prec11],
AC_ARG_ENABLE([prec11-final],
[AS_HELP_STRING([--enable-prec11-final],
[enable pre-C++11 compilers for Verilator binary
and Verilated makefiles])],
[case "${enableval}" in
yes) CFG_WITH_PREC11=yes ;;
no) CFG_WITH_PREC11=no ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-prec11]) ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-prec11-final]) ;;
esac],
[CFG_WITH_PREC11=no;]
)
AC_SUBST(CFG_WITH_PREC11)
AC_MSG_RESULT($CFG_WITH_PREC11)
# Compiler flags
CFLAGS+=" -I${includedir}"
CPPFLAGS+=" -I${includedir}"
CXXFLAGS+=" -I${includedir}"
LDFLAGS+=" -L${libdir}"
# Compiler flags (ensure they are not empty to avoid configure defaults)
CFLAGS+=" "
CPPFLAGS+=" "
CXXFLAGS+=" "
LDFLAGS+=" "
# Checks for programs.
AC_PROG_CC
@ -153,14 +153,20 @@ AC_PATH_PROG(PERL,perl)
if test "x$PERL" = "x" ; then
AC_MSG_ERROR([Cannot find "perl" in your PATH, please install it])
fi
AC_PATH_PROG(LEX,flex)
if test "x$LEX" = "x" ; then
AC_MSG_ERROR([Cannot find "flex" in your PATH, please install it])
fi
flex_version=$($LEX --version | head -1)
AC_MSG_RESULT([$LEX --version = $flex_version])
AC_PATH_PROG(YACC,bison)
if test "x$YACC" = "x" ; then
AC_MSG_ERROR([Cannot find "bison" in your PATH, please install it])
fi
bison_version=$($YACC --version | head -1)
AC_MSG_RESULT([$YACC --version = $bison_version])
AC_CHECK_PROG(OBJCACHE,ccache,ccache)
if test "x$OBJCACHE" != "x" ; then
@ -427,12 +433,11 @@ if test "$CFG_WITH_THREADED" = "no" ; then
AC_MSG_NOTICE([[]])
AC_MSG_ERROR([[the $CXX compiler appears to not support C++11.
Verilator plans to require a C++11 or newer compiler in a future release,
unless sufficient people report problems. Therefore, if you do not have a
C++11 compiler, please post a message to
https://www.veripool.org/boards/3/topics/2580-Verilator-Requiring-C-11-compiler
indicating your OS and when you think C++11 might be ok, and then rerun
configure with the --enable-prec11 argument. Thanks.]])
Verilator will require a C++11 or newer compiler for all releases starting
September 2020. Please investigate a C++11 build environment now so you
will be ready. Until then you may rerun configure with the
--enable-prec11-final argument to enable reduced functionality with such
older compilers. Thanks.]])
fi
fi
@ -447,14 +452,18 @@ AC_CHECK_MEMBER([struct stat.st_mtim.tv_nsec],
# - If not found or not system-wide, user can set SYSTEMC_INCLUDE.
# AC_CHECK_HEADERS seems to not locate on Travis-CI but include does work.
AC_MSG_CHECKING([whether SystemC is found (in system path)])
AC_COMPILE_IFELSE(
ACO_SAVE_LIBS="$LIBS"
LIBS="$LIBS -lsystemc"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[#include <systemc.h>
]],[])],
extern "C" int sc_main(int argc, char* argv[]) {}
]],[[sc_version()]])],
[_my_result=yes
AC_DEFINE([HAVE_SYSTEMC_H],[1],[Defined if have systemc.h])],
AC_DEFINE([HAVE_SYSTEMC],[1],[Defined if have SystemC library])],
[_my_result=no])
AC_MSG_RESULT($_my_result)
AC_SUBST(HAVE_SYSTEMC_H)
LIBS="$ACO_SAVE_LIBS"
AC_SUBST(HAVE_SYSTEMC)
# Checks for system services

View File

@ -6,15 +6,18 @@ Please see the Verilator manual for 200+ additional contributors. Thanks to all.
Ahmed El-Mahmoudy
Alex Chadwick
Chris Randall
Conor McCullough
Dan Petrisko
David Horton
David Stanford
Driss Hafdi
Eric Rippey
Fan Shupei
Garrett Smith
Geza Lore
Gianfranco Costamagna
Glen Gibb
Harald Heckmann
Howard Su
Huang Rui
Iztok Jeras

View File

@ -39,7 +39,7 @@ brief:
#sudo apt-get install libfl2 # Ubuntu only (ignore if gives error)
#sudo apt-get install libfl-dev # Ubuntu only (ignore if gives error)
git clone https://git.veripool.org/git/verilator # Only first time
git clone https://github.com/verilator/verilator # Only first time
## Note the URL above is not a page you can see with a browser, it's for git only
# Every time you need to build:
@ -89,7 +89,7 @@ To build or run the following are optional but should be installed for
good performance:
sudo apt-get install ccache # If present at build, needed for run
sudo apt-get install libgoogle-perftools-dev numactl
sudo apt-get install libgoogle-perftools-dev numactl perl-doc
To build Verilator you will need to install these packages; these do not
need to be present to run Verilator:
@ -128,7 +128,7 @@ Downloads]; we presume you know how to use it, and is not described here.)
Get the sources from the repository: (You need do this only once, ever.)
git clone https://git.veripool.org/git/verilator # Only first time
git clone https://github.com/verilator/verilator # Only first time
## Note the URL above is not a page you can see with a browser, it's for git only
Enter the checkout and determine what version/branch to use:

View File

@ -777,9 +777,10 @@ output, for example:
You can then print a.ps. You may prefer gif format, which doesn't get
scaled so can be more useful with large graphs.
For dynamic graph viewing consider
For interactive graph viewing consider
https://github.com/jrfonseca/xdot.py[xdot] or
http://zvtm.sourceforge.net/zgrviewer.html[ZGRViewer]. If you know of
better viewers let us know; ZGRViewer isn't great for large graphs.
better viewers (especially for large graphs) please let us know.
=== .tree Output

View File

@ -68,7 +68,7 @@ run:
@echo " library (libverilated_secret.a) generated from the previous"
@echo " step"
@echo "---------------------------------------------------------------"
$(VERILATOR) $(TOP_VERILATOR_FLAGS) --exe -LDFLAGS '-L../obj_dir_secret -lverilated_secret -static' top.v obj_dir_secret/verilated_secret.sv sim_main.cpp
$(VERILATOR) $(TOP_VERILATOR_FLAGS) --exe -LDFLAGS '../obj_dir_secret/libverilated_secret.a' top.v obj_dir_secret/verilated_secret.sv sim_main.cpp
@echo
@echo "-- COMPILE entire design --------------------------------------"

View File

@ -3,7 +3,7 @@
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix). */
#if !defined(__MINGW32__)
#if !defined(__MINGW32__) && !defined(__FreeBSD__)
# define HAVE_ALLOCA_H 1
#endif

View File

@ -794,6 +794,7 @@ pthread_t thread;
pthread_attr_t thread_attr;
struct fstWriterContext *xc_parent;
#endif
unsigned in_pthread : 1;
size_t fst_orig_break_size;
size_t fst_orig_break_add_size;
@ -1806,10 +1807,9 @@ static void *fstWriterFlushContextPrivate1(void *ctx)
{
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
pthread_mutex_lock(&(xc->xc_parent->mutex));
fstWriterFlushContextPrivate2(xc);
pthread_mutex_unlock(&(xc->xc_parent->mutex));
#ifdef FST_REMOVE_DUPLICATE_VC
free(xc->curval_mem);
#endif
@ -1818,6 +1818,9 @@ free(xc->vchg_mem);
tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam);
free(xc);
xc->xc_parent->in_pthread = 0;
pthread_mutex_unlock(&(xc->xc_parent->mutex));
return(NULL);
}
@ -1865,7 +1868,15 @@ if(xc->parallel_enabled)
xc->section_header_only = 0;
xc->secnum++;
while (xc->in_pthread)
{
pthread_mutex_lock(&xc->mutex);
pthread_mutex_unlock(&xc->mutex);
};
pthread_mutex_lock(&xc->mutex);
xc->in_pthread = 1;
pthread_mutex_unlock(&xc->mutex);
pthread_create(&xc->thread, &xc->thread_attr, fstWriterFlushContextPrivate1, xc2);
}
@ -1947,6 +1958,12 @@ if(xc && !xc->already_in_close && !xc->already_in_flush)
#ifdef FST_WRITER_PARALLEL
pthread_mutex_lock(&xc->mutex);
pthread_mutex_unlock(&xc->mutex);
while (xc->in_pthread)
{
pthread_mutex_lock(&xc->mutex);
pthread_mutex_unlock(&xc->mutex);
};
#endif
}
}

View File

@ -31,6 +31,8 @@
#include <cerrno>
#include <sstream>
#include <sys/stat.h> // mkdir
#include <list>
#include <utility>
// clang-format off
#if defined(_WIN32) || defined(__MINGW32__)
@ -59,7 +61,6 @@ typedef union {
// Slow path variables
VerilatedMutex Verilated::m_mutex;
VerilatedVoidCb Verilated::s_flushCb = NULL;
// Keep below together in one cache line
Verilated::Serialized Verilated::s_s;
@ -83,7 +84,8 @@ void vl_finish(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE
if (Verilated::gotFinish()) {
VL_PRINTF( // Not VL_PRINTF_MT, already on main thread
"- %s:%d: Second verilog $finish, exiting\n", filename, linenum);
Verilated::flushCall();
Verilated::runFlushCallbacks();
Verilated::runExitCallbacks();
exit(0);
}
Verilated::gotFinish(true);
@ -93,7 +95,7 @@ void vl_finish(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE
#ifndef VL_USER_STOP ///< Define this to override this function
void vl_stop(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE {
Verilated::gotFinish(true);
Verilated::flushCall();
Verilated::runFlushCallbacks();
vl_fatal(filename, linenum, hier, "Verilog $stop");
}
#endif
@ -108,10 +110,15 @@ void vl_fatal(const char* filename, int linenum, const char* hier, const char* m
} else {
VL_PRINTF("%%Error: %s\n", msg);
}
Verilated::flushCall();
Verilated::runFlushCallbacks();
VL_PRINTF("Aborting...\n"); // Not VL_PRINTF_MT, already on main thread
Verilated::flushCall(); // Second flush in case VL_PRINTF does something needing a flush
// Second flush in case VL_PRINTF does something needing a flush
Verilated::runFlushCallbacks();
// Callbacks prior to termination
Verilated::runExitCallbacks();
abort();
}
#endif
@ -1700,7 +1707,7 @@ const char* vl_dumpctl_filenamep(bool setit, const std::string& filename) VL_MT_
static const char* memhFormat(int nBits) {
assert((nBits >= 1) && (nBits <= 32));
static char buf[32];
static VL_THREAD_LOCAL char buf[32];
switch ((nBits - 1) / 4) {
case 0: VL_SNPRINTF(buf, 32, "%%01x"); break;
case 1: VL_SNPRINTF(buf, 32, "%%02x"); break;
@ -1715,6 +1722,18 @@ static const char* memhFormat(int nBits) {
return buf;
}
static const char* formatBinary(int nBits, vluint32_t bits) {
assert((nBits >= 1) && (nBits <= 32));
static VL_THREAD_LOCAL char buf[64];
for (int i = 0; i < nBits; i++) {
bool isOne = bits & (1 << (nBits - 1 - i));
buf[i] = (isOne ? '1' : '0');
}
buf[nBits] = '\0';
return buf;
}
VlReadMem::VlReadMem(bool hex, int bits, const std::string& filename, QData start, QData end)
: m_hex(hex)
, m_bits(bits)
@ -1852,14 +1871,9 @@ void VlReadMem::setData(void* valuep, const std::string& rhs) {
}
VlWriteMem::VlWriteMem(bool hex, int bits, const std::string& filename, QData start, QData end)
: m_bits(bits)
: m_hex(hex)
, m_bits(bits)
, m_addr(0) {
if (VL_UNLIKELY(!hex)) {
VL_FATAL_MT(filename.c_str(), 0, "",
"Unsupported: $writemem binary format (suggest hex format)");
return;
}
if (VL_UNLIKELY(start > end)) {
VL_FATAL_MT(filename.c_str(), 0, "", "$writemem invalid address range");
return;
@ -1886,23 +1900,40 @@ void VlWriteMem::print(QData addr, bool addrstamp, const void* valuep) {
m_addr = addr + 1;
if (m_bits <= 8) {
const CData* datap = reinterpret_cast<const CData*>(valuep);
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
fprintf(m_fp, "\n");
if (m_hex) {
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
fprintf(m_fp, "\n");
} else {
fprintf(m_fp, "%s\n", formatBinary(m_bits, *datap));
}
} else if (m_bits <= 16) {
const SData* datap = reinterpret_cast<const SData*>(valuep);
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
fprintf(m_fp, "\n");
if (m_hex) {
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
fprintf(m_fp, "\n");
} else {
fprintf(m_fp, "%s\n", formatBinary(m_bits, *datap));
}
} else if (m_bits <= 32) {
const IData* datap = reinterpret_cast<const IData*>(valuep);
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
fprintf(m_fp, "\n");
if (m_hex) {
fprintf(m_fp, memhFormat(m_bits), VL_MASK_I(m_bits) & *datap);
fprintf(m_fp, "\n");
} else {
fprintf(m_fp, "%s\n", formatBinary(m_bits, *datap));
}
} else if (m_bits <= 64) {
const QData* datap = reinterpret_cast<const QData*>(valuep);
vluint64_t value = VL_MASK_Q(m_bits) & *datap;
vluint32_t lo = value & 0xffffffff;
vluint32_t hi = value >> 32;
fprintf(m_fp, memhFormat(m_bits - 32), hi);
fprintf(m_fp, "%08x\n", lo);
if (m_hex) {
fprintf(m_fp, memhFormat(m_bits - 32), hi);
fprintf(m_fp, "%08x\n", lo);
} else {
fprintf(m_fp, "%s", formatBinary(m_bits - 32, hi));
fprintf(m_fp, "%s\n", formatBinary(32, lo));
}
} else {
WDataInP datap = reinterpret_cast<WDataInP>(valuep);
// output as a sequence of VL_EDATASIZE'd words
@ -1915,9 +1946,17 @@ void VlWriteMem::print(QData addr, bool addrstamp, const void* valuep) {
if (first) {
data &= VL_MASK_E(m_bits);
int top_word_nbits = VL_BITBIT_E(m_bits - 1) + 1;
fprintf(m_fp, memhFormat(top_word_nbits), data);
if (m_hex) {
fprintf(m_fp, memhFormat(top_word_nbits), data);
} else {
fprintf(m_fp, "%s", formatBinary(top_word_nbits, data));
}
} else {
fprintf(m_fp, "%08x", data);
if (m_hex) {
fprintf(m_fp, "%08x", data);
} else {
fprintf(m_fp, "%s", formatBinary(32, data));
}
}
word_idx--;
first = false;
@ -2242,29 +2281,60 @@ const char* Verilated::catName(const char* n1, const char* n2, const char* delim
return strp;
}
void Verilated::flushCb(VerilatedVoidCb cb) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
if (s_flushCb == cb) { // Ok - don't duplicate
} else if (!s_flushCb) {
s_flushCb = cb;
} else { // LCOV_EXCL_LINE
// Someday we may allow multiple callbacks ala atexit(), but until then
VL_FATAL_MT("unknown", 0, "", // LCOV_EXCL_LINE
"Verilated::flushCb called twice with different callbacks");
}
//=========================================================================
// Flush and exit callbacks
// Keeping these out of class Verilated to avoid having to include <list>
// in verilated.h (for compilation speed)
typedef std::list<std::pair<Verilated::VoidPCb, void*> > VoidPCbList;
static VoidPCbList g_flushCbs;
static VoidPCbList g_exitCbs;
static void addCb(Verilated::VoidPCb cb, void* datap, VoidPCbList& cbs) {
std::pair<Verilated::VoidPCb, void*> pair(cb, datap);
cbs.remove(pair); // Just in case it's a duplicate
cbs.push_back(pair);
}
static void removeCb(Verilated::VoidPCb cb, void* datap, VoidPCbList& cbs) {
std::pair<Verilated::VoidPCb, void*> pair(cb, datap);
cbs.remove(pair);
}
static void runCallbacks(VoidPCbList& cbs) VL_MT_SAFE {
for (VoidPCbList::iterator it = cbs.begin(); it != cbs.end(); ++it) { it->first(it->second); }
}
// When running internal code coverage (gcc --coverage, as opposed to
// verilator --coverage), dump coverage data to properly cover failing
// tests.
void Verilated::flushCall() VL_MT_SAFE {
void Verilated::addFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
if (s_flushCb) (*s_flushCb)();
addCb(cb, datap, g_flushCbs);
}
void Verilated::removeFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
removeCb(cb, datap, g_flushCbs);
}
void Verilated::runFlushCallbacks() VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
runCallbacks(g_flushCbs);
fflush(stderr);
fflush(stdout);
// When running internal code coverage (gcc --coverage, as opposed to
// verilator --coverage), dump coverage data to properly cover failing
// tests.
VL_GCOV_FLUSH();
}
void Verilated::addExitCb(VoidPCb cb, void* datap) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
addCb(cb, datap, g_exitCbs);
}
void Verilated::removeExitCb(VoidPCb cb, void* datap) VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
removeCb(cb, datap, g_exitCbs);
}
void Verilated::runExitCallbacks() VL_MT_SAFE {
const VerilatedLockGuard lock(m_mutex);
runCallbacks(g_exitCbs);
}
const char* Verilated::productName() VL_PURE { return VERILATOR_PRODUCT; }
const char* Verilated::productVersion() VL_PURE { return VERILATOR_VERSION; }
@ -2565,7 +2635,7 @@ void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) VL_
}
}
void VerilatedScope::varInsert(int finalize, const char* namep, void* datap,
void VerilatedScope::varInsert(int finalize, const char* namep, void* datap, bool isParam,
VerilatedVarType vltype, int vlflags, int dims, ...) VL_MT_UNSAFE {
// Grab dimensions
// In the future we may just create a large table at emit time and
@ -2573,7 +2643,7 @@ void VerilatedScope::varInsert(int finalize, const char* namep, void* datap,
if (!finalize) return;
if (!m_varsp) m_varsp = new VerilatedVarNameMap();
VerilatedVar var(namep, datap, vltype, static_cast<VerilatedVarFlags>(vlflags), dims);
VerilatedVar var(namep, datap, vltype, static_cast<VerilatedVarFlags>(vlflags), dims, isParam);
va_list ap;
va_start(ap, dims);

View File

@ -84,10 +84,6 @@ typedef EData WData; ///< Verilated pack data, >64 bits, as an array
typedef const WData* WDataInP; ///< Array input to a function
typedef WData* WDataOutP; ///< Array output from a function
typedef void (*VerilatedVoidCb)(void);
class SpTraceVcd;
class SpTraceVcdCFile;
class VerilatedEvalMsgQueue;
class VerilatedScopeNameMap;
class VerilatedVar;
@ -339,8 +335,8 @@ public: // But internals only - called from VerilatedModule's
void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp,
const char* identifier, vlsint8_t timeunit, const Type& type) VL_MT_UNSAFE;
void exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE;
void varInsert(int finalize, const char* namep, void* datap, VerilatedVarType vltype,
int vlflags, int dims, ...) VL_MT_UNSAFE;
void varInsert(int finalize, const char* namep, void* datap, bool isParam,
VerilatedVarType vltype, int vlflags, int dims, ...) VL_MT_UNSAFE;
// ACCESSORS
const char* name() const { return m_namep; }
const char* identifier() const { return m_identifierp; }
@ -376,8 +372,6 @@ class Verilated {
// Slow path variables
static VerilatedMutex m_mutex; ///< Mutex for s_s/s_ns members, when VL_THREADED
static VerilatedVoidCb s_flushCb; ///< Flush callback function
static struct Serialized { // All these members serialized/deserialized
// Fast path
int s_debug; ///< See accessors... only when VL_DEBUG set
@ -501,9 +495,15 @@ public:
static void profThreadsFilenamep(const char* flagp) VL_MT_SAFE;
static const char* profThreadsFilenamep() VL_MT_SAFE { return s_ns.s_profThreadsFilenamep; }
/// Flush callback for VCD waves
static void flushCb(VerilatedVoidCb cb) VL_MT_SAFE;
static void flushCall() VL_MT_SAFE;
typedef void (*VoidPCb)(void*); // Callback type for below
/// Callbacks to run on global flush
static void addFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE;
static void removeFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE;
static void runFlushCallbacks() VL_MT_SAFE;
/// Callbacks to run prior to termination
static void addExitCb(VoidPCb cb, void* datap) VL_MT_SAFE;
static void removeExitCb(VoidPCb cb, void* datap) VL_MT_SAFE;
static void runExitCallbacks() VL_MT_SAFE;
/// Record command line arguments, for retrieval by $test$plusargs/$value$plusargs,
/// and for parsing +verilator+ run-time arguments.
@ -843,7 +843,7 @@ inline vluint64_t vl_time_stamp64() { return static_cast<vluint64_t>(sc_time_sta
// Optimized assuming scale is always constant.
// Can't use multiply in Q flavor, as might lose precision
#define VL_TIME_UNITED_Q(scale) (VL_TIME_Q() / static_cast<QData>(scale))
#define VL_TIME_UNITED_D(scale) (VL_TIME_D() * (1.0 / (scale)))
#define VL_TIME_UNITED_D(scale) (VL_TIME_D() / static_cast<double>(scale))
/// Time imported from units to time precision
double vl_time_multiplier(int scale);
@ -1571,24 +1571,30 @@ static inline WDataOutP VL_MULS_WWW(int, int lbits, int, WDataOutP owp, WDataInP
static inline IData VL_DIVS_III(int lbits, IData lhs, IData rhs) VL_PURE {
if (VL_UNLIKELY(rhs == 0)) return 0;
// -MAX / -1 cannot be represented in twos complement, and will cause SIGFPE
if (VL_UNLIKELY(lhs == 0x80000000 && rhs == 0xffffffff)) return 0;
vlsint32_t lhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, lhs);
vlsint32_t rhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, rhs);
return lhs_signed / rhs_signed;
}
static inline QData VL_DIVS_QQQ(int lbits, QData lhs, QData rhs) VL_PURE {
if (VL_UNLIKELY(rhs == 0)) return 0;
// -MAX / -1 cannot be represented in twos complement, and will cause SIGFPE
if (VL_UNLIKELY(lhs == 0x8000000000000000ULL && rhs == 0xffffffffffffffffULL)) return 0;
vlsint64_t lhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, lhs);
vlsint64_t rhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, rhs);
return lhs_signed / rhs_signed;
}
static inline IData VL_MODDIVS_III(int lbits, IData lhs, IData rhs) VL_PURE {
if (VL_UNLIKELY(rhs == 0)) return 0;
if (VL_UNLIKELY(lhs == 0x80000000 && rhs == 0xffffffff)) return 0;
vlsint32_t lhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, lhs);
vlsint32_t rhs_signed = VL_EXTENDS_II(VL_IDATASIZE, lbits, rhs);
return lhs_signed % rhs_signed;
}
static inline QData VL_MODDIVS_QQQ(int lbits, QData lhs, QData rhs) VL_PURE {
if (VL_UNLIKELY(rhs == 0)) return 0;
if (VL_UNLIKELY(lhs == 0x8000000000000000ULL && rhs == 0xffffffffffffffffULL)) return 0;
vlsint64_t lhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, lhs);
vlsint64_t rhs_signed = VL_EXTENDS_QQ(VL_QUADSIZE, lbits, rhs);
return lhs_signed % rhs_signed;

View File

@ -220,20 +220,19 @@ private:
}
static void selftest() VL_MT_SAFE {
// Little selftest
#define VL_CST_CHECK(got, exp) \
#define SELF_CHECK(got, exp) \
do { \
if ((got) != (exp)) VL_FATAL_MT(__FILE__, __LINE__, "", "%Error: selftest\n"); \
} while (0)
VL_CST_CHECK(combineHier("a.b.c", "a.b.c"), "a.b.c");
VL_CST_CHECK(combineHier("a.b.c", "a.b"), "a.b*");
VL_CST_CHECK(combineHier("a.x.c", "a.y.c"), "a.*.c");
VL_CST_CHECK(combineHier("a.z.z.z.c", "a.b.c"), "a.*.c");
VL_CST_CHECK(combineHier("z", "a"), "*");
VL_CST_CHECK(combineHier("q.a", "q.b"), "q.*");
VL_CST_CHECK(combineHier("q.za", "q.zb"), "q.z*");
VL_CST_CHECK(combineHier("1.2.3.a", "9.8.7.a"), "*.a");
#undef VL_CST_CHECK
SELF_CHECK(combineHier("a.b.c", "a.b.c"), "a.b.c");
SELF_CHECK(combineHier("a.b.c", "a.b"), "a.b*");
SELF_CHECK(combineHier("a.x.c", "a.y.c"), "a.*.c");
SELF_CHECK(combineHier("a.z.z.z.c", "a.b.c"), "a.*.c");
SELF_CHECK(combineHier("z", "a"), "*");
SELF_CHECK(combineHier("q.a", "q.b"), "q.*");
SELF_CHECK(combineHier("q.za", "q.zb"), "q.z*");
SELF_CHECK(combineHier("1.2.3.a", "9.8.7.a"), "*.a");
#undef SELF_CHECK
}
void clearGuts() VL_REQUIRES(m_mutex) {
for (ItemList::const_iterator it = m_items.begin(); it != m_items.end(); ++it) {

View File

@ -133,8 +133,6 @@ void VerilatedFst::declare(vluint32_t code, const char* name, int dtypenum, fstV
VerilatedTrace<VerilatedFst>::declCode(code, bits, false);
std::pair<Code2SymbolType::iterator, bool> p
= m_code2symbol.insert(std::make_pair(code, static_cast<fstHandle>(NULL)));
std::istringstream nameiss(name);
std::istream_iterator<std::string> beg(nameiss);
std::istream_iterator<std::string> end;
@ -174,11 +172,13 @@ void VerilatedFst::declare(vluint32_t code, const char* name, int dtypenum, fstV
fstEnumHandle enumNum = m_local2fstdtype[dtypenum];
fstWriterEmitEnumTableRef(m_fst, enumNum);
}
if (p.second) { // New
p.first->second = fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), 0);
assert(p.first->second);
Code2SymbolType::const_iterator it = m_code2symbol.find(code);
if (it == m_code2symbol.end()) { // New
m_code2symbol[code]
= fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), 0);
} else { // Alias
fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), p.first->second);
fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), it->second);
}
}

View File

@ -62,6 +62,7 @@ public:
};
class VlWriteMem {
bool m_hex; // Hex format
int m_bits; // Bit width of values
FILE* m_fp; // File handle for filename
QData m_addr; // Next address to write

View File

@ -487,8 +487,8 @@ public: // But only for verilated*.cpp
const VerilatedLockGuard lock(s_s.m_fdMutex);
if (s_s.m_fdFree.empty()) {
// Need to create more space in m_fdps and m_fdFree
const size_t start = std::max(31ul + 1ul + 3ul, s_s.m_fdps.size());
const size_t excess = 10;
const std::size_t start = std::max<std::size_t>(31UL + 1UL + 3UL, s_s.m_fdps.size());
const std::size_t excess = 10;
s_s.m_fdps.resize(start + excess);
std::fill(s_s.m_fdps.begin() + start, s_s.m_fdps.end(), (FILE*)0);
s_s.m_fdFree.resize(excess);

View File

@ -129,7 +129,7 @@ void VerilatedSave::open(const char* filenamep) VL_MT_UNSAFE_ONE {
// cppcheck-suppress duplicateExpression
m_fd = ::open(filenamep,
O_CREAT | O_WRONLY | O_TRUNC | O_LARGEFILE | O_NONBLOCK | O_CLOEXEC, 0666);
if (m_fd < 0) {
if (VL_UNLIKELY(m_fd < 0)) {
// User code can check isOpen()
m_isOpen = false;
return;
@ -151,7 +151,7 @@ void VerilatedRestore::open(const char* filenamep) VL_MT_UNSAFE_ONE {
} else {
// cppcheck-suppress duplicateExpression
m_fd = ::open(filenamep, O_CREAT | O_RDONLY | O_LARGEFILE | O_CLOEXEC, 0666);
if (m_fd < 0) {
if (VL_UNLIKELY(m_fd < 0)) {
// User code can check isOpen()
m_isOpen = false;
return;

View File

@ -232,13 +232,15 @@ class VerilatedVar : public VerilatedVarProps {
void* m_datap; // Location of data
const char* m_namep; // Name - slowpath
protected:
bool m_isParam;
friend class VerilatedScope;
// CONSTRUCTORS
VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype,
VerilatedVarFlags vlflags, int dims)
VerilatedVarFlags vlflags, int dims, bool isParam)
: VerilatedVarProps(vltype, vlflags, (dims > 0 ? 1 : 0), ((dims > 1) ? dims - 1 : 0))
, m_datap(datap)
, m_namep(namep) {}
, m_namep(namep)
, m_isParam(isParam) {}
public:
~VerilatedVar() {}
@ -247,6 +249,7 @@ public:
const VerilatedRange& range() const { return packed(); } // Deprecated
const VerilatedRange& array() const { return unpacked(); } // Deprecated
const char* name() const { return m_namep; }
bool isParam() const { return m_isParam; }
};
#endif // Guard

View File

@ -158,6 +158,11 @@ private:
// to access duck-typed functions to avoid a virtual function call.
T_Derived* self() { return static_cast<T_Derived*>(this); }
// Flush any remaining data for this file
static void onFlush(void* selfp) VL_MT_UNSAFE_ONE;
// Close the file on termination
static void onExit(void* selfp) VL_MT_UNSAFE_ONE;
#ifdef VL_TRACE_THREADED
// Number of total trace buffers that have been allocated
vluint32_t m_numTraceBuffers;

View File

@ -258,6 +258,19 @@ template <> void VerilatedTrace<VL_DERIVED_T>::flush() {
#endif
}
//=============================================================================
// Callbacks to run on global events
template <> void VerilatedTrace<VL_DERIVED_T>::onFlush(void* selfp) {
// Note this calls 'flush' on the derived class
reinterpret_cast<VL_DERIVED_T*>(selfp)->flush();
}
template <> void VerilatedTrace<VL_DERIVED_T>::onExit(void* selfp) {
// Note this calls 'close' on the derived class
reinterpret_cast<VL_DERIVED_T*>(selfp)->close();
}
//=============================================================================
// VerilatedTrace
@ -282,6 +295,8 @@ VerilatedTrace<VL_DERIVED_T>::VerilatedTrace()
template <> VerilatedTrace<VL_DERIVED_T>::~VerilatedTrace() {
if (m_sigs_oldvalp) VL_DO_CLEAR(delete[] m_sigs_oldvalp, m_sigs_oldvalp = NULL);
Verilated::removeFlushCb(VerilatedTrace<VL_DERIVED_T>::onFlush, this);
Verilated::removeExitCb(VerilatedTrace<VL_DERIVED_T>::onExit, this);
#ifdef VL_TRACE_THREADED
close();
#endif
@ -318,6 +333,10 @@ template <> void VerilatedTrace<VL_DERIVED_T>::traceInit() VL_MT_UNSAFE {
// holding previous signal values.
if (!m_sigs_oldvalp) m_sigs_oldvalp = new vluint32_t[nextCode()];
// Set callback so flush/abort will flush this file
Verilated::addFlushCb(VerilatedTrace<VL_DERIVED_T>::onFlush, this);
Verilated::addExitCb(VerilatedTrace<VL_DERIVED_T>::onExit, this);
#ifdef VL_TRACE_THREADED
// Compute trace buffer size. we need to be able to store a new value for
// each signal, which is 'nextCode()' entries after the init callbacks

View File

@ -66,47 +66,6 @@
#include "verilated_trace_imp.cpp"
#undef VL_DERIVED_T
//=============================================================================
// VerilatedVcdImp
/// Base class to hold some static state
/// This is an internally used class
class VerilatedVcdSingleton {
private:
typedef std::vector<VerilatedVcd*> VcdVec;
struct Singleton {
VerilatedMutex s_vcdMutex; ///< Protect the singleton
VcdVec s_vcdVecp VL_GUARDED_BY(s_vcdMutex); ///< List of all created traces
};
static Singleton& singleton() {
static Singleton s;
return s;
}
public:
static void pushVcd(VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
const VerilatedLockGuard lock(singleton().s_vcdMutex);
singleton().s_vcdVecp.push_back(vcdp);
}
static void removeVcd(const VerilatedVcd* vcdp) VL_EXCLUDES(singleton().s_vcdMutex) {
const VerilatedLockGuard lock(singleton().s_vcdMutex);
VcdVec::iterator pos
= find(singleton().s_vcdVecp.begin(), singleton().s_vcdVecp.end(), vcdp);
if (pos != singleton().s_vcdVecp.end()) { singleton().s_vcdVecp.erase(pos); }
}
static void flush_all() VL_EXCLUDES(singleton().s_vcdMutex) VL_MT_UNSAFE_ONE {
// Thread safety: Although this function is protected by a mutex so
// perhaps in the future we can allow tracing in separate threads,
// vcdp->flush() assumes call from single thread
const VerilatedLockGuard lock(singleton().s_vcdMutex);
for (VcdVec::const_iterator it = singleton().s_vcdVecp.begin();
it != singleton().s_vcdVecp.end(); ++it) {
VerilatedVcd* vcdp = *it;
vcdp->flush();
}
}
};
//=============================================================================
//=============================================================================
//=============================================================================
@ -152,13 +111,7 @@ void VerilatedVcd::open(const char* filename) {
// Set member variables
m_filename = filename; // "" is ok, as someone may overload open
VerilatedVcdSingleton::pushVcd(this);
// SPDIFF_OFF
// Set callback so an early exit will flush us
Verilated::flushCb(&flush_all);
// SPDIFF_ON
openNext(m_rolloverMB != 0);
if (!isOpen()) return;
@ -266,7 +219,6 @@ VerilatedVcd::~VerilatedVcd() {
if (m_wrBufp) VL_DO_CLEAR(delete[] m_wrBufp, m_wrBufp = NULL);
deleteNameMap();
if (m_filep && m_fileNewed) VL_DO_CLEAR(delete m_filep, m_filep = NULL);
VerilatedVcdSingleton::removeVcd(this);
}
void VerilatedVcd::closePrev() {
@ -823,11 +775,6 @@ void VerilatedVcd::fullDouble(vluint32_t code, const double newval) {
#endif // VL_TRACE_VCD_OLD_API
//======================================================================
// Static members
void VerilatedVcd::flush_all() VL_MT_UNSAFE_ONE { VerilatedVcdSingleton::flush_all(); }
//======================================================================
//======================================================================
//======================================================================

View File

@ -105,9 +105,6 @@ private:
void finishLine(vluint32_t code, char* writep);
/// Flush any remaining data from all files
static void flush_all() VL_MT_UNSAFE_ONE;
// CONSTRUCTORS
VL_UNCOPYABLE(VerilatedVcd);

File diff suppressed because it is too large Load Diff

View File

@ -435,7 +435,7 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
// Performance counters
/// The vluint64_t argument is loaded with a high-performance counter for profiling
/// or 0x0 if not implemeted on this platform
/// or 0x0 if not implemented on this platform
#if defined(__i386__) || defined(__x86_64__)
#define VL_RDTSC(val) \
{ \

View File

@ -53,6 +53,7 @@ exclude_line_regexp(qr/(\bv3fatalSrc\b
|\bUINFO\b)/x);
# Exclude for branch coverage only
exclude_branch_regexp(qr/(\bdebug\(\))/x);
exclude_branch_regexp(qr/(\bdebug\(\)
|\bSELF_CHECK)/x);
1;

View File

@ -69,16 +69,17 @@ dbg: ../bin/verilator_bin_dbg ../bin/verilator_coverage_bin_dbg
$(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj serial_vlcov
$(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj
ifneq ($(VERILATOR_NO_OPT_BUILD),1) # Faster laptop development... don't rebuild each commit
ifneq ($(UNDER_GIT),) # If local git tree... else don't burden users
GIT_CHANGE_DEP = ${srcdir}/../.git/logs/HEAD
endif
endif
prefiles::
prefiles:: config_rev.h
ifneq ($(UNDER_GIT),) # If local git tree... Else don't burden users
# 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
config_rev.h: ${srcdir}/config_rev.pl $(GIT_CHANGE_DEP)
$(PERL) ${srcdir}/config_rev.pl ${srcdir} >$@
else
config_rev.h: ${srcdir}/config_rev.pl
$(PERL) ${srcdir}/config_rev.pl ${srcdir} >$@
endif
maintainer-copy::
clean mostlyclean distclean maintainer-clean::

View File

@ -278,7 +278,6 @@ V3__CONCAT.cpp: $(addsuffix .cpp, $(basename $(RAW_OBJS)))
$(TGT): $(PREDEP_H) $(OBJS)
@echo " Linking $@..."
-rm -rf $@ $@.exe
${LINK} ${LDFLAGS} -o $@ $(OBJS) $(CCMALLOC) ${LIBS}
V3Number_test: V3Number_test.o

View File

@ -316,10 +316,8 @@ private:
if (!combo && !sequent) combo = true; // If no list, Verilog 2000: always @ (*)
if (combo && sequent) {
if (!v3Global.opt.bboxUnsup()) {
nodep->v3error("Unsupported: Mixed edge (pos/negedge) and activity "
"(no edge) sensitive activity list");
}
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Mixed edge (pos/negedge) and activity "
"(no edge) sensitive activity list");
sequent = false;
}
@ -378,14 +376,6 @@ private:
// if (debug() >= 9) nodep->dumpTree(cout, " Alw: ");
visitAlways(nodep, nodep->sensesp(), VAlwaysKwd::ALWAYS);
}
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
AstSenItem* subitemp = nodep->sensesp();
UASSERT_OBJ(subitemp->edgeType() == VEdgeType::ET_ANYEDGE
|| subitemp->edgeType() == VEdgeType::ET_POSEDGE
|| subitemp->edgeType() == VEdgeType::ET_NEGEDGE,
nodep, "Strange activity type under SenGate");
iterateChildren(nodep);
}
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
if (nodep->varrefp()) {
if (AstBasicDType* basicp = nodep->varrefp()->dtypep()->basicp()) {
@ -405,8 +395,9 @@ private:
} else if (nodep->varrefp()) {
// V3LinkResolve should have cleaned most of these up
if (!nodep->varrefp()->width1()) {
nodep->v3error("Unsupported: Non-single bit wide signal pos/negedge sensitivity: "
<< nodep->varrefp()->prettyNameQ());
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Non-single bit wide signal pos/negedge sensitivity: "
<< nodep->varrefp()->prettyNameQ());
}
m_itemSequent = true;
nodep->varrefp()->varp()->usedClock(true);

View File

@ -54,7 +54,7 @@ private:
// VISITORS
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
m_topscopep = nodep;
m_finder.main(m_topscopep);
m_finder.init(m_topscopep);
iterateChildren(nodep);
m_topscopep = NULL;
}

View File

@ -34,11 +34,11 @@ private:
// NODE STATE/TYPES
// STATE
// Reset each module:
AstNodeSenItem* m_seniDefaultp; // Default sensitivity (from AstDefClock)
AstSenItem* m_seniDefaultp; // Default sensitivity (from AstDefClock)
// Reset each assertion:
AstNodeSenItem* m_senip; // Last sensitivity
AstSenItem* m_senip; // Last sensitivity
// Reset each always:
AstNodeSenItem* m_seniAlwaysp; // Last sensitivity in always
AstSenItem* m_seniAlwaysp; // Last sensitivity in always
// METHODS
VL_DEBUG_FUNC; // Declare debug()
@ -47,11 +47,11 @@ private:
// Create sentree based on clocked or default clock
// Return NULL for always
AstSenTree* newp = NULL;
AstNodeSenItem* senip = m_senip;
AstSenItem* senip = m_senip;
if (!senip) senip = m_seniDefaultp;
if (!senip) senip = m_seniAlwaysp;
if (!senip) {
nodep->v3error("Unsupported: Unclocked assertion");
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Unclocked assertion");
newp = new AstSenTree(nodep->fileline(), NULL);
} else {
newp = new AstSenTree(nodep->fileline(), senip->cloneTree(true));
@ -97,7 +97,8 @@ private:
virtual void visit(AstPropClocked* nodep) VL_OVERRIDE {
// No need to iterate the body, once replace will get iterated
iterateAndNextNull(nodep->sensesp());
if (m_senip) nodep->v3error("Unsupported: Only one PSL clock allowed per assertion");
if (m_senip)
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Only one PSL clock allowed per assertion");
// Block is the new expression to evaluate
AstNode* blockp = nodep->propp()->unlinkFrBack();
if (nodep->disablep()) {

View File

@ -117,6 +117,9 @@ public:
inline bool operator==(const VLifetime& lhs, const VLifetime& rhs) { return lhs.m_e == rhs.m_e; }
inline bool operator==(const VLifetime& lhs, VLifetime::en rhs) { return lhs.m_e == rhs; }
inline bool operator==(VLifetime::en lhs, const VLifetime& rhs) { return lhs == rhs.m_e; }
inline std::ostream& operator<<(std::ostream& os, const VLifetime& rhs) {
return os << rhs.ascii();
}
//######################################################################
@ -1809,6 +1812,8 @@ public:
virtual bool hasDType() const { return false; }
// Iff has a non-null childDTypep(), as generic node function
virtual AstNodeDType* getChildDTypep() const { return NULL; }
// Iff has a non-null child2DTypep(), as generic node function
virtual AstNodeDType* getChild2DTypep() const { return NULL; }
// Another AstNode* may have a pointer into this node, other then normal front/back/etc.
virtual bool maybePointedTo() const { return false; }
virtual const char* broken() const { return NULL; }
@ -2241,19 +2246,6 @@ public:
void addNotParallelp(AstNode* nodep) { setOp3p(nodep); }
};
class AstNodeSenItem : public AstNode {
// An AstSenItem or AstSenGate
public:
AstNodeSenItem(AstType t, FileLine* fl)
: AstNode(t, fl) {}
ASTNODE_BASE_FUNCS(NodeSenItem)
virtual bool isClocked() const = 0;
virtual bool isCombo() const = 0;
virtual bool isInitial() const = 0;
virtual bool isSettle() const = 0;
virtual bool isNever() const = 0;
};
class AstNodeVarRef : public AstNodeMath {
// An AstVarRef or AstVarXRef
private:
@ -2264,29 +2256,26 @@ private:
string m_name; // Name of variable
string m_hiername; // Scope converted into name-> for emitting
bool m_hierThis; // Hiername points to "this" function
void init();
public:
AstNodeVarRef(AstType t, FileLine* fl, const string& name, bool lvalue)
: AstNodeMath(t, fl)
, m_lvalue(lvalue)
, m_varp(NULL)
, m_varScopep(NULL)
, m_packagep(NULL)
, m_name(name)
, m_hierThis(false) {
init();
this->varp(NULL);
}
AstNodeVarRef(AstType t, FileLine* fl, const string& name, AstVar* varp, bool lvalue)
: AstNodeMath(t, fl)
, m_lvalue(lvalue)
, m_varp(varp)
, m_varScopep(NULL)
, m_packagep(NULL)
, m_name(name)
, m_hierThis(false) {
// May have varp==NULL
init();
this->varp(varp);
}
ASTNODE_BASE_FUNCS(NodeVarRef)
virtual bool hasDType() const { return true; }
@ -2298,7 +2287,7 @@ public:
bool lvalue() const { return m_lvalue; }
void lvalue(bool lval) { m_lvalue = lval; } // Avoid using this; Set in constructor
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
void varp(AstVar* varp) { m_varp = varp; }
void varp(AstVar* varp);
AstVarScope* varScopep() const { return m_varScopep; }
void varScopep(AstVarScope* varscp) { m_varScopep = varscp; }
string hiername() const { return m_hiername; }
@ -2636,6 +2625,7 @@ private:
bool m_taskPublic : 1; // Public task
bool m_attrIsolateAssign : 1; // User isolate_assignments attribute
bool m_classMethod : 1; // Class method
bool m_extern : 1; // Extern prototype
bool m_prototype : 1; // Just a prototype
bool m_dpiExport : 1; // DPI exported
bool m_dpiImport : 1; // DPI imported
@ -2644,6 +2634,8 @@ private:
bool m_dpiTask : 1; // DPI import task (vs. void function)
bool m_isConstructor : 1; // Class constructor
bool m_pure : 1; // DPI import pure (vs. virtual pure)
bool m_pureVirtual : 1; // Pure virtual
bool m_virtual : 1; // Virtual method in class
VLifetime m_lifetime; // Lifetime
public:
AstNodeFTask(AstType t, FileLine* fl, const string& name, AstNode* stmtsp)
@ -2653,6 +2645,7 @@ public:
, m_taskPublic(false)
, m_attrIsolateAssign(false)
, m_classMethod(false)
, m_extern(false)
, m_prototype(false)
, m_dpiExport(false)
, m_dpiImport(false)
@ -2660,7 +2653,9 @@ public:
, m_dpiOpenChild(false)
, m_dpiTask(false)
, m_isConstructor(false)
, m_pure(false) {
, m_pure(false)
, m_pureVirtual(false)
, m_virtual(false) {
addNOp3p(stmtsp);
cname(name); // Might be overridden by dpi import/export
}
@ -2693,6 +2688,8 @@ public:
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
void classMethod(bool flag) { m_classMethod = flag; }
bool classMethod() const { return m_classMethod; }
void isExtern(bool flag) { m_extern = flag; }
bool isExtern() const { return m_extern; }
void prototype(bool flag) { m_prototype = flag; }
bool prototype() const { return m_prototype; }
void dpiExport(bool flag) { m_dpiExport = flag; }
@ -2709,6 +2706,10 @@ public:
bool isConstructor() const { return m_isConstructor; }
void pure(bool flag) { m_pure = flag; }
bool pure() const { return m_pure; }
void pureVirtual(bool flag) { m_pureVirtual = flag; }
bool pureVirtual() const { return m_pureVirtual; }
void isVirtual(bool flag) { m_virtual = flag; }
bool isVirtual() const { return m_virtual; }
void lifetime(const VLifetime& flag) { m_lifetime = flag; }
VLifetime lifetime() const { return m_lifetime; }
};
@ -2926,8 +2927,9 @@ inline bool AstNode::sameGateTree(const AstNode* node2p) const {
return sameTreeIter(this, node2p, true, true);
}
inline void AstNodeVarRef::init() {
if (m_varp) dtypep(m_varp->dtypep());
inline void AstNodeVarRef::varp(AstVar* varp) {
m_varp = varp;
dtypeFrom(varp);
}
inline bool AstNodeDType::isFourstate() const { return basicp()->isFourstate(); }

View File

@ -22,6 +22,7 @@
#include "V3Global.h"
#include "V3Graph.h"
#include "V3PartitionGraph.h" // Just for mtask dumping
#include "V3String.h" // For VString::parseDouble
#include "V3EmitCBase.h"
#include <iomanip>
@ -225,6 +226,36 @@ AstNode* AstInsideRange::newAndFromInside(AstNode* exprp, AstNode* lhsp, AstNode
return newp;
}
AstConst* AstConst::parseParamLiteral(FileLine* fl, const string& literal) {
bool success = false;
if (literal[0] == '"') {
// This is a string
string v = literal.substr(1, literal.find('"', 1) - 1);
return new AstConst(fl, AstConst::VerilogStringLiteral(), v);
} else if (literal.find_first_of(".eEpP") != string::npos) {
// This may be a real
double v = VString::parseDouble(literal, &success);
if (success) return new AstConst(fl, AstConst::RealDouble(), v);
}
if (!success) {
// This is either an integer or an error
// We first try to convert it as C literal. If strtol returns
// 0 this is either an error or 0 was parsed. But in any case
// we will try to parse it as a verilog literal, hence having
// the false negative for 0 is okay. If anything remains in
// the string after the number, this is invalid C and we try
// the Verilog literal parser.
char* endp;
int v = strtol(literal.c_str(), &endp, 0);
if ((v != 0) && (endp[0] == 0)) { // C literal
return new AstConst(fl, AstConst::WidthedValue(), 32, v);
} else { // Try a Verilog literal (fatals if not)
return new AstConst(fl, AstConst::StringToParse(), literal.c_str());
}
}
return NULL;
}
void AstNetlist::timeprecisionMerge(FileLine*, const VTimescale& value) {
VTimescale prec = v3Global.opt.timeComputePrec(value);
if (prec.isNone() || prec == m_timeprecision) {
@ -495,8 +526,8 @@ string AstVar::cPubArgType(bool named, bool forReturn) const {
}
if (isWide()) {
if (forReturn) {
v3error("Unsupported: Public functions with >64 bit outputs; "
"make an output of a public task instead");
v3warn(E_UNSUPPORTED, "Unsupported: Public functions with >64 bit outputs; "
"make an output of a public task instead");
}
arg += " (& " + name();
arg += ")[" + cvtToStr(widthWords()) + "]";
@ -784,28 +815,28 @@ string AstScopeName::scopeNameFormatter(AstText* scopeTextp) const {
bool AstSenTree::hasClocked() const {
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) {
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
if (senp->isClocked()) return true;
}
return false;
}
bool AstSenTree::hasSettle() const {
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) {
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
if (senp->isSettle()) return true;
}
return false;
}
bool AstSenTree::hasInitial() const {
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) {
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
if (senp->isInitial()) return true;
}
return false;
}
bool AstSenTree::hasCombo() const {
UASSERT_OBJ(sensesp(), this, "SENTREE without any SENITEMs under it");
for (AstNodeSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) {
for (AstSenItem* senp = sensesp(); senp; senp = VN_CAST(senp->nextp(), SenItem)) {
if (senp->isCombo()) return true;
}
return false;

View File

@ -170,6 +170,9 @@ public:
virtual int instrCount() const { return widthInstrs(); }
bool isEqAllOnes() const { return num().isEqAllOnes(width()); }
bool isEqAllOnesV() const { return num().isEqAllOnes(widthMinV()); }
// Parse string and create appropriate type of AstConst.
// May return NULL on parse failure.
static AstConst* parseParamLiteral(FileLine* fl, const string& literal);
};
class AstRange : public AstNodeRange {
@ -231,33 +234,23 @@ public:
virtual bool same(const AstNode* samep) const { return true; }
};
class AstAssocRange : public AstNodeRange {
// Associative array range specification
// Only for early parsing - becomes AstAssocDType
class AstBracketRange : public AstNodeRange {
// Parser only concept "[lhsp]", a AstUnknownRange, QueueRange or Range,
// unknown until lhsp type is determined
public:
AstAssocRange(FileLine* fl, AstNodeDType* dtp)
AstBracketRange(FileLine* fl, AstNode* elementsp)
: ASTGEN_SUPER(fl) {
setOp1p(dtp);
setOp1p(elementsp);
}
ASTNODE_NODE_FUNCS(AssocRange)
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual string emitVerilog() { V3ERROR_NA_RETURN(""); }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const { return true; }
AstNodeDType* keyDTypep() const { return VN_CAST(op1p(), NodeDType); }
};
class AstQueueRange : public AstNodeRange {
// Queue range specification
// Only for early parsing - becomes AstQueueDType
public:
explicit AstQueueRange(FileLine* fl)
: ASTGEN_SUPER(fl) {}
ASTNODE_NODE_FUNCS(QueueRange)
ASTNODE_NODE_FUNCS(BracketRange)
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual string emitVerilog() { V3ERROR_NA_RETURN(""); }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const { return true; }
// Will be removed in V3Width, which relies on this
// being a child not a dtype pointed node
virtual bool maybePointedTo() const { return false; }
AstNode* elementsp() const { return op1p(); }
};
class AstUnsizedRange : public AstNodeRange {
@ -311,6 +304,7 @@ class AstClass : public AstNodeModule {
// MEMBERS
MemberNameMap m_members; // Members or method children
AstClassPackage* m_packagep; // Class package this is under
bool m_virtual; // Virtual class
void insertCache(AstNode* nodep);
public:
@ -343,6 +337,8 @@ public:
MemberNameMap::const_iterator it = m_members.find(name);
return (it == m_members.end()) ? NULL : it->second;
}
bool isVirtual() const { return m_virtual; }
void isVirtual(bool flag) { m_virtual = flag; }
};
class AstClassExtends : public AstNode {
@ -541,8 +537,9 @@ public:
virtual string prettyDTypeName() const;
virtual void dumpSmall(std::ostream& str) const;
virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); }
virtual AstNodeDType* getChildDTypep() const { return childDTypep(); }
virtual AstNodeDType* getChild2DTypep() const { return keyChildDTypep(); }
virtual bool isHeavy() const { return true; }
AstNodeDType* getChildDTypep() const { return childDTypep(); }
// op1 = Range of variable
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
@ -567,6 +564,36 @@ public:
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
};
class AstBracketArrayDType : public AstNodeDType {
// Associative/Queue/Normal array data type, ie "[dtype_or_expr]"
// only for early parsing then becomes another data type
// Children: DTYPE (moved to refDTypep() in V3Width)
// Children: DTYPE (the key)
public:
AstBracketArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* elementsp)
: ASTGEN_SUPER(fl) {
setOp1p(dtp); // Only for parser
setOp2p(elementsp); // Only for parser
}
ASTNODE_NODE_FUNCS(BracketArrayDType)
virtual bool similarDType(AstNodeDType* samep) const { V3ERROR_NA_RETURN(false); }
// op1 = Range of variable
AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); }
virtual AstNodeDType* subDTypep() const { return childDTypep(); }
// op2 = Range of variable
AstNode* elementsp() const { return op2p(); }
// METHODS
// Will be removed in V3Width, which relies on this
// being a child not a dtype pointed node
virtual bool maybePointedTo() const { return false; }
virtual AstBasicDType* basicp() const { return NULL; }
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const { V3ERROR_NA_RETURN(0); }
virtual int widthTotalBytes() const { V3ERROR_NA_RETURN(0); }
};
class AstDynArrayDType : public AstNodeDType {
// Dynamic array data type, ie "[]"
// Children: DTYPE (moved to refDTypep() in V3Width)
@ -1539,6 +1566,25 @@ public:
virtual bool same(const AstNode* samep) const { return true; }
};
class AstSelLoopVars : public AstNode {
// Parser only concept "[id, id, id]" for a foreach statement
// Unlike normal selects elements is a list
public:
AstSelLoopVars(FileLine* fl, AstNode* fromp, AstNode* elementsp)
: ASTGEN_SUPER(fl) {
setOp1p(fromp);
addNOp2p(elementsp);
}
ASTNODE_NODE_FUNCS(SelLoopVars)
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual string emitVerilog() { V3ERROR_NA_RETURN(""); }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const { return true; }
virtual bool maybePointedTo() const { return false; }
AstNode* fromp() const { return op1p(); }
AstNode* elementsp() const { return op2p(); }
};
class AstSelExtract : public AstNodePreSel {
// Range extraction, gets replaced with AstSel
public:
@ -2972,11 +3018,26 @@ public:
void cname(const string& cname) { m_cname = cname; }
};
class AstWith : public AstNodeStmt {
public:
AstWith(FileLine* fl, bool stmt, AstNode* funcrefp, AstNode* argsp)
: ASTGEN_SUPER(fl) {
statement(stmt);
setOp1p(funcrefp);
addNOp2p(argsp);
}
ASTNODE_NODE_FUNCS(With)
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const { return true; }
//
AstNode* funcrefp() const { return op1p(); }
};
//######################################################################
class AstSenItem : public AstNodeSenItem {
class AstSenItem : public AstNode {
// Parents: SENTREE
// Children: (optional) VARREF SENGATE
// Children: (optional) VARREF
private:
VEdgeType m_edgeType; // Edge type
public:
@ -3026,41 +3087,15 @@ public:
return VN_CAST(op1p(), NodeVarRef);
} // op1 = Signal sensitized
//
virtual bool isClocked() const { return edgeType().clockedStmt(); }
virtual bool isCombo() const { return edgeType() == VEdgeType::ET_COMBO; }
virtual bool isInitial() const { return edgeType() == VEdgeType::ET_INITIAL; }
virtual bool isIllegal() const { return edgeType() == VEdgeType::ET_ILLEGAL; }
virtual bool isSettle() const { return edgeType() == VEdgeType::ET_SETTLE; }
virtual bool isNever() const { return edgeType() == VEdgeType::ET_NEVER; }
bool isClocked() const { return edgeType().clockedStmt(); }
bool isCombo() const { return edgeType() == VEdgeType::ET_COMBO; }
bool isInitial() const { return edgeType() == VEdgeType::ET_INITIAL; }
bool isIllegal() const { return edgeType() == VEdgeType::ET_ILLEGAL; }
bool isSettle() const { return edgeType() == VEdgeType::ET_SETTLE; }
bool isNever() const { return edgeType() == VEdgeType::ET_NEVER; }
bool hasVar() const { return !(isCombo() || isInitial() || isSettle() || isNever()); }
};
class AstSenGate : public AstNodeSenItem {
// Parents: SENTREE
// Children: SENITEM expr
// AND as applied to a sensitivity list and a gating expression
// Performing this gating is optional; it may be removed by later optimizations
public:
AstSenGate(FileLine* fl, AstSenItem* sensesp, AstNode* rhsp)
: ASTGEN_SUPER(fl) {
dtypeSetLogicBool();
addOp1p(sensesp);
setOp2p(rhsp);
}
ASTNODE_NODE_FUNCS(SenGate)
virtual string emitVerilog() { return "(%l) %f&& (%r)"; }
AstSenItem* sensesp() const { return VN_CAST(op1p(), SenItem); }
AstNode* rhsp() const { return op2p(); }
void sensesp(AstSenItem* nodep) { addOp1p(nodep); }
void rhsp(AstNode* nodep) { setOp2p(nodep); }
//
virtual bool isClocked() const { return true; }
virtual bool isCombo() const { return false; }
virtual bool isInitial() const { return false; }
virtual bool isSettle() const { return false; }
virtual bool isNever() const { return false; }
};
class AstSenTree : public AstNode {
// A list of senitems
// Parents: MODULE | SBLOCK
@ -3068,7 +3103,7 @@ class AstSenTree : public AstNode {
private:
bool m_multi; // Created from combo logic by ORing multiple clock domains
public:
AstSenTree(FileLine* fl, AstNodeSenItem* sensesp)
AstSenTree(FileLine* fl, AstSenItem* sensesp)
: ASTGEN_SUPER(fl)
, m_multi(false) {
addNOp1p(sensesp);
@ -3079,8 +3114,8 @@ public:
virtual V3Hash sameHash() const { return V3Hash(); }
bool isMulti() const { return m_multi; }
// op1 = Sensitivity list
AstNodeSenItem* sensesp() const { return VN_CAST(op1p(), NodeSenItem); }
void addSensesp(AstNodeSenItem* nodep) { addOp1p(nodep); }
AstSenItem* sensesp() const { return VN_CAST(op1p(), SenItem); }
void addSensesp(AstSenItem* nodep) { addOp1p(nodep); }
void multi(bool flag) { m_multi = true; }
// METHODS
bool hasClocked() const; // Includes a clocked statement
@ -3116,6 +3151,7 @@ public:
//
virtual void dump(std::ostream& str) const;
AstSenTree* sensesp() const { return VN_CAST(op1p(), SenTree); } // op1 = Sensitivity list
void sensesp(AstSenTree* nodep) { setOp1p(nodep); }
VAlwaysKwd keyword() const { return m_keyword; }
};
@ -3548,10 +3584,11 @@ public:
addNOp1p(exprsp);
addNOp2p(NULL);
}
AstSFormatF(FileLine* fl, NoFormat, AstNode* exprsp, char missingArgChar = 'd')
AstSFormatF(FileLine* fl, NoFormat, AstNode* exprsp, char missingArgChar = 'd',
bool hidden = true)
: ASTGEN_SUPER(fl)
, m_text("")
, m_hidden(true)
, m_hidden(hidden)
, m_hasFormat(false)
, m_missingArgChar(missingArgChar) {
dtypeSetString();
@ -3708,6 +3745,11 @@ public:
setOp1p(new AstSFormatF(fl, text, true, exprsp, missingArgChar));
setOp3p(lhsp);
}
AstSFormat(FileLine* fl, AstNode* lhsp, AstNode* exprsp, char missingArgChar = 'd')
: ASTGEN_SUPER(fl) {
setOp1p(new AstSFormatF(fl, AstSFormatF::NoFormat(), exprsp, missingArgChar));
setOp3p(lhsp);
}
ASTNODE_NODE_FUNCS(SFormat)
virtual const char* broken() const {
BROKEN_RTN(!fmtp());
@ -4088,8 +4130,9 @@ public:
class AstWriteMem : public AstNodeReadWriteMem {
public:
AstWriteMem(FileLine* fl, AstNode* filenamep, AstNode* memp, AstNode* lsbp, AstNode* msbp)
: ASTGEN_SUPER(fl, true, filenamep, memp, lsbp, msbp) {}
AstWriteMem(FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, AstNode* lsbp,
AstNode* msbp)
: ASTGEN_SUPER(fl, hex, filenamep, memp, lsbp, msbp) {}
ASTNODE_NODE_FUNCS(WriteMem)
virtual string verilogKwd() const { return (isHex() ? "$writememh" : "$writememb"); }
virtual const char* cFuncPrefixp() const { return "VL_WRITEMEM_"; }
@ -4196,15 +4239,13 @@ public:
class AstForeach : public AstNodeStmt {
public:
AstForeach(FileLine* fl, AstNode* arrayp, AstNode* varsp, AstNode* bodysp)
AstForeach(FileLine* fl, AstNode* arrayp, AstNode* bodysp)
: ASTGEN_SUPER(fl) {
setOp1p(arrayp);
addNOp2p(varsp);
addNOp4p(bodysp);
}
ASTNODE_NODE_FUNCS(Foreach)
AstNode* arrayp() const { return op1p(); } // op1 = array
AstNode* varsp() const { return op2p(); } // op2 = variable index list
AstNode* arrayp() const { return op1p(); } // op1 = array and index vars
AstNode* bodysp() const { return op4p(); } // op4 = body of loop
virtual bool isGateOptimizable() const { return false; }
virtual int instrCount() const { return instrCountBranch(); }
@ -4228,6 +4269,17 @@ public:
virtual bool same(const AstNode* samep) const { return true; }
};
class AstWait : public AstNodeStmt {
public:
AstWait(FileLine* fl, AstNode* condp, AstNode* bodysp)
: ASTGEN_SUPER(fl) {
setOp2p(condp);
addNOp3p(bodysp);
}
ASTNODE_NODE_FUNCS(Wait)
AstNode* bodysp() const { return op3p(); } // op3 = body of loop
};
class AstWhile : public AstNodeStmt {
public:
AstWhile(FileLine* fl, AstNode* condp, AstNode* bodysp, AstNode* incsp = NULL)
@ -4292,6 +4344,22 @@ public:
}
};
class AstDisableFork : public AstNodeStmt {
// A "disable fork" statement
public:
AstDisableFork(FileLine* fl)
: ASTGEN_SUPER(fl) {}
ASTNODE_NODE_FUNCS(DisableFork)
};
class AstWaitFork : public AstNodeStmt {
// A "wait fork" statement
public:
AstWaitFork(FileLine* fl)
: ASTGEN_SUPER(fl) {}
ASTNODE_NODE_FUNCS(WaitFork)
};
class AstReturn : public AstNodeStmt {
public:
explicit AstReturn(FileLine* fl, AstNode* lhsp = NULL)
@ -4798,6 +4866,26 @@ public:
virtual bool same(const AstNode* samep) const { return fileline() == samep->fileline(); }
};
class AstTimingControl : public AstNodeStmt {
// Parents: stmtlist
public:
AstTimingControl(FileLine* fl, AstSenTree* sensesp, AstNode* stmtsp)
: ASTGEN_SUPER(fl) {
setNOp1p(sensesp);
setNOp2p(stmtsp);
}
ASTNODE_NODE_FUNCS(TimingControl)
virtual string verilogKwd() const { return "@(%l) %r"; }
virtual bool isGateOptimizable() const { return false; }
virtual bool isPredictOptimizable() const { return false; }
virtual bool isPure() const { return false; }
virtual bool isOutputter() const { return false; }
virtual int instrCount() const { return 0; }
virtual V3Hash sameHash() const { return V3Hash(); }
AstSenTree* sensesp() const { return VN_CAST(op1p(), SenTree); }
AstNode* stmtsp() const { return op2p(); }
};
class AstTimeFormat : public AstNodeStmt {
// Parents: stmtlist
public:
@ -5593,6 +5681,30 @@ public:
AstNode* lhsp() const { return op1p(); }
AstNodeDType* getChildDTypep() const { return childDTypep(); }
AstNodeDType* childDTypep() const { return VN_CAST(op2p(), NodeDType); }
virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
};
class AstCastDynamic : public AstNodeBiop {
public:
AstCastDynamic(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
: ASTGEN_SUPER(fl, lhsp, rhsp) {}
ASTNODE_NODE_FUNCS(CastDynamic)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) {
V3ERROR_NA;
}
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) {
return new AstCastDynamic(this->fileline(), lhsp, rhsp);
}
virtual string emitVerilog() { return "%f$cast(%r, %l)"; }
// Non-existent filehandle returns EOF
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const { return true; }
virtual bool cleanLhs() const { return true; }
virtual bool cleanRhs() const { return true; }
virtual bool sizeMattersLhs() const { return false; }
virtual bool sizeMattersRhs() const { return false; }
virtual int instrCount() const { return widthInstrs() * 20; }
virtual bool isPure() const { return true; }
};
class AstCastParse : public AstNode {
@ -7940,14 +8052,14 @@ class AstClocking : public AstNode {
// Parents: MODULE
// Children: Assertions
public:
AstClocking(FileLine* fl, AstNodeSenItem* sensesp, AstNode* bodysp)
AstClocking(FileLine* fl, AstSenItem* sensesp, AstNode* bodysp)
: ASTGEN_SUPER(fl) {
addOp1p(sensesp);
addNOp2p(bodysp);
}
ASTNODE_NODE_FUNCS(Clocking)
// op1 = Sensitivity list
AstNodeSenItem* sensesp() const { return VN_CAST(op1p(), NodeSenItem); }
AstSenItem* sensesp() const { return VN_CAST(op1p(), SenItem); }
AstNode* bodysp() const { return op2p(); } // op2 = Body
};
@ -7959,7 +8071,7 @@ class AstPropClocked : public AstNode {
// Parents: ASSERT|COVER (property)
// Children: SENITEM, Properties
public:
AstPropClocked(FileLine* fl, AstNodeSenItem* sensesp, AstNode* disablep, AstNode* propp)
AstPropClocked(FileLine* fl, AstSenItem* sensesp, AstNode* disablep, AstNode* propp)
: ASTGEN_SUPER(fl) {
addNOp1p(sensesp);
addNOp2p(disablep);
@ -7967,9 +8079,7 @@ public:
}
ASTNODE_NODE_FUNCS(PropClocked)
virtual bool hasDType() const { return true; } // Used under Cover, which expects a bool child
AstNodeSenItem* sensesp() const {
return VN_CAST(op1p(), NodeSenItem);
} // op1 = Sensitivity list
AstSenItem* sensesp() const { return VN_CAST(op1p(), SenItem); } // op1 = Sensitivity list
AstNode* disablep() const { return op2p(); } // op2 = disable
AstNode* propp() const { return op3p(); } // op3 = property
};

View File

@ -694,8 +694,6 @@ private:
m_inDly = false;
}
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
// Note we look at only AstSenItems, not AstSenGate's
// The gating term of a AstSenGate is normal logic
m_inSenItem = true;
iterateChildren(nodep);
m_inSenItem = false;
@ -705,11 +703,6 @@ private:
// CDC doesn't care about public variables
}
virtual void visit(AstCFunc* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
// First handle the clock part will be handled in a minute by visit AstSenItem
// The logic gating term is dealt with as logic
iterateNewStmt(nodep);
}
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
virtual void visit(AstAssignW* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }

View File

@ -66,8 +66,8 @@ private:
if (vscp->user1p()) return static_cast<AstVarScope*>(vscp->user1p());
AstVar* varp = vscp->varp();
if (!varp->width1()) {
varp->v3error(
"Unsupported: Clock edge on non-single bit signal: " << varp->prettyNameQ());
varp->v3warn(E_UNSUPPORTED, "Unsupported: Clock edge on non-single bit signal: "
<< varp->prettyNameQ());
}
string newvarname
= (string("__Vclklast__") + vscp->scopep()->nameDotless() + "__" + varp->name());
@ -103,10 +103,8 @@ private:
// LOWEDGE: ~var
AstNode* newp = NULL;
if (nodep->edgeType() == VEdgeType::ET_ILLEGAL) {
if (!v3Global.opt.bboxUnsup()) {
nodep->v3error(
"Unsupported: Complicated event expression in sensitive activity list");
}
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Complicated event expression in sensitive activity list");
return NULL;
}
AstVarScope* clkvscp = nodep->varrefp()->varScopep();
@ -138,23 +136,11 @@ private:
}
return newp;
}
AstNode* createSenGateEquation(AstSenGate* nodep) {
AstNode* newp = new AstAnd(nodep->fileline(), createSenseEquation(nodep->sensesp()),
nodep->rhsp()->cloneTree(true));
return newp;
}
AstNode* createSenseEquation(AstNodeSenItem* nodesp) {
AstNode* createSenseEquation(AstSenItem* nodesp) {
// Nodep may be a list of elements; we need to walk it
AstNode* senEqnp = NULL;
for (AstNodeSenItem* senp = nodesp; senp; senp = VN_CAST(senp->nextp(), NodeSenItem)) {
AstNode* senOnep = NULL;
if (AstSenItem* itemp = VN_CAST(senp, SenItem)) {
senOnep = createSenItemEquation(itemp);
} else if (AstSenGate* itemp = VN_CAST(senp, SenGate)) {
senOnep = createSenGateEquation(itemp);
} else {
senp->v3fatalSrc("Strange node under sentree");
}
for (AstSenItem* senp = nodesp; senp; senp = VN_CAST(senp->nextp(), SenItem)) {
AstNode* const senOnep = createSenItemEquation(senp);
if (senEqnp) {
// Add new OR to the sensitivity list equation
senEqnp = new AstOr(senp->fileline(), senEqnp, senOnep);

View File

@ -158,19 +158,19 @@ typedef V3ConfigWildcardResolver<V3ConfigFTask> V3ConfigFTaskResolver;
class V3ConfigModule {
typedef vl_unordered_set<string> StringSet;
typedef std::set<AstPragmaType> PragmaSet;
V3ConfigFTaskResolver m_tasks; // Functions/tasks in module
V3ConfigVarResolver m_vars; // Variables in module
StringSet m_coverageOffBlocks; // List of block names for coverage_off
PragmaSet m_modPragmas; // List of Pragmas for modules
bool m_inline; // Whether to force the inline
bool m_inlineValue; // The inline value (on/off)
bool m_public; // Public module
public:
V3ConfigModule()
: m_inline(false)
, m_inlineValue(false)
, m_public(false) {}
, m_inlineValue(false) {}
void update(const V3ConfigModule& m) {
m_tasks.update(m.m_tasks);
@ -183,7 +183,10 @@ public:
m_inline = m.m_inline;
m_inlineValue = m.m_inlineValue;
}
if (!m_public) m_public = m.m_public;
for (PragmaSet::const_iterator it = m.m_modPragmas.begin(); it != m.m_modPragmas.end();
++it) {
m_modPragmas.insert(*it);
}
}
V3ConfigFTaskResolver& ftasks() { return m_tasks; }
@ -194,7 +197,7 @@ public:
m_inline = true;
m_inlineValue = set;
}
void setPublic(bool set) { m_public = set; }
void addModulePragma(AstPragmaType pragma) { m_modPragmas.insert(pragma); }
void apply(AstNodeModule* modp) {
if (m_inline) {
@ -203,8 +206,8 @@ public:
AstNode* nodep = new AstPragma(modp->fileline(), type);
modp->addStmtp(nodep);
}
if (m_public) {
AstNode* nodep = new AstPragma(modp->fileline(), AstPragmaType::PUBLIC_MODULE);
for (PragmaSet::const_iterator it = m_modPragmas.begin(); it != m_modPragmas.end(); ++it) {
AstNode* nodep = new AstPragma(modp->fileline(), *it);
modp->addStmtp(nodep);
}
}
@ -408,6 +411,10 @@ void V3Config::addIgnore(V3ErrorCode code, bool on, const string& filename, int
}
}
void V3Config::addModulePragma(const string& module, AstPragmaType pragma) {
V3ConfigResolver::s().modules().at(module).addModulePragma(pragma);
}
void V3Config::addInline(FileLine* fl, const string& module, const string& ftask, bool on) {
if (ftask.empty()) {
V3ConfigResolver::s().modules().at(module).setInline(on);
@ -439,7 +446,8 @@ void V3Config::addVarAttr(FileLine* fl, const string& module, const string& ftas
} else if (attr == AstAttrType::VAR_PUBLIC) {
if (ftask.empty()) {
// public module, this is the only exception from var here
V3ConfigResolver::s().modules().at(module).setPublic(true);
V3ConfigResolver::s().modules().at(module).addModulePragma(
AstPragmaType::PUBLIC_MODULE);
} else {
V3ConfigResolver::s().modules().at(module).ftasks().at(ftask).setPublic(true);
}

View File

@ -34,6 +34,7 @@ public:
static void addCoverageBlockOff(const string& module, const string& blockname);
static void addIgnore(V3ErrorCode code, bool on, const string& filename, int min, int max);
static void addWaiver(V3ErrorCode code, const string& filename, const string& message);
static void addModulePragma(const string& module, AstPragmaType pragma);
static void addInline(FileLine* fl, const string& module, const string& ftask, bool on);
static void addVarAttr(FileLine* fl, const string& module, const string& ftask,
const string& signal, AstAttrType type, AstSenTree* nodep);

View File

@ -588,6 +588,7 @@ private:
}
return false;
}
bool operandsSameSize(AstNode* lhsp, AstNode* rhsp) { return lhsp->width() == rhsp->width(); }
//----------------------------------------
// Constant Replacement functions.
@ -1678,7 +1679,7 @@ private:
// Not constant propagated (for today) because AstNodeMath::isOpaque is set
// Someday if lower is constant, convert to quoted "string".
bool onlySenItemInSenTree(AstNodeSenItem* nodep) {
bool onlySenItemInSenTree(AstSenItem* nodep) {
// Only one if it's not in a list
return (!nodep->nextp() && nodep->backp()->nextp() != nodep);
}
@ -1722,56 +1723,29 @@ private:
"Null sensitivity variable");
}
}
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (AstConst* constp = VN_CAST(nodep->rhsp(), Const)) {
if (constp->isZero()) {
UINFO(4, "SENGATE(...,0)->NEVER" << endl);
if (onlySenItemInSenTree(nodep)) {
nodep->replaceWith(new AstSenItem(nodep->fileline(), AstSenItem::Never()));
VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else {
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
} else {
UINFO(4, "SENGATE(SENITEM,0)->ALWAYS SENITEM" << endl);
AstNode* senitemp = nodep->sensesp()->unlinkFrBack();
nodep->replaceWith(senitemp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
}
}
struct SenItemCmp {
inline bool operator()(AstNodeSenItem* lhsp, AstNodeSenItem* rhsp) const {
inline bool operator()(const AstSenItem* lhsp, const AstSenItem* rhsp) const {
if (lhsp->type() < rhsp->type()) return true;
if (lhsp->type() > rhsp->type()) return false;
const AstSenItem* litemp = VN_CAST_CONST(lhsp, SenItem);
const AstSenItem* ritemp = VN_CAST_CONST(rhsp, SenItem);
if (litemp && ritemp) {
// Looks visually better if we keep sorted by name
if (!litemp->varrefp() && ritemp->varrefp()) return true;
if (litemp->varrefp() && !ritemp->varrefp()) return false;
if (litemp->varrefp() && ritemp->varrefp()) {
if (litemp->varrefp()->name() < ritemp->varrefp()->name()) return true;
if (litemp->varrefp()->name() > ritemp->varrefp()->name()) return false;
// But might be same name with different scopes
if (litemp->varrefp()->varScopep() < ritemp->varrefp()->varScopep()) {
return true;
}
if (litemp->varrefp()->varScopep() > ritemp->varrefp()->varScopep()) {
return false;
}
// Or rarely, different data types
if (litemp->varrefp()->dtypep() < ritemp->varrefp()->dtypep()) return true;
if (litemp->varrefp()->dtypep() > ritemp->varrefp()->dtypep()) return false;
}
// Sort by edge, AFTER variable, as we want multiple edges for same var adjacent.
// note the SenTree optimizer requires this order (more
// general first, less general last)
if (litemp->edgeType() < ritemp->edgeType()) return true;
if (litemp->edgeType() > ritemp->edgeType()) return false;
// Looks visually better if we keep sorted by name
if (!lhsp->varrefp() && rhsp->varrefp()) return true;
if (lhsp->varrefp() && !rhsp->varrefp()) return false;
if (lhsp->varrefp() && rhsp->varrefp()) {
if (lhsp->varrefp()->name() < rhsp->varrefp()->name()) return true;
if (lhsp->varrefp()->name() > rhsp->varrefp()->name()) return false;
// But might be same name with different scopes
if (lhsp->varrefp()->varScopep() < rhsp->varrefp()->varScopep()) { return true; }
if (lhsp->varrefp()->varScopep() > rhsp->varrefp()->varScopep()) { return false; }
// Or rarely, different data types
if (lhsp->varrefp()->dtypep() < rhsp->varrefp()->dtypep()) return true;
if (lhsp->varrefp()->dtypep() > rhsp->varrefp()->dtypep()) return false;
}
// Sort by edge, AFTER variable, as we want multiple edges for same var adjacent.
// note the SenTree optimizer requires this order (more
// general first, less general last)
if (lhsp->edgeType() < rhsp->edgeType()) return true;
if (lhsp->edgeType() > rhsp->edgeType()) return false;
return false;
}
};
@ -1792,30 +1766,10 @@ private:
{
AstUser4InUse m_inuse4;
// Mark x in SENITEM(x)
for (AstNodeSenItem* senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp;
senp = VN_CAST(senp->nextp(), NodeSenItem)) {
if (AstSenItem* itemp = VN_CAST(senp, SenItem)) {
if (itemp->varrefp() && itemp->varrefp()->varScopep()) {
itemp->varrefp()->varScopep()->user4(1);
}
}
}
// Find x in SENTREE(SENITEM(x))
for (AstNodeSenItem *nextp, *senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp;
senp = nextp) {
nextp = VN_CAST(senp->nextp(), NodeSenItem);
if (AstSenGate* gatep = VN_CAST(senp, SenGate)) {
if (AstSenItem* itemp = VN_CAST(gatep->sensesp(), SenItem)) {
if (itemp->varrefp() && itemp->varrefp()->varScopep()) {
if (itemp->varrefp()->varScopep()->user4()) {
// Found, push this item up to the top
itemp->unlinkFrBack();
nodep->addSensesp(itemp);
VL_DO_DANGLING(gatep->unlinkFrBack()->deleteTree(), gatep);
VL_DANGLING(senp);
}
}
}
for (AstSenItem* senp = VN_CAST(nodep->sensesp(), SenItem); senp;
senp = VN_CAST(senp->nextp(), SenItem)) {
if (senp->varrefp() && senp->varrefp()->varScopep()) {
senp->varrefp()->varScopep()->user4(1);
}
}
}
@ -1823,25 +1777,25 @@ private:
// Sort the sensitivity names so "posedge a or b" and "posedge b or a" end up together.
// Also, remove duplicate assignments, and fold POS&NEGs into ANYEDGEs
// Make things a little faster; check first if we need a sort
for (AstNodeSenItem *nextp, *senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp;
for (AstSenItem *nextp, *senp = VN_CAST(nodep->sensesp(), SenItem); senp;
senp = nextp) {
nextp = VN_CAST(senp->nextp(), NodeSenItem);
nextp = VN_CAST(senp->nextp(), SenItem);
// cppcheck-suppress unassignedVariable // cppcheck bug
SenItemCmp cmp;
if (nextp && !cmp(senp, nextp)) {
// Something's out of order, sort it
senp = NULL;
std::vector<AstNodeSenItem*> vec;
for (AstNodeSenItem* senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp;
senp = VN_CAST(senp->nextp(), NodeSenItem)) {
std::vector<AstSenItem*> vec;
for (AstSenItem* senp = VN_CAST(nodep->sensesp(), SenItem); senp;
senp = VN_CAST(senp->nextp(), SenItem)) {
vec.push_back(senp);
}
stable_sort(vec.begin(), vec.end(), SenItemCmp());
for (std::vector<AstNodeSenItem*>::iterator it = vec.begin(); it != vec.end();
for (std::vector<AstSenItem*>::iterator it = vec.begin(); it != vec.end();
++it) {
(*it)->unlinkFrBack();
}
for (std::vector<AstNodeSenItem*>::iterator it = vec.begin(); it != vec.end();
for (std::vector<AstSenItem*>::iterator it = vec.begin(); it != vec.end();
++it) {
nodep->addSensesp(*it);
}
@ -1850,13 +1804,12 @@ private:
}
// Pass2, remove dup edges
for (AstNodeSenItem *nextp, *senp = VN_CAST(nodep->sensesp(), NodeSenItem); senp;
for (AstSenItem *nextp, *senp = VN_CAST(nodep->sensesp(), SenItem); senp;
senp = nextp) {
nextp = VN_CAST(senp->nextp(), NodeSenItem);
AstNodeSenItem* cmpp = nextp;
AstSenItem* litemp = VN_CAST(senp, SenItem);
AstSenItem* ritemp = VN_CAST(cmpp, SenItem);
if (litemp && ritemp) {
nextp = VN_CAST(senp->nextp(), SenItem);
AstSenItem* const litemp = senp;
AstSenItem* const ritemp = nextp;
if (ritemp) {
if ((litemp->varrefp() && ritemp->varrefp()
&& litemp->varrefp()->sameGateTree(ritemp->varrefp()))
|| (!litemp->varrefp() && !ritemp->varrefp())) {
@ -1876,7 +1829,7 @@ private:
litemp->edgeType(VEdgeType::ET_BOTHEDGE);
// Remove redundant node
VL_DO_DANGLING(ritemp->unlinkFrBack()->deleteTree(), ritemp);
VL_DANGLING(cmpp);
VL_DANGLING(ritemp);
// Try to collapse again
nextp = litemp;
}
@ -1934,9 +1887,12 @@ private:
if (constp->isZero()) {
UINFO(4, "IF(0,{any},{x}) => {x}: " << nodep << endl);
keepp = nodep->elsesp();
} else {
} else if (!m_doV || constp->isNeqZero()) { // Might be X in Verilog
UINFO(4, "IF(!0,{x},{any}) => {x}: " << nodep << endl);
keepp = nodep->ifsp();
} else {
UINFO(4, "IF condition is X, retaining: " << nodep << endl);
return;
}
if (keepp) {
keepp->unlinkFrBackWithNext();
@ -2322,7 +2278,7 @@ private:
TREEOP ("AstMulS {$lhsp.isOne, $rhsp}", "replaceWRhs(nodep)");
TREEOP ("AstDiv {$lhsp, $rhsp.isOne}", "replaceWLhs(nodep)");
TREEOP ("AstDivS {$lhsp, $rhsp.isOne}", "replaceWLhs(nodep)");
TREEOP ("AstMul {operandIsPowTwo($lhsp), $rhsp}", "replaceMulShift(nodep)"); // a*2^n -> a<<n
TREEOP ("AstMul {operandIsPowTwo($lhsp), operandsSameSize($lhsp,,$rhsp)}", "replaceMulShift(nodep)"); // a*2^n -> a<<n
TREEOP ("AstDiv {$lhsp, operandIsPowTwo($rhsp)}", "replaceDivShift(nodep)"); // a/2^n -> a>>n
TREEOP ("AstModDiv{$lhsp, operandIsPowTwo($rhsp)}", "replaceModAnd(nodep)"); // a % 2^n -> a&(2^n-1)
TREEOP ("AstPow {operandIsTwo($lhsp), $rhsp}", "replacePowShift(nodep)"); // 2**a == 1<<a

View File

@ -326,11 +326,11 @@ private:
}
}
bool mightElimVar(AstVar* nodep) {
return (!nodep->isSigPublic() // Can't elim publics!
&& !nodep->isIO() && !nodep->isClassMember()
&& ((nodep->isTemp() && !nodep->isTrace())
|| (nodep->isParam() && !nodep->isTrace() && !v3Global.opt.xmlOnly())
|| m_elimUserVars)); // Post-Trace can kill most anything
if (nodep->isSigPublic()) return false; // Can't elim publics!
if (nodep->isIO() || nodep->isClassMember()) return false;
if (nodep->isTemp() && !nodep->isTrace()) return true;
if (nodep->isParam() && !nodep->isTrace() && !v3Global.opt.xmlOnly()) return true;
return m_elimUserVars; // Post-Trace can kill most anything
}
void deadCheckScope() {

View File

@ -171,8 +171,8 @@ private:
UINFO(4, " Act: " << m_activep << endl);
UINFO(4, " Act: " << oldactivep << endl);
// Make a new sensitivity list, which is the combination of both blocks
AstNodeSenItem* sena = m_activep->sensesp()->sensesp()->cloneTree(true);
AstNodeSenItem* senb = oldactivep->sensesp()->sensesp()->cloneTree(true);
AstSenItem* sena = m_activep->sensesp()->sensesp()->cloneTree(true);
AstSenItem* senb = oldactivep->sensesp()->sensesp()->cloneTree(true);
AstSenTree* treep = new AstSenTree(m_activep->fileline(), sena);
if (senb) treep->addSensesp(senb);
if (AstSenTree* storep = oldactivep->sensesStorep()) {
@ -373,7 +373,8 @@ private:
m_nextDlyp
= VN_CAST(nodep->nextp(), AssignDly); // Next assignment in same block, maybe NULL.
if (m_cfuncp) {
nodep->v3error("Unsupported: Delayed assignment inside public function/task");
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Delayed assignment inside public function/task");
}
if (VN_IS(nodep->lhsp(), ArraySel)
|| (VN_IS(nodep->lhsp(), Sel)
@ -385,7 +386,9 @@ private:
"loops (non-delayed is ok - see docs)");
}
AstBasicDType* basicp = lhsp->dtypep()->basicp();
if (basicp && basicp->isEventValue()) nodep->v3error("Unsupported: event arrays");
if (basicp && basicp->isEventValue()) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: event arrays");
}
if (newlhsp) {
nodep->lhsp(newlhsp);
} else {

View File

@ -154,6 +154,58 @@ public:
}
}
void emitParams(AstNodeModule* modp, bool init, bool* firstp, string& sectionr) {
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstVar* varp = VN_CAST(nodep, Var)) {
if (varp->isParam() && (varp->isUsedParam() || varp->isSigPublic())) {
if (!init && sectionr != "") {
puts(sectionr);
sectionr = "";
}
UASSERT_OBJ(varp->valuep(), nodep, "No init for a param?");
// These should be static const values, however microsloth VC++ doesn't
// support them. They also cause problems with GDB under GCC2.95.
if (varp->isWide()) { // Unsupported for output
if (!init) {
putsDecoration("// enum WData " + varp->nameProtect() + " //wide");
}
} else if (varp->isString()) {
if (init) {
emitCtorSep(firstp);
puts(protect("var_" + varp->name()) + " (");
iterateAndNextNull(varp->valuep());
puts(")");
} else {
puts("const std::string " + protect("var_" + varp->name()) + ";\n");
}
} else if (!VN_IS(varp->valuep(), Const)) { // Unsupported for output
// putsDecoration("// enum ..... "+varp->nameProtect()
// +"not simple value, see variable above instead");
} else if (VN_IS(varp->dtypep(), BasicDType)
&& VN_CAST(varp->dtypep(), BasicDType)
->isOpaque()) { // Can't put out e.g. doubles
} else {
if (init) {
emitCtorSep(firstp);
puts(protect("var_" + varp->name()) + " (");
iterateAndNextNull(varp->valuep());
puts(")");
} else {
// enum
puts(varp->isQuad() ? "enum _QData" : "enum _IData");
puts("" + varp->nameProtect() + " { " + varp->nameProtect() + " = ");
iterateAndNextNull(varp->valuep());
puts("};\n");
// var
puts(varp->isQuad() ? "const QData " : "const IData ");
puts(protect("var_" + varp->name()) + ";\n");
}
}
}
}
}
}
struct CmpName {
inline bool operator()(const AstNode* lhsp, const AstNode* rhsp) const {
return lhsp->name() < rhsp->name();
@ -598,7 +650,7 @@ public:
}
virtual void visit(AstFFlush* nodep) VL_OVERRIDE {
if (!nodep->filep()) {
puts("Verilated::flushCall();\n");
puts("Verilated::runFlushCallbacks();\n");
} else {
puts("if (");
iterateAndNextNull(nodep->filep());
@ -865,41 +917,51 @@ public:
}
virtual void visit(AstMulS* nodep) VL_OVERRIDE {
if (nodep->widthWords() > VL_MULS_MAX_WORDS) {
nodep->v3error("Unsupported: Signed multiply of "
<< nodep->width()
<< " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
nodep->v3warn(
E_UNSUPPORTED,
"Unsupported: Signed multiply of "
<< nodep->width()
<< " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
}
visit(VN_CAST(nodep, NodeBiop));
}
virtual void visit(AstPow* nodep) VL_OVERRIDE {
if (nodep->widthWords() > VL_MULS_MAX_WORDS) {
nodep->v3error("Unsupported: Power of "
<< nodep->width()
<< " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
nodep->v3warn(
E_UNSUPPORTED,
"Unsupported: Power of "
<< nodep->width()
<< " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
}
visit(VN_CAST(nodep, NodeBiop));
}
virtual void visit(AstPowSS* nodep) VL_OVERRIDE {
if (nodep->widthWords() > VL_MULS_MAX_WORDS) {
nodep->v3error("Unsupported: Power of "
<< nodep->width()
<< " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
nodep->v3warn(
E_UNSUPPORTED,
"Unsupported: Power of "
<< nodep->width()
<< " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
}
visit(VN_CAST(nodep, NodeBiop));
}
virtual void visit(AstPowSU* nodep) VL_OVERRIDE {
if (nodep->widthWords() > VL_MULS_MAX_WORDS) {
nodep->v3error("Unsupported: Power of "
<< nodep->width()
<< " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
nodep->v3warn(
E_UNSUPPORTED,
"Unsupported: Power of "
<< nodep->width()
<< " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
}
visit(VN_CAST(nodep, NodeBiop));
}
virtual void visit(AstPowUS* nodep) VL_OVERRIDE {
if (nodep->widthWords() > VL_MULS_MAX_WORDS) {
nodep->v3error("Unsupported: Power of "
<< nodep->width()
<< " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
nodep->v3warn(
E_UNSUPPORTED,
"Unsupported: Power of "
<< nodep->width()
<< " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h");
}
visit(VN_CAST(nodep, NodeBiop));
}
@ -1057,7 +1119,7 @@ public:
void emitConstant(AstConst* nodep, AstVarRef* assigntop, const string& assignString) {
// Put out constant set to the specified variable, or given variable in a string
if (nodep->num().isFourState()) {
nodep->v3error("Unsupported: 4-state numbers in this context");
nodep->v3warn(E_UNSUPPORTED, "Unsupported: 4-state numbers in this context");
} else if (nodep->num().isString()) {
putbs("std::string(");
putsQuoted(nodep->num().toString());
@ -2301,6 +2363,8 @@ void EmitCImp::emitCtorImp(AstNodeModule* modp) {
}
emitVarCtors(&first);
if (modp->isTop() && v3Global.opt.mtasks()) emitMTaskVertexCtors(&first);
string section("");
emitParams(modp, true, &first, section /*ref*/);
puts(" {\n");
emitCellCtors(modp);
emitSensitives();
@ -3031,35 +3095,8 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
ofp()->putsPrivate(false); // public:
emitVarList(modp->stmtsp(), EVL_CLASS_PAR, "",
section /*ref*/); // Only those that are non-CONST
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (const AstVar* varp = VN_CAST(nodep, Var)) {
if (varp->isParam() && (varp->isUsedParam() || varp->isSigPublic())) {
if (section != "") {
puts(section);
section = "";
}
UASSERT_OBJ(varp->valuep(), nodep, "No init for a param?");
// These should be static const values, however microsloth VC++ doesn't
// support them. They also cause problems with GDB under GCC2.95.
if (varp->isWide()) { // Unsupported for output
putsDecoration("// enum WData " + varp->nameProtect() + " //wide");
} else if (!VN_IS(varp->valuep(), Const)) { // Unsupported for output
// putsDecoration("// enum ..... "+varp->nameProtect()
// +"not simple value, see variable above instead");
} else if (VN_IS(varp->dtypep(), BasicDType)
&& VN_CAST(varp->dtypep(), BasicDType)
->isOpaque()) { // Can't put out e.g. doubles
} else {
puts("enum ");
puts(varp->isQuad() ? "_QData" : "_IData");
puts("" + varp->nameProtect() + " { " + varp->nameProtect() + " = ");
iterateAndNextNull(varp->valuep());
puts("};");
}
puts("\n");
}
}
}
bool first = true;
emitParams(modp, false, &first, section /*ref*/);
if (!VN_IS(modp, Class)) {
puts("\n// CONSTRUCTORS\n");

View File

@ -42,7 +42,8 @@ class EmitCInlines : EmitCBaseVisitor {
}
virtual void visit(AstCNew* nodep) VL_OVERRIDE {
checkHeavy(nodep);
if (v3Global.opt.savable()) v3error("Unsupported: --savable with dynamic new");
if (v3Global.opt.savable())
v3warn(E_UNSUPPORTED, "Unsupported: --savable with dynamic new");
iterateChildren(nodep);
}
virtual void visit(AstDumpCtl* nodep) VL_OVERRIDE {

View File

@ -163,8 +163,9 @@ class CMakeEmitter {
+ "_c.cpp");
if (v3Global.opt.systemC()) {
if (v3Global.opt.traceFormat() != TraceFormat::VCD) {
v3error("Unsupported: This trace format is not supported in SystemC, "
"use VCD format.");
v3warn(E_UNSUPPORTED,
"Unsupported: This trace format is not supported in SystemC, "
"use VCD format.");
}
global.push_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceLang()
+ ".cpp");

View File

@ -332,12 +332,7 @@ class EmitCSyms : EmitCBaseVisitor {
virtual void visit(AstVar* nodep) VL_OVERRIDE {
nameCheck(nodep);
iterateChildren(nodep);
if (nodep->isSigUserRdPublic()
// The VPI functions require a pointer to allow modification,
// but parameters are constants
&& !nodep->isParam()) {
m_modVars.push_back(make_pair(m_modp, nodep));
}
if (nodep->isSigUserRdPublic()) { m_modVars.push_back(make_pair(m_modp, nodep)); }
}
virtual void visit(AstCoverDecl* nodep) VL_OVERRIDE {
// Assign numbers to all bins, so we know how big of an array to use
@ -794,16 +789,38 @@ void EmitCSyms::emitSymImp() {
}
puts(protect("__Vscope_" + it->second.m_scopeName) + ".varInsert(__Vfinal,");
putsQuoted(protect(it->second.m_varBasePretty));
puts(", &(");
std::string varName;
if (modp->isTop()) {
puts(protectIf(scopep->nameDotless() + "p", scopep->protect()));
puts("->");
varName += (protectIf(scopep->nameDotless() + "p", scopep->protect()) + "->");
} else {
puts(protectIf(scopep->nameDotless(), scopep->protect()));
puts(".");
varName += (protectIf(scopep->nameDotless(), scopep->protect()) + ".");
}
puts(varp->nameProtect());
puts("), ");
if (varp->isParam()) {
varName += protect("var_" + varp->name());
} else {
varName += protect(varp->name());
}
if (varp->isParam()) {
if (varp->vlEnumType() == "VLVT_STRING") {
puts(", const_cast<void*>(static_cast<const void*>(");
puts(varName.c_str());
puts(".c_str())), ");
} else {
puts(", const_cast<void*>(static_cast<const void*>(&(");
puts(varName.c_str());
puts("))), ");
}
} else {
puts(", &(");
puts(varName.c_str());
puts("), ");
}
puts(varp->isParam() ? "true" : "false");
puts(", ");
puts(varp->vlEnumType()); // VLVT_UINT32 etc
puts(",");
puts(varp->vlEnumDir()); // VLVD_IN etc

View File

@ -104,8 +104,9 @@ public:
putMakeClassEntry(of, v3Global.opt.traceSourceBase() + "_c.cpp");
if (v3Global.opt.systemC()) {
if (v3Global.opt.traceFormat() != TraceFormat::VCD) {
v3error("Unsupported: This trace format is not supported "
"in SystemC, use VCD format.");
v3warn(E_UNSUPPORTED,
"Unsupported: This trace format is not supported "
"in SystemC, use VCD format.");
} else {
putMakeClassEntry(of, v3Global.opt.traceSourceLang() + ".cpp");
}

View File

@ -160,9 +160,6 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
puts(")");
}
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->sensesp(), nodep->rhsp());
}
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
putfs(nodep, "");
puts(nodep->edgeType().verilogKwd());

View File

@ -44,6 +44,7 @@ public:
EC_FATALSRC, // Kill the program, for internal source errors
EC_ERROR, // General error out, can't suppress
// Boolean information we track per-line, but aren't errors
I_CELLDEFINE, // Inside cell define from `celldefine/`endcelldefine
I_COVERAGE, // Coverage is on/off from /*verilator coverage_on/off*/
I_TRACING, // Tracing is on/off from /*verilator tracing_on/off*/
I_LINT, // All lint messages
@ -51,6 +52,7 @@ public:
// Error codes:
E_DETECTARRAY, // Error: Unsupported: Can't detect changes on arrayed variable
E_PORTSHORT, // Error: Output port is connected to a constant, electrical short
E_UNSUPPORTED, // Error: Unsupported (generally)
E_TASKNSVAR, // Error: Task I/O not simple
//
// Warning codes:
@ -140,9 +142,9 @@ public:
// Leading spaces indicate it can't be disabled.
" MIN", " INFO", " FATAL", " FATALEXIT", " FATALSRC", " ERROR",
// Boolean
" I_COVERAGE", " I_TRACING", " I_LINT", " I_DEF_NETTYPE_WIRE",
" I_CELLDEFINE", " I_COVERAGE", " I_TRACING", " I_LINT", " I_DEF_NETTYPE_WIRE",
// Errors
"DETECTARRAY", "PORTSHORT", "TASKNSVAR",
"DETECTARRAY", "PORTSHORT", "UNSUPPORTED", "TASKNSVAR",
// Warnings
" EC_FIRST_WARN",
"ALWCOMBORDER", "ASSIGNDLY", "ASSIGNIN",
@ -170,7 +172,9 @@ public:
return names[m_e];
}
// Warnings that default to off
bool defaultsOff() const { return (m_e == IMPERFECTSCH || styleError()); }
bool defaultsOff() const {
return (m_e == IMPERFECTSCH || m_e == I_CELLDEFINE || styleError());
}
// Warnings that warn about nasty side effects
bool dangerous() const { return (m_e == COMBDLY); }
// Warnings we'll present to the user as errors

View File

@ -206,8 +206,8 @@ private:
UINFO(8, " Wordize ASSIGN(CONST) " << nodep << endl);
// -> {for each_word{ ASSIGN(WORDSEL(wide,#),WORDSEL(CONST,#))}}
if (rhsp->num().isFourState()) {
rhsp->v3error( // LCOV_EXCL_LINE // impossible?
"Unsupported: 4-state numbers in this context");
rhsp->v3warn(E_UNSUPPORTED, // LCOV_EXCL_LINE // impossible?
"Unsupported: 4-state numbers in this context");
}
for (int w = 0; w < nodep->widthWords(); w++) {
addWordAssign(

View File

@ -218,6 +218,8 @@ public:
bool lastWarnWaived() { return m_waive; }
// Specific flag ACCESSORS/METHODS
bool celldefineOn() const { return m_warnOn.test(V3ErrorCode::I_CELLDEFINE); }
void celldefineOn(bool flag) { warnOn(V3ErrorCode::I_CELLDEFINE, flag); }
bool coverageOn() const { return m_warnOn.test(V3ErrorCode::I_COVERAGE); }
void coverageOn(bool flag) { warnOn(V3ErrorCode::I_COVERAGE, flag); }
bool tracingOn() const { return m_warnOn.test(V3ErrorCode::I_TRACING); }
@ -265,6 +267,21 @@ public:
&& m_lastLineno == rhs.m_lastLineno && m_lastColumn == rhs.m_lastColumn
&& m_filenameno == rhs.m_filenameno && m_warnOn == rhs.m_warnOn);
}
// Returns -1 if (*this) should come before rhs after sorted. 1 for the opposite case. 0 for
// equivalent.
int operatorCompare(const FileLine& rhs) const {
if (m_filenameno != rhs.m_filenameno) return (m_filenameno < rhs.m_filenameno) ? -1 : 1;
if (m_firstLineno != rhs.m_firstLineno)
return (m_firstLineno < rhs.m_firstLineno) ? -1 : 1;
if (m_firstColumn != rhs.m_firstColumn)
return (m_firstColumn < rhs.m_firstColumn) ? -1 : 1;
if (m_lastLineno != rhs.m_lastLineno) return (m_lastLineno < rhs.m_lastLineno) ? -1 : 1;
if (m_lastColumn != rhs.m_lastColumn) return (m_lastColumn < rhs.m_lastColumn) ? -1 : 1;
for (size_t i = 0; i < m_warnOn.size(); ++i) {
if (m_warnOn[i] != rhs.m_warnOn[i]) return (m_warnOn[i] < rhs.m_warnOn[i]) ? -1 : 1;
}
return 0; // (*this) and rhs are equivalent
}
private:
string warnContext(bool secondary) const;

View File

@ -483,8 +483,6 @@ private:
iterateNewStmt(nodep, "User C Function", "User C Function");
}
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
// Note we look at only AstSenItems, not AstSenGate's
// The gating term of a AstSenGate is normal logic
m_inSenItem = true;
if (m_logicVertexp) { // Already under logic; presumably a SenGate
iterateChildren(nodep);
@ -493,11 +491,6 @@ private:
}
m_inSenItem = false;
}
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
// First handle the clock part will be handled in a minute by visit AstSenItem
// The logic gating term is dealt with as logic
iterateNewStmt(nodep, "Clock gater", "Clock gater");
}
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
bool lastslow = m_inSlow;
m_inSlow = true;

View File

@ -116,8 +116,8 @@ private:
virtual void visit(AstUdpTable* nodep) VL_OVERRIDE {
if (!v3Global.opt.bboxUnsup()) {
// If we support primitives, update V3Undriven to remove special case
nodep->v3error("Unsupported: Verilog 1995 UDP Tables. "
"Use --bbox-unsup to ignore tables.");
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Verilog 1995 UDP Tables. "
"Use --bbox-unsup to ignore tables.");
}
}
@ -358,8 +358,8 @@ private:
&& !VN_IS(exprp, VarRef)
// V3Const will collapse the SEL with the one we're about to make
&& !VN_IS(exprp, Concat) && !VN_IS(exprp, Sel)) {
nodep->v3error("Unsupported: Per-bit array instantiations with output "
"connections to non-wires.");
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Per-bit array instantiations "
"with output connections to non-wires.");
// Note spec allows more complicated matches such as slices and such
}
exprp = new AstSel(exprp->fileline(), exprp, pinwidth * m_instSelNum, pinwidth);
@ -375,7 +375,8 @@ private:
V3Const::constifyParamsEdit(arrselp->rhsp());
const AstConst* constp = VN_CAST(arrselp->rhsp(), Const);
if (!constp) {
nodep->v3error(
nodep->v3warn(
E_UNSUPPORTED,
"Unsupported: Non-constant index when passing interface to module");
return;
}
@ -442,7 +443,6 @@ private:
string newname = varrefp->name() + "__BRA__" + cvtToStr(i + offset) + "__KET__";
AstVarXRef* newVarXRefp = new AstVarXRef(nodep->fileline(), newname, "", true);
newVarXRefp->varp(newp->modVarp());
newVarXRefp->dtypep(newp->modVarp()->dtypep());
newp->exprp()->unlinkFrBack()->deleteTree();
newp->exprp(newVarXRefp);
if (!prevPinp) {

View File

@ -75,12 +75,13 @@ public:
void LinkCellsGraph::loopsMessageCb(V3GraphVertex* vertexp) {
if (LinkCellsVertex* vvertexp = dynamic_cast<LinkCellsVertex*>(vertexp)) {
vvertexp->modp()->v3error(
"Unsupported: Recursive multiple modules (module instantiates "
"something leading back to itself): "
<< vvertexp->modp()->prettyNameQ() << endl
<< V3Error::warnMore()
<< "... note: self-recursion (module instantiating itself directly) is supported.");
vvertexp->modp()->v3warn(E_UNSUPPORTED,
"Unsupported: Recursive multiple modules (module instantiates "
"something leading back to itself): "
<< vvertexp->modp()->prettyNameQ() << endl
<< V3Error::warnMore()
<< "... note: self-recursion (module instantiating itself "
"directly) is supported.");
V3Error::abortIfErrors();
} else { // Everything should match above, but...
v3fatalSrc("Recursive instantiations");

View File

@ -67,7 +67,6 @@
#include "V3SymTable.h"
#include "V3Graph.h"
#include "V3Ast.h"
#include "V3ParseImp.h"
#include "V3String.h"
#include <algorithm>
@ -540,8 +539,8 @@ private:
}
public:
VSymEnt* findDotted(VSymEnt* lookupSymp, const string& dotname, string& baddot,
VSymEnt*& okSymp) {
VSymEnt* findDotted(FileLine* /*refLocationp*/, VSymEnt* lookupSymp, const string& dotname,
string& baddot, VSymEnt*& okSymp) {
// Given a dotted hierarchy name, return where in scope it is
// Note when dotname=="" we just fall through and return lookupSymp
UINFO(8, " dottedFind se" << cvtToHex(lookupSymp) << " '" << dotname << "'" << endl);
@ -711,35 +710,6 @@ class LinkDotFindVisitor : public AstNVisitor {
// METHODS
int debug() { return LinkDotState::debug(); }
AstConst* parseParamLiteral(FileLine* fl, const string& literal) const {
bool success = false;
if (literal[0] == '"') {
// This is a string
string v = literal.substr(1, literal.find('"', 1) - 1);
return new AstConst(fl, AstConst::VerilogStringLiteral(), v);
} else if (literal.find_first_of(".eEpP") != string::npos) {
// This may be a real
double v = V3ParseImp::parseDouble(literal.c_str(), literal.length(), &success);
if (success) return new AstConst(fl, AstConst::RealDouble(), v);
}
if (!success) {
// This is either an integer or an error
// We first try to convert it as C literal. If strtol returns
// 0 this is either an error or 0 was parsed. But in any case
// we will try to parse it as a verilog literal, hence having
// the false negative for 0 is okay. If anything remains in
// the string after the number, this is invalid C and we try
// the Verilog literal parser.
char* endp;
int v = strtol(literal.c_str(), &endp, 0);
if ((v != 0) && (endp[0] == 0)) { // C literal
return new AstConst(fl, AstConst::WidthedValue(), 32, v);
} else { // Try a Verilog literal (fatals if not)
return new AstConst(fl, AstConst::StringToParse(), literal.c_str());
}
}
return NULL;
}
void makeImplicitNew(AstClass* nodep) {
AstFunc* newp = new AstFunc(nodep->fileline(), "new", NULL, NULL);
newp->isConstructor(true);
@ -794,9 +764,10 @@ class LinkDotFindVisitor : public AstNVisitor {
int oldBlockNum = m_blockNum;
int oldModBlockNum = m_modBlockNum;
if (doit && nodep->user2()) {
nodep->v3error("Unsupported: Identically recursive module (module instantiates "
"itself, without changing parameters): "
<< AstNode::prettyNameQ(nodep->origName()));
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Identically recursive module (module instantiates "
"itself, without changing parameters): "
<< AstNode::prettyNameQ(nodep->origName()));
} else if (doit) {
UINFO(4, " Link Module: " << nodep << endl);
UASSERT_OBJ(!nodep->dead(), nodep, "Module in cell tree mislabeled as dead?");
@ -904,7 +875,7 @@ class LinkDotFindVisitor : public AstNVisitor {
string scope = origname.substr(0, pos);
string baddot;
VSymEnt* okSymp;
aboveSymp = m_statep->findDotted(aboveSymp, scope, baddot, okSymp);
aboveSymp = m_statep->findDotted(nodep->fileline(), aboveSymp, scope, baddot, okSymp);
UASSERT_OBJ(aboveSymp, nodep,
"Can't find cell insertion point at " << AstNode::prettyNameQ(baddot)
<< " in: " << nodep->prettyNameQ());
@ -935,7 +906,7 @@ class LinkDotFindVisitor : public AstNVisitor {
string ident = dottedname.substr(pos + strlen("__DOT__"));
string baddot;
VSymEnt* okSymp;
aboveSymp = m_statep->findDotted(aboveSymp, dotted, baddot, okSymp);
aboveSymp = m_statep->findDotted(nodep->fileline(), aboveSymp, dotted, baddot, okSymp);
UASSERT_OBJ(aboveSymp, nodep,
"Can't find cellinline insertion point at "
<< AstNode::prettyNameQ(baddot) << " in: " << nodep->prettyNameQ());
@ -1036,10 +1007,16 @@ class LinkDotFindVisitor : public AstNVisitor {
UASSERT_OBJ(m_curSymp && m_modSymp, nodep, "Var not under module?");
iterateChildren(nodep);
if (m_ftaskp && nodep->isParam()) {
nodep->v3error("Unsupported: Parameters in functions."); // Big3 unsupported too
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Parameters in functions"); // Big3 unsupported too
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return;
}
if (nodep->isFuncLocal() && nodep->lifetime().isStatic()) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'static' function/task variables");
} else if (nodep->isClassMember() && nodep->lifetime().isStatic()) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'static' class members");
}
if (!m_statep->forScopeCreation()) {
// Find under either a task or the module's vars
VSymEnt* foundp = m_curSymp->findIdFallback(nodep->name());
@ -1129,7 +1106,8 @@ class LinkDotFindVisitor : public AstNVisitor {
= new AstVar(nodep->fileline(), AstVarType(AstVarType::GPARAM),
nodep->name(), nodep);
string svalue = v3Global.opt.parameter(nodep->name());
if (AstNode* valuep = parseParamLiteral(nodep->fileline(), svalue)) {
if (AstNode* valuep
= AstConst::parseParamLiteral(nodep->fileline(), svalue)) {
newp->valuep(valuep);
UINFO(9, " replace parameter " << nodep << endl);
UINFO(9, " with " << newp << endl);
@ -1482,13 +1460,15 @@ class LinkDotScopeVisitor : public AstNVisitor {
string ifcellname = dtypep->cellName();
string baddot;
VSymEnt* okSymp;
VSymEnt* cellSymp = m_statep->findDotted(m_modSymp, ifcellname, baddot, okSymp);
VSymEnt* cellSymp = m_statep->findDotted(nodep->fileline(), m_modSymp, ifcellname,
baddot, okSymp);
UASSERT_OBJ(cellSymp, nodep,
"No symbol for interface cell: " << nodep->prettyNameQ(ifcellname));
UINFO(5, " Found interface cell: se" << cvtToHex(cellSymp) << " "
<< cellSymp->nodep() << endl);
if (dtypep->modportName() != "") {
VSymEnt* mpSymp = m_statep->findDotted(m_modSymp, ifcellname, baddot, okSymp);
VSymEnt* mpSymp = m_statep->findDotted(nodep->fileline(), m_modSymp,
ifcellname, baddot, okSymp);
UASSERT_OBJ(mpSymp, nodep,
"No symbol for interface modport: "
<< nodep->prettyNameQ(dtypep->modportName()));
@ -1537,7 +1517,8 @@ class LinkDotScopeVisitor : public AstNVisitor {
= refp ? refp->name() : (inl.size() ? (inl + xrefp->name()) : xrefp->name());
string baddot;
VSymEnt* okSymp;
symp = m_statep->findDotted(m_modSymp, scopename, baddot, okSymp);
symp = m_statep->findDotted(nodep->rhsp()->fileline(), m_modSymp, scopename,
baddot, okSymp);
if (inl == "") break;
inl = LinkDotState::removeLastInlineScope(inl);
}
@ -1560,7 +1541,8 @@ class LinkDotScopeVisitor : public AstNVisitor {
string scopename = refp ? refp->varp()->name() : xrefp->dotted() + "." + xrefp->name();
string baddot;
VSymEnt* okSymp;
VSymEnt* symp = m_statep->findDotted(m_modSymp, scopename, baddot, okSymp);
VSymEnt* symp = m_statep->findDotted(nodep->lhsp()->fileline(), m_modSymp, scopename,
baddot, okSymp);
UASSERT_OBJ(symp, nodep, "No symbol for interface alias lhs");
UINFO(5, " Found a linked scope LHS: " << scopename << " se" << cvtToHex(symp)
<< " " << symp->nodep() << endl);
@ -1619,7 +1601,7 @@ class LinkDotIfaceVisitor : public AstNVisitor {
virtual void visit(AstModportFTaskRef* nodep) VL_OVERRIDE {
UINFO(5, " fif: " << nodep << endl);
iterateChildren(nodep);
if (nodep->isExport()) nodep->v3error("Unsupported: modport export");
if (nodep->isExport()) nodep->v3warn(E_UNSUPPORTED, "Unsupported: modport export");
VSymEnt* symp = m_curSymp->findIdFallback(nodep->name());
if (!symp) {
nodep->v3error("Modport item not found: " << nodep->prettyNameQ());
@ -2026,12 +2008,24 @@ private:
// Generally resolved during Primay, but might be at param time under AstUnlinkedRef
UASSERT_OBJ(m_statep->forPrimary() || m_statep->forPrearray(), nodep,
"ParseRefs should no longer exist");
if (nodep->name() == "this") {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: this");
} else if (nodep->name() == "super") {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: super");
}
DotStates lastStates = m_ds;
bool start = (m_ds.m_dotPos == DP_NONE); // Save, as m_dotp will be changed
if (start) {
m_ds.init(m_curSymp);
// Note m_ds.m_dot remains NULL; this is a reference not under a dot
}
if (nodep->name() == "this") {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: this");
m_ds.m_dotErr = true;
} else if (nodep->name() == "super") {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: super");
m_ds.m_dotErr = true;
}
if (m_ds.m_dotPos == DP_MEMBER) {
// Found a Var, everything following is membership. {scope}.{var}.HERE {member}
AstNode* varEtcp = m_ds.m_dotp->lhsp()->unlinkFrBack();
@ -2077,8 +2071,8 @@ private:
string baddot;
VSymEnt* okSymp = NULL;
if (allowScope) {
foundp = m_statep->findDotted(m_ds.m_dotSymp, nodep->name(), baddot,
okSymp); // Maybe NULL
foundp = m_statep->findDotted(nodep->fileline(), m_ds.m_dotSymp, nodep->name(),
baddot, okSymp); // Maybe NULL
} else {
foundp = m_ds.m_dotSymp->findIdFallback(nodep->name());
}
@ -2311,13 +2305,13 @@ private:
// ignore (t_math_divw)
dotSymp = m_modSymp;
string inl = AstNode::dedotName(nodep->inlinedDots());
dotSymp = m_statep->findDotted(dotSymp, inl, baddot, okSymp);
dotSymp = m_statep->findDotted(nodep->fileline(), dotSymp, inl, baddot, okSymp);
UASSERT_OBJ(dotSymp, nodep,
"Couldn't resolve inlined scope " << AstNode::prettyNameQ(baddot)
<< " in: " << nodep->inlinedDots());
}
dotSymp
= m_statep->findDotted(dotSymp, nodep->dotted(), baddot, okSymp); // Maybe NULL
dotSymp = m_statep->findDotted(nodep->fileline(), dotSymp, nodep->dotted(), baddot,
okSymp); // Maybe NULL
if (!m_statep->forScopeCreation()) {
VSymEnt* foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot);
AstVar* varp = foundp ? foundToVarp(foundp, nodep, nodep->lvalue()) : NULL;
@ -2388,6 +2382,11 @@ private:
}
m_ds = lastStates;
}
virtual void visit(AstWith* nodep) VL_OVERRIDE {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: with statements");
nodep->replaceWith(nodep->funcrefp()->unlinkFrBack());
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstVar* nodep) VL_OVERRIDE {
checkNoDot(nodep);
iterateChildren(nodep);
@ -2460,7 +2459,8 @@ private:
dotSymp = m_modSymp;
string inl = AstNode::dedotName(nodep->inlinedDots());
UINFO(8, " Inlined " << inl << endl);
dotSymp = m_statep->findDotted(dotSymp, inl, baddot, okSymp);
dotSymp
= m_statep->findDotted(nodep->fileline(), dotSymp, inl, baddot, okSymp);
if (!dotSymp) {
okSymp->cellErrorScopes(nodep);
nodep->v3fatalSrc("Couldn't resolve inlined scope "
@ -2468,7 +2468,7 @@ private:
<< " in: " << nodep->inlinedDots());
}
}
dotSymp = m_statep->findDotted(dotSymp, nodep->dotted(), baddot,
dotSymp = m_statep->findDotted(nodep->fileline(), dotSymp, nodep->dotted(), baddot,
okSymp); // Maybe NULL
}
VSymEnt* foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot);
@ -2611,6 +2611,12 @@ private:
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
UINFO(5, " " << nodep << endl);
checkNoDot(nodep);
if (nodep->classMethod() && nodep->lifetime().isStatic()) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'static' class method");
}
if (nodep->isExtern()) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: extern class methods");
}
VSymEnt* oldCurSymp = m_curSymp;
{
m_ftaskp = nodep;
@ -2627,7 +2633,7 @@ private:
if (AstClassExtends* eitemp = VN_CAST(itemp, ClassExtends)) {
// Replace abstract reference with hard pointer
// Will need later resolution when deal with parameters
eitemp->v3error("Unsupported: class extends");
eitemp->v3warn(E_UNSUPPORTED, "Unsupported: class extends");
}
}
VSymEnt* oldCurSymp = m_curSymp;

View File

@ -178,7 +178,7 @@ private:
AstNodeVarRef* varrefp;
if (m_unsupportedHere || !(varrefp = VN_CAST(nodep->rhsp(), VarRef))) {
nodep->v3error("Unsupported: Incrementation in this context.");
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Incrementation in this context.");
return;
}

View File

@ -173,6 +173,17 @@ private:
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstWait* nodep) VL_OVERRIDE {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: wait statements");
// Statements we'll just execute immediately; equivalent to if they followed this
if (AstNode* bodysp = nodep->bodysp()) {
bodysp->unlinkFrBackWithNext();
nodep->replaceWith(bodysp);
} else {
nodep->unlinkFrBack();
}
VL_DO_DANGLING(nodep->deleteTree(), nodep);
}
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
// Don't need to track AstRepeat/AstFor as they have already been converted
AstWhile* lastLoopp = m_loopp;
@ -260,7 +271,7 @@ private:
AstJumpLabel* labelp = findAddLabel(beginp, false);
nodep->addNextHere(new AstJumpGo(nodep->fileline(), labelp));
} else {
nodep->v3error("Unsupported: disable fork");
nodep->v3warn(E_UNSUPPORTED, "Unsupported: disable fork");
}
nodep->unlinkFrBack();
VL_DO_DANGLING(pushDeletep(nodep), nodep);

View File

@ -228,8 +228,9 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
varp->primaryIO(true);
}
if (varp->direction().isRefOrConstRef()) {
varp->v3error("Unsupported: ref/const ref as primary input/output: "
<< varp->prettyNameQ());
varp->v3warn(E_UNSUPPORTED,
"Unsupported: ref/const ref as primary input/output: "
<< varp->prettyNameQ());
}
if (varp->isIO() && v3Global.opt.systemC()) {
varp->sc(true);

View File

@ -196,8 +196,8 @@ private:
if (v3Global.opt.publicFlatRW()) {
switch (nodep->varType()) {
case AstVarType::VAR:
case AstVarType::PORT:
case AstVarType::VAR: // FALLTHRU
case AstVarType::PORT: // FALLTHRU
case AstVarType::WIRE: nodep->sigUserRWPublic(true); break;
default: break;
}
@ -228,8 +228,8 @@ private:
new AstInitial(fl, new AstAssign(fl, new AstVarRef(fl, nodep->name(), true),
nodep->valuep()->unlinkFrBack())));
} else if (!m_ftaskp && nodep->isNonOutput()) {
nodep->v3error(
"Unsupported: Default value on module input: " << nodep->prettyNameQ());
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Default value on module input: "
<< nodep->prettyNameQ());
nodep->valuep()->unlinkFrBack()->deleteTree();
} // 3. Under modules, it's an initial value to be loaded at time 0 via an AstInitial
else if (m_valueModp) {
@ -251,7 +251,7 @@ private:
// What breaks later is we don't have a Scope/Cell representing
// the interface to attach to
if (m_modp->level() <= 2) {
nodep->v3error("Unsupported: Interfaced port on top level module");
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Interfaced port on top level module");
}
}
}
@ -385,11 +385,50 @@ private:
// FOREACH(array,loopvars,body)
// -> BEGIN(declare vars, loopa=lowest; WHILE(loopa<=highest, ... body))
// nodep->dumpTree(cout, "-foreach-old:");
AstNode* newp = nodep->bodysp()->unlinkFrBackWithNext();
AstNode* arrayp = nodep->arrayp();
int dimension = 1;
UINFO(9, "FOREACH " << nodep << endl);
// nodep->dumpTree(cout, "-foreach-in:");
AstNode* newp = nodep->bodysp();
if (newp) newp->unlinkFrBackWithNext();
// Separate iteration vars from base from variable
// Input:
// v--- arrayp
// 1. DOT(DOT(first, second), ASTSELLOOPVARS(third, var0..var1))
// Separated:
// bracketp = ASTSELLOOPVARS(...)
// arrayp = DOT(DOT(first, second), third)
// firstVarp = var0..var1
// Other examples
// 2. ASTSELBIT(first, var0))
// 3. ASTSELLOOPVARS(first, var0..var1))
// 4. DOT(DOT(first, second), ASTSELBIT(third, var0))
AstNode* bracketp = nodep->arrayp();
AstNode* firstVarsp = NULL;
while (AstDot* dotp = VN_CAST(bracketp, Dot)) { bracketp = dotp->rhsp(); }
if (AstSelBit* selp = VN_CAST(bracketp, SelBit)) {
firstVarsp = selp->rhsp()->unlinkFrBackWithNext();
selp->replaceWith(selp->fromp()->unlinkFrBack());
VL_DO_DANGLING(selp->deleteTree(), selp);
} else if (AstSelLoopVars* selp = VN_CAST(bracketp, SelLoopVars)) {
firstVarsp = selp->elementsp()->unlinkFrBackWithNext();
selp->replaceWith(selp->fromp()->unlinkFrBack());
VL_DO_DANGLING(selp->deleteTree(), selp);
} else {
nodep->v3error(
"Syntax error; foreach missing bracketed index variable (IEEE 1800-2017 12.7.3)");
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return;
}
AstNode* arrayp = nodep->arrayp(); // Maybe different node since bracketp looked
if (!VN_IS(arrayp, ParseRef)) {
// Code below needs to use other then attributes to figure out the bounds
// Also need to deal with queues, etc
arrayp->v3warn(E_UNSUPPORTED, "Unsupported: foreach on non-simple variable reference");
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
return;
}
// Split into for loop
// Must do innermost (last) variable first
AstNode* firstVarsp = nodep->varsp()->unlinkFrBackWithNext();
int dimension = 1;
AstNode* lastVarsp = firstVarsp;
while (lastVarsp->nextp()) {
lastVarsp = lastVarsp->nextp();
@ -498,26 +537,55 @@ private:
}
virtual void visit(AstPrintTimeScale* nodep) VL_OVERRIDE {
// Inlining may change hierarchy, so just save timescale where needed
cleanFileline(nodep);
iterateChildren(nodep);
nodep->name(m_modp->name());
nodep->timeunit(m_modp->timeunit());
}
virtual void visit(AstSFormatF* nodep) VL_OVERRIDE {
cleanFileline(nodep);
iterateChildren(nodep);
nodep->timeunit(m_modp->timeunit());
}
virtual void visit(AstTime* nodep) VL_OVERRIDE {
cleanFileline(nodep);
iterateChildren(nodep);
nodep->timeunit(m_modp->timeunit());
}
virtual void visit(AstTimeD* nodep) VL_OVERRIDE {
cleanFileline(nodep);
iterateChildren(nodep);
nodep->timeunit(m_modp->timeunit());
}
virtual void visit(AstTimeImport* nodep) VL_OVERRIDE {
cleanFileline(nodep);
iterateChildren(nodep);
nodep->timeunit(m_modp->timeunit());
}
virtual void visit(AstTimingControl* nodep) VL_OVERRIDE {
cleanFileline(nodep);
iterateChildren(nodep);
AstAlways* alwaysp = VN_CAST(nodep->backp(), Always);
if (alwaysp && alwaysp->keyword() == VAlwaysKwd::ALWAYS_COMB) {
alwaysp->v3error("Timing control statements not legal under always_comb\n"
<< nodep->warnMore() << "... Suggest use a normal 'always'");
} else if (alwaysp && !alwaysp->sensesp()) {
// Verilator is still ony supporting SenTrees under an always,
// so allow the parser to handle everything and shim to
// historical AST here
if (AstSenTree* sensesp = nodep->sensesp()) {
sensesp->unlinkFrBackWithNext();
alwaysp->sensesp(sensesp);
}
if (nodep->stmtsp()) alwaysp->addStmtp(nodep->stmtsp()->unlinkFrBackWithNext());
} else {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: timing control statement in this location\n"
<< nodep->warnMore()
<< "... Suggest have one timing control statement "
<< "per procedure, at the top of the procedure");
}
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
virtual void visit(AstNode* nodep) VL_OVERRIDE {
// Default: Just iterate

View File

@ -108,9 +108,16 @@ private:
virtual void visit(AstVar* nodep) VL_OVERRIDE {
iterateChildren(nodep);
if (m_classp && !nodep->isParam()) nodep->varType(AstVarType::MEMBER);
if (m_classp && nodep->isParam()) nodep->v3error("Unsupported: class parameter");
if (m_classp && nodep->isParam())
nodep->v3warn(E_UNSUPPORTED, "Unsupported: class parameter");
if (m_ftaskp) nodep->funcLocal(true);
if (nodep->lifetime().isNone()) nodep->lifetime(m_lifetime);
if (nodep->lifetime().isNone()) {
if (nodep->isFuncLocal() && nodep->isIO()) {
nodep->lifetime(VLifetime::AUTOMATIC);
} else {
nodep->lifetime(m_lifetime);
}
}
if (nodep->isSigModPublic()) {
nodep->sigModPublic(false); // We're done with this attribute
m_modp->modPublic(true); // Avoid flattening if signals are exposed
@ -129,7 +136,7 @@ private:
if (m_classp) nodep->classMethod(true);
VLifetime origLifetime = m_lifetime;
{
if (!nodep->lifetime().isNone()) m_lifetime = nodep->lifetime();
m_lifetime = nodep->lifetime();
if (m_lifetime.isNone()) m_lifetime = VLifetime::AUTOMATIC;
m_ftaskp = nodep;
iterateChildren(nodep);
@ -167,8 +174,9 @@ private:
addwherep = addwherep->backp();
}
if (!VN_IS(addwherep, Always)) { // Assertion perhaps?
sensp->v3error("Unsupported: Non-single-bit pos/negedge clock statement under "
"some complicated block");
sensp->v3warn(E_UNSUPPORTED,
"Unsupported: Non-single-bit pos/negedge clock statement under "
"some complicated block");
addwherep = m_modp;
}
addwherep->addNext(newvarp);
@ -207,12 +215,9 @@ private:
&& !VN_IS(nodep->sensp(), EnumItemRef) // V3Const will cleanup
&& !nodep->isIllegal()) {
if (debug()) nodep->dumpTree(cout, "-tree: ");
nodep->v3error("Unsupported: Complex statement in sensitivity list");
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Complex statement in sensitivity list");
}
}
virtual void visit(AstSenGate* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
nodep->v3fatalSrc("SenGates shouldn't be in tree yet");
}
virtual void visit(AstNodePreSel* nodep) VL_OVERRIDE {
if (!nodep->attrp()) {
@ -239,7 +244,7 @@ private:
} else if (VN_IS(basefromp, Replicate)) {
// From {...}[...] syntax in IEEE 2017
if (basefromp) { UINFO(1, " Related node: " << basefromp << endl); }
nodep->v3error("Unsupported: Select of concatenation");
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Select of concatenation");
nodep = NULL;
} else {
if (basefromp) { UINFO(1, " Related node: " << basefromp << endl); }
@ -309,13 +314,13 @@ private:
break;
case 'm': // %m - auto insert "name"
if (isScan) {
nodep->v3error("Unsupported: %m in $fscanf");
nodep->v3warn(E_UNSUPPORTED, "Unsupported: %m in $fscanf");
fmt = "";
}
break;
case 'l': // %l - auto insert "library"
if (isScan) {
nodep->v3error("Unsupported: %l in $fscanf");
nodep->v3warn(E_UNSUPPORTED, "Unsupported: %l in $fscanf");
fmt = "";
}
if (m_modp) fmt = VString::quotePercent(m_modp->prettyName());
@ -395,7 +400,8 @@ private:
void expectDescriptor(AstNode* nodep, AstNodeVarRef* filep) {
if (!filep) {
nodep->v3error("Unsupported: $fopen/$fclose/$f* descriptor must be a simple variable");
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: $fopen/$fclose/$f* descriptor must be a simple variable");
}
if (filep && filep->varp()) filep->varp()->attrFileDescr(true);
}

View File

@ -108,11 +108,11 @@ private:
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildrenConst(nodep); }
public:
// Set user1 on all referenced AstVar
void operator()(AstNode* node) {
AstNode::user1ClearTree();
iterate(node);
}
// Remove marks from AstVars (clear user1)
void clear() { AstNode::user1ClearTree(); }
// Mark all AstVars referenced by setting user1
void mark(AstNode* node) { iterate(node); }
};
class MergeCondVisitor : public AstNVisitor {
@ -239,6 +239,7 @@ private:
m_mgCondp = NULL;
m_mgLastp = NULL;
m_mgNextp = NULL;
m_markVars.clear();
}
void addToList(AstNode* nodep, AstNode* condp) {
@ -248,7 +249,7 @@ private:
m_mgFirstp = nodep;
m_mgCondp = condp;
m_listLenght = 0;
m_markVars(condp);
m_markVars.mark(condp);
}
// Add node
++m_listLenght;
@ -268,9 +269,14 @@ private:
if (AstNodeCond* const condp = extractCond(rhsp)) {
if (!m_checkMergeable(nodep)) {
// Node not mergeable.
// Finish current list if any, do not start a new one.
if (m_mgFirstp) mergeEnd();
return;
// If no current list, then this node is just special, move on.
if (!m_mgFirstp) return;
// Otherwise finish current list
mergeEnd();
// Finishing the list might make the node mergeable again, e.g.
// if the reason we could not merge was due to the condition
// being assigned, so check again and stop only if still no.
if (!m_checkMergeable(nodep)) return;
}
if (m_mgFirstp && (m_mgNextp != nodep || !condp->condp()->sameTree(m_mgCondp))) {
// Node in different list, or has different condition.
@ -282,7 +288,7 @@ private:
} else if (m_mgFirstp) {
// RHS is not a conditional, but we already started a list.
// If it's a 1-bit signal, and a mergeable assignment, try reduced forms
if (rhsp->widthMin() == 1 && m_checkMergeable(nodep)) {
if (m_mgNextp == nodep && rhsp->widthMin() == 1 && m_checkMergeable(nodep)) {
// Is it a 'lhs = cond & value' or 'lhs = value & cond'?
if (AstAnd* const andp = VN_CAST(rhsp, And)) {
if (andp->lhsp()->sameTree(m_mgCondp) || andp->rhsp()->sameTree(m_mgCondp)) {
@ -320,6 +326,7 @@ public:
m_mgLastp = NULL;
m_mgNextp = NULL;
m_listLenght = 0;
m_markVars.clear();
iterate(nodep);
}
virtual ~MergeCondVisitor() {

View File

@ -294,7 +294,7 @@ void V3Options::addForceInc(const string& filename) { m_forceIncs.push_back(file
void V3Options::addArg(const string& arg) { m_impp->m_allArgs.push_back(arg); }
string V3Options::allArgsString() {
string V3Options::allArgsString() const {
string out;
for (std::list<string>::const_iterator it = m_impp->m_allArgs.begin();
it != m_impp->m_allArgs.end(); ++it) {
@ -568,7 +568,7 @@ string V3Options::getenvVERILATOR_ROOT() {
}
bool V3Options::systemCSystemWide() {
#ifdef HAVE_SYSTEMC_H
#ifdef HAVE_SYSTEMC
return true;
#else
return false;
@ -603,8 +603,9 @@ void V3Options::notify() {
if (allPublic()) {
// We always call protect() on names, we don't check if public or not
// Hence any external references wouldn't be able to find the refed public object.
cmdfl->v3error("Unsupported: Using --protect-ids with --public\n" //
+ V3Error::warnMore() + "... Suggest remove --public.");
cmdfl->v3warn(E_UNSUPPORTED, "Unsupported: Using --protect-ids with --public\n" //
+ V3Error::warnMore()
+ "... Suggest remove --public.");
}
if (trace()) {
cmdfl->v3warn(INSECURE,
@ -644,7 +645,8 @@ void V3Options::notify() {
if (m_outputSplitCTrace < 0) m_outputSplitCTrace = m_outputSplit;
if (v3Global.opt.main() && v3Global.opt.systemC()) {
cmdfl->v3error("--main not usable with SystemC. Suggest see examples for sc_main().");
cmdfl->v3warn(E_UNSUPPORTED,
"--main not usable with SystemC. Suggest see examples for sc_main().");
}
}
@ -824,85 +826,168 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
if (sw[0] == '-' && sw[1] == '-') ++sw;
bool hadSwitchPart1 = true;
// Single switches
// clang-format off
if (!strcmp(sw, "-E")) { m_preprocOnly = true; }
else if ( onoffb(sw, "-MMD", bflag/*ref*/)) { m_makeDepend = bflag; }
else if ( onoff (sw, "-MP", flag/*ref*/)) { m_makePhony = flag; }
else if (!strcmp(sw, "-P")) { m_preprocNoLine = true; }
else if ( onoff (sw, "-assert", flag/*ref*/)) { m_assert = flag; }
else if ( onoff (sw, "-autoflush", flag/*ref*/)) { m_autoflush = flag; }
else if ( onoff (sw, "-bbox-sys", flag/*ref*/)) { m_bboxSys = flag; }
else if ( onoff (sw, "-bbox-unsup", flag/*ref*/)) { m_bboxUnsup = flag; }
else if (!strcmp(sw, "-build")) { m_build = true; }
else if (!strcmp(sw, "-cc")) { m_outFormatOk = true; m_systemC = false; }
else if ( onoff (sw, "-cdc", flag/*ref*/)) { m_cdc = flag; }
else if ( onoff (sw, "-coverage", flag/*ref*/)) { coverage(flag); }
else if ( onoff (sw, "-coverage-line", flag/*ref*/)){ m_coverageLine = flag; }
else if ( onoff (sw, "-coverage-toggle", flag/*ref*/)){ m_coverageToggle = flag; }
else if ( onoff (sw, "-coverage-underscore", flag/*ref*/)){ m_coverageUnderscore = flag; }
else if ( onoff (sw, "-coverage-user", flag/*ref*/)){ m_coverageUser = flag; }
else if ( onoff (sw, "-covsp", flag/*ref*/)) { } // TBD
else if (!strcmp(sw, "-debug-abort")) { V3Error::vlAbort(); } // Undocumented, see also --debug-sigsegv
else if ( onoff (sw, "-debug-check", flag/*ref*/)) { m_debugCheck = flag; }
else if ( onoff (sw, "-debug-collision", flag/*ref*/)) { m_debugCollision = flag; } // Undocumented
else if ( onoff (sw, "-debug-leak", flag/*ref*/)) { m_debugLeak = flag; }
else if ( onoff (sw, "-debug-nondeterminism", flag/*ref*/)){ m_debugNondeterminism = flag; }
else if ( onoff (sw, "-debug-partition", flag/*ref*/)){ m_debugPartition = flag; } // Undocumented
else if ( onoff (sw, "-debug-protect", flag/*ref*/)){ m_debugProtect = flag; } // Undocumented
else if ( onoff (sw, "-debug-self-test", flag/*ref*/)){ m_debugSelfTest = flag; } // Undocumented
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, "-decoration", flag/*ref*/)) { m_decoration = flag; }
else if ( onoff (sw, "-dpi-hdr-only", flag/*ref*/)) { m_dpiHdrOnly = flag; }
else if ( onoff (sw, "-dump-defines", flag/*ref*/)) { m_dumpDefines = flag; }
else if ( onoff (sw, "-dump-tree", flag/*ref*/)) { m_dumpTree = flag ? 3 : 0; } // Also see --dump-treei
else if ( onoff (sw, "-dump-tree-addrids", flag/*ref*/)){ m_dumpTreeAddrids = flag; }
else if ( onoff (sw, "-exe", flag/*ref*/)) { m_exe = flag; }
else if ( onoff (sw, "-flatten", flag/*ref*/)) { m_flatten = flag; }
else if ( onoff (sw, "-ignc", flag/*ref*/)) { m_ignc = flag; }
else if ( onoff (sw, "-inhibit-sim", flag/*ref*/)) { m_inhibitSim = flag; }
else if ( onoff (sw, "-lint-only", flag/*ref*/)) { m_lintOnly = flag; }
else if ( onoff (sw, "-main", flag/*ref*/)) { m_main = flag; } // Undocumented future
else if (!strcmp(sw, "-no-pins64")) { m_pinsBv = 33; }
else if ( onoff (sw, "-order-clock-delay", flag/*ref*/)) { m_orderClockDly = flag; }
else if (!strcmp(sw, "-pins64")) { m_pinsBv = 65; }
else if ( onoff (sw, "-pins-sc-uint", flag/*ref*/)) { m_pinsScUint = flag; if (!m_pinsScBigUint) m_pinsBv = 65; }
else if ( onoff (sw, "-pins-sc-biguint", flag/*ref*/)){ m_pinsScBigUint = flag; m_pinsBv = 513; }
else if ( onoff (sw, "-pins-uint8", flag/*ref*/)) { m_pinsUint8 = flag; }
else if ( onoff (sw, "-pp-comments", flag/*ref*/)) { m_ppComments = flag; }
else if (!strcmp(sw, "-private")) { m_public = false; }
else if ( onoff (sw, "-prof-cfuncs", flag/*ref*/)) { m_profCFuncs = flag; }
else if ( onoff (sw, "-profile-cfuncs", flag/*ref*/)) { m_profCFuncs = flag; } // Undocumented, for backward compat
else if ( onoff (sw, "-prof-threads", flag/*ref*/)) { m_profThreads = flag; }
else if ( onoff (sw, "-protect-ids", flag/*ref*/)) { m_protectIds = flag; }
else if ( onoff (sw, "-public", flag/*ref*/)) { m_public = flag; }
else if ( onoff (sw, "-public-flat-rw", flag/*ref*/) ) { m_publicFlatRW = flag; v3Global.dpi(true); }
else if (!strncmp(sw, "-pvalue+", strlen("-pvalue+"))) { addParameter(string(sw+strlen("-pvalue+")), false); }
else if ( onoff (sw, "-quiet-exit", flag/*ref*/)) { m_quietExit = flag; }
else if ( onoff (sw, "-relative-cfuncs", flag/*ref*/)) { m_relativeCFuncs = flag; }
else if ( onoff (sw, "-relative-includes", flag/*ref*/)) { m_relativeIncludes = flag; }
else if ( onoff (sw, "-report-unoptflat", flag/*ref*/)) { m_reportUnoptflat = flag; }
else if ( onoff (sw, "-savable", flag/*ref*/)) { m_savable = flag; }
else if (!strcmp(sw, "-sc")) { m_outFormatOk = true; m_systemC = true; }
else if ( onoffb(sw, "-skip-identical", bflag/*ref*/)) { m_skipIdentical = bflag; }
else if ( onoff (sw, "-stats", flag/*ref*/)) { m_stats = flag; }
else if ( onoff (sw, "-stats-vars", flag/*ref*/)) { m_statsVars = flag; m_stats |= flag; }
else if ( onoff (sw, "-structs-unpacked", flag/*ref*/)) { m_structsPacked = flag; }
else if (!strcmp(sw, "-sv")) { m_defaultLanguage = V3LangCode::L1800_2005; }
else if ( onoff (sw, "-threads-coarsen", flag/*ref*/)) { m_threadsCoarsen = flag; } // Undocumented, debug
else if ( onoff (sw, "-trace", flag/*ref*/)) { m_trace = flag; }
else if ( onoff (sw, "-trace-coverage", flag/*ref*/)) { m_traceCoverage = flag; }
else if ( onoff (sw, "-trace-params", flag/*ref*/)) { m_traceParams = flag; }
else if ( onoff (sw, "-trace-structs", flag/*ref*/)) { m_traceStructs = flag; }
else if ( onoff (sw, "-trace-underscore", flag/*ref*/)) { m_traceUnderscore = flag; }
else if ( onoff (sw, "-underline-zero", flag/*ref*/)) { m_underlineZero = flag; } // Undocumented, old Verilator-2
else if ( onoff (sw, "-verilate", flag/*ref*/)) { m_verilate = flag; }
else if ( onoff (sw, "-vpi", flag/*ref*/)) { m_vpi = flag; }
else if ( onoff (sw, "-Wpedantic", flag/*ref*/)) { m_pedantic = flag; }
else if ( onoff (sw, "-x-initial-edge", flag/*ref*/)) { m_xInitialEdge = flag; }
else if ( onoff (sw, "-xml-only", flag/*ref*/)) { m_xmlOnly = flag; }
else { hadSwitchPart1 = false; }
// clang-format on
if (!strcmp(sw, "-E")) {
m_preprocOnly = true;
} else if (onoffb(sw, "-MMD", bflag /*ref*/)) {
m_makeDepend = bflag;
} else if (onoff(sw, "-MP", flag /*ref*/)) {
m_makePhony = flag;
} else if (!strcmp(sw, "-P")) {
m_preprocNoLine = true;
} else if (onoff(sw, "-assert", flag /*ref*/)) {
m_assert = flag;
} else if (onoff(sw, "-autoflush", flag /*ref*/)) {
m_autoflush = flag;
} else if (onoff(sw, "-bbox-sys", flag /*ref*/)) {
m_bboxSys = flag;
} else if (onoff(sw, "-bbox-unsup", flag /*ref*/)) {
FileLine::globalWarnOff(V3ErrorCode::E_UNSUPPORTED, true);
m_bboxUnsup = flag;
} else if (!strcmp(sw, "-build")) {
m_build = true;
} else if (!strcmp(sw, "-cc")) {
m_outFormatOk = true;
m_systemC = false;
} else if (onoff(sw, "-cdc", flag /*ref*/)) {
m_cdc = flag;
} else if (onoff(sw, "-coverage", flag /*ref*/)) {
coverage(flag);
} else if (onoff(sw, "-coverage-line", flag /*ref*/)) {
m_coverageLine = flag;
} else if (onoff(sw, "-coverage-toggle", flag /*ref*/)) {
m_coverageToggle = flag;
} else if (onoff(sw, "-coverage-underscore", flag /*ref*/)) {
m_coverageUnderscore = flag;
} else if (onoff(sw, "-coverage-user", flag /*ref*/)) {
m_coverageUser = flag;
} else if (!strcmp(sw, "-debug-abort")) { // Undocumented, see also --debug-sigsegv
V3Error::vlAbort();
} else if (onoff(sw, "-debug-check", flag /*ref*/)) {
m_debugCheck = flag;
} else if (onoff(sw, "-debug-collision", flag /*ref*/)) { // Undocumented
m_debugCollision = flag;
} else if (onoff(sw, "-debug-exit-parse", flag /*ref*/)) { // Undocumented
m_debugExitParse = flag;
} else if (onoff(sw, "-debug-leak", flag /*ref*/)) {
m_debugLeak = flag;
} else if (onoff(sw, "-debug-nondeterminism", flag /*ref*/)) {
m_debugNondeterminism = flag;
} else if (onoff(sw, "-debug-partition", flag /*ref*/)) { // Undocumented
m_debugPartition = flag;
} else if (onoff(sw, "-debug-protect", flag /*ref*/)) { // Undocumented
m_debugProtect = flag;
} else if (onoff(sw, "-debug-self-test", flag /*ref*/)) { // Undocumented
m_debugSelfTest = flag;
} else if (!strcmp(sw, "-debug-sigsegv")) { // Undocumented, see also --debug-abort
throwSigsegv();
} else if (!strcmp(sw, "-debug-fatalsrc")) { // Undocumented, see also --debug-abort
v3fatalSrc("--debug-fatal-src");
} else if (onoff(sw, "-decoration", flag /*ref*/)) {
m_decoration = flag;
} else if (onoff(sw, "-dpi-hdr-only", flag /*ref*/)) {
m_dpiHdrOnly = flag;
} else if (onoff(sw, "-dump-defines", flag /*ref*/)) {
m_dumpDefines = flag;
} else if (onoff(sw, "-dump-tree", flag /*ref*/)) { // Also see --dump-treei
m_dumpTree = flag ? 3 : 0;
} else if (onoff(sw, "-dump-tree-addrids", flag /*ref*/)) {
m_dumpTreeAddrids = flag;
} else if (onoff(sw, "-exe", flag /*ref*/)) {
m_exe = flag;
} else if (onoff(sw, "-flatten", flag /*ref*/)) {
m_flatten = flag;
} else if (onoff(sw, "-ignc", flag /*ref*/)) {
m_ignc = flag;
} else if (onoff(sw, "-inhibit-sim", flag /*ref*/)) {
m_inhibitSim = flag;
} else if (onoff(sw, "-lint-only", flag /*ref*/)) {
m_lintOnly = flag;
} else if (onoff(sw, "-main", flag /*ref*/)) { // Undocumented future
m_main = flag;
} else if (!strcmp(sw, "-no-pins64")) {
m_pinsBv = 33;
} else if (onoff(sw, "-order-clock-delay", flag /*ref*/)) {
m_orderClockDly = flag;
} else if (!strcmp(sw, "-pins64")) {
m_pinsBv = 65;
} else if (onoff(sw, "-pins-sc-uint", flag /*ref*/)) {
m_pinsScUint = flag;
if (!m_pinsScBigUint) m_pinsBv = 65;
} else if (onoff(sw, "-pins-sc-biguint", flag /*ref*/)) {
m_pinsScBigUint = flag;
m_pinsBv = 513;
} else if (onoff(sw, "-pins-uint8", flag /*ref*/)) {
m_pinsUint8 = flag;
} else if (onoff(sw, "-pp-comments", flag /*ref*/)) {
m_ppComments = flag;
} else if (!strcmp(sw, "-private")) {
m_public = false;
} else if (onoff(sw, "-prof-cfuncs", flag /*ref*/)) {
m_profCFuncs = flag;
} else if (onoff(sw, "-profile-cfuncs", flag /*ref*/)) { // Undocumented, renamed
m_profCFuncs = flag;
} else if (onoff(sw, "-prof-threads", flag /*ref*/)) {
m_profThreads = flag;
} else if (onoff(sw, "-protect-ids", flag /*ref*/)) {
m_protectIds = flag;
} else if (onoff(sw, "-public", flag /*ref*/)) {
m_public = flag;
} else if (onoff(sw, "-public-flat-rw", flag /*ref*/)) {
m_publicFlatRW = flag;
v3Global.dpi(true);
} else if (!strncmp(sw, "-pvalue+", strlen("-pvalue+"))) {
addParameter(string(sw + strlen("-pvalue+")), false);
} else if (onoff(sw, "-quiet-exit", flag /*ref*/)) {
m_quietExit = flag;
} else if (onoff(sw, "-relative-cfuncs", flag /*ref*/)) {
m_relativeCFuncs = flag;
} else if (onoff(sw, "-relative-includes", flag /*ref*/)) {
m_relativeIncludes = flag;
} else if (onoff(sw, "-report-unoptflat", flag /*ref*/)) {
m_reportUnoptflat = flag;
} else if (onoff(sw, "-savable", flag /*ref*/)) {
m_savable = flag;
} else if (!strcmp(sw, "-sc")) {
m_outFormatOk = true;
m_systemC = true;
} else if (onoffb(sw, "-skip-identical", bflag /*ref*/)) {
m_skipIdentical = bflag;
} else if (onoff(sw, "-stats", flag /*ref*/)) {
m_stats = flag;
} else if (onoff(sw, "-stats-vars", flag /*ref*/)) {
m_statsVars = flag;
m_stats |= flag;
} else if (onoff(sw, "-structs-unpacked", flag /*ref*/)) {
m_structsPacked = flag;
} else if (!strcmp(sw, "-sv")) {
m_defaultLanguage = V3LangCode::L1800_2005;
} else if (onoff(sw, "-threads-coarsen", flag /*ref*/)) { // Undocumented, debug
m_threadsCoarsen = flag;
} else if (onoff(sw, "-trace", flag /*ref*/)) {
m_trace = flag;
} else if (onoff(sw, "-trace-coverage", flag /*ref*/)) {
m_traceCoverage = flag;
} else if (onoff(sw, "-trace-params", flag /*ref*/)) {
m_traceParams = flag;
} else if (onoff(sw, "-trace-structs", flag /*ref*/)) {
m_traceStructs = flag;
} else if (onoff(sw, "-trace-underscore", flag /*ref*/)) {
m_traceUnderscore = flag;
} else if (onoff(sw, "-underline-zero", flag /*ref*/)) { // Deprecated
m_underlineZero = flag;
} else if (onoff(sw, "-verilate", flag /*ref*/)) {
m_verilate = flag;
} else if (onoff(sw, "-vpi", flag /*ref*/)) {
m_vpi = flag;
} else if (onoff(sw, "-Wpedantic", flag /*ref*/)) {
m_pedantic = flag;
} else if (onoff(sw, "-x-initial-edge", flag /*ref*/)) {
m_xInitialEdge = flag;
} else if (onoff(sw, "-xml-only", flag /*ref*/)) {
m_xmlOnly = flag;
} else {
hadSwitchPart1 = false;
}
if (hadSwitchPart1) {
} else if (!strncmp(sw, "-O", 2)) {
@ -1552,6 +1637,7 @@ V3Options::V3Options() {
m_coverageUser = false;
m_debugCheck = false;
m_debugCollision = false;
m_debugExitParse = false;
m_debugLeak = true;
m_debugNondeterminism = false;
m_debugPartition = false;

View File

@ -239,6 +239,7 @@ private:
bool m_coverageUser; // main switch: --coverage-func
bool m_debugCheck; // main switch: --debug-check
bool m_debugCollision; // main switch: --debug-collision
bool m_debugExitParse; // main switch: --debug-exit-parse
bool m_debugLeak; // main switch: --debug-leak
bool m_debugNondeterminism; // main switch: --debug-nondeterminism
bool m_debugPartition; // main switch: --debug-partition
@ -438,6 +439,7 @@ public:
bool coverageUser() const { return m_coverageUser; }
bool debugCheck() const { return m_debugCheck; }
bool debugCollision() const { return m_debugCollision; }
bool debugExitParse() const { return m_debugExitParse; }
bool debugLeak() const { return m_debugLeak; }
bool debugNondeterminism() const { return m_debugNondeterminism; }
bool debugPartition() const { return m_debugPartition; }
@ -596,7 +598,7 @@ public:
// METHODS (from main)
static string version();
static string argString(int argc, char** argv); ///< Return list of arguments as simple string
string allArgsString(); ///< Return all passed arguments as simple string
string allArgsString() const; ///< Return all passed arguments as simple string
void bin(const string& flag) { m_bin = flag; }
void parseOpts(FileLine* fl, int argc, char** argv);
void parseOptsList(FileLine* fl, const string& optdir, int argc, char** argv);

View File

@ -965,8 +965,8 @@ private:
m_activep = NULL;
m_topScopep = nodep;
m_scopetopp = nodep->scopep();
// Find sentree's
m_finder.main(m_topScopep);
// Find global SenTrees
m_finder.init(m_topScopep);
// ProcessDomainsIterate will use these when it needs to move
// something to a combodomain. This saves a ton of find() operations.
AstSenTree* combp
@ -1282,8 +1282,7 @@ static bool domainsExclusive(const AstSenTree* fromp, const AstSenTree* top) {
const AstSenItem* fromSenListp = VN_CAST(fromp->sensesp(), SenItem);
const AstSenItem* toSenListp = VN_CAST(top->sensesp(), SenItem);
// If clk gating is ever reenabled, we may need to update this to handle
// AstSenGate also.
UASSERT_OBJ(fromSenListp, fromp, "sensitivity list item is not an AstSenItem");
UASSERT_OBJ(toSenListp, top, "sensitivity list item is not an AstSenItem");
@ -1531,7 +1530,7 @@ void OrderVisitor::processDomainsIterate(OrderEitherVertex* vertexp) {
fromVertexp->domainp()->dumpTree(cout);
} // LCOV_EXCL_STOP
AstSenTree* newtreep = domainp->cloneTree(false);
AstNodeSenItem* newtree2p = fromVertexp->domainp()->sensesp()->cloneTree(true);
AstSenItem* newtree2p = fromVertexp->domainp()->sensesp()->cloneTree(true);
UASSERT_OBJ(newtree2p, fromVertexp->domainp(),
"No senitem found under clocked domain");
newtreep->addSensesp(newtree2p);

View File

@ -33,6 +33,7 @@
#include "V3Os.h"
#include <cerrno>
#include <climits> // PATH_MAX (especially on FreeBSD)
#include <cstdarg>
#include <dirent.h>
#include <fstream>

View File

@ -176,6 +176,19 @@ private:
}
return string("z") + cvtToStr(num);
}
AstNodeDType* arraySubDTypep(AstNodeDType* nodep) {
// If an unpacked array, return the subDTypep under it
if (AstUnpackArrayDType* adtypep = VN_CAST(nodep, UnpackArrayDType)) {
return adtypep->subDTypep();
}
// We have not resolved parameter of the child yet, so still
// have BracketArrayDType's. We'll presume it'll end up as assignment
// compatible (or V3Width will complain).
if (AstBracketArrayDType* adtypep = VN_CAST(nodep, BracketArrayDType)) {
return adtypep->subDTypep();
}
return NULL;
}
void collectPins(CloneMap* clonemapp, AstNodeModule* modp) {
// Grab all I/O so we can remap our pins later
for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
@ -585,7 +598,7 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
pinp->v3error("Attempted parameter setting of non-parameter: Param "
<< pinp->prettyNameQ() << " of " << nodep->prettyNameQ());
} else if (VN_IS(pinp->exprp(), InitArray)
&& VN_IS(modvarp->subDTypep(), UnpackArrayDType)) {
&& arraySubDTypep(modvarp->subDTypep())) {
// Array assigned to array
AstNode* exprp = pinp->exprp();
longname += "_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp);
@ -647,10 +660,8 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
AstVar* modvarp = pinp->modVarp();
if (modvarp->isIfaceRef()) {
AstIfaceRefDType* portIrefp = VN_CAST(modvarp->subDTypep(), IfaceRefDType);
if (!portIrefp && VN_IS(modvarp->subDTypep(), UnpackArrayDType)) {
portIrefp
= VN_CAST(VN_CAST(modvarp->subDTypep(), UnpackArrayDType)->subDTypep(),
IfaceRefDType);
if (!portIrefp && arraySubDTypep(modvarp->subDTypep())) {
portIrefp = VN_CAST(arraySubDTypep(modvarp->subDTypep()), IfaceRefDType);
}
AstIfaceRefDType* pinIrefp = NULL;
@ -662,34 +673,20 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
} else if (exprp && exprp->op1p() && VN_IS(exprp->op1p(), VarRef)
&& VN_CAST(exprp->op1p(), VarRef)->varp()
&& VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()
&& VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(),
UnpackArrayDType)
&& VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(),
UnpackArrayDType)
->subDTypep()
&& VN_CAST(VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(),
UnpackArrayDType)
->subDTypep(),
IfaceRefDType)) {
pinIrefp = VN_CAST(VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(),
UnpackArrayDType)
->subDTypep(),
IfaceRefDType);
&& arraySubDTypep(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep())
&& VN_CAST(
arraySubDTypep(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()),
IfaceRefDType)) {
pinIrefp = VN_CAST(
arraySubDTypep(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()),
IfaceRefDType);
} else if (exprp && VN_IS(exprp, VarRef) && VN_CAST(exprp, VarRef)->varp()
&& VN_CAST(exprp, VarRef)->varp()->subDTypep()
&& VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(),
UnpackArrayDType)
&& VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(),
UnpackArrayDType)
->subDTypep()
&& VN_CAST(VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(),
UnpackArrayDType)
->subDTypep(),
&& arraySubDTypep(VN_CAST(exprp, VarRef)->varp()->subDTypep())
&& VN_CAST(arraySubDTypep(VN_CAST(exprp, VarRef)->varp()->subDTypep()),
IfaceRefDType)) {
pinIrefp = VN_CAST(
VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), UnpackArrayDType)
->subDTypep(),
IfaceRefDType);
pinIrefp = VN_CAST(arraySubDTypep(VN_CAST(exprp, VarRef)->varp()->subDTypep()),
IfaceRefDType);
}
UINFO(9, " portIfaceRef " << portIrefp << endl);

View File

@ -100,7 +100,7 @@ AstRange* V3ParseGrammar::scrubRange(AstNodeRange* nrangep) {
}
if (nrangep && nrangep->nextp()) {
// Not supported by at least 2 of big 3
nrangep->nextp()->v3error("Unsupported: Multidimensional cells/interfaces.");
nrangep->nextp()->v3warn(E_UNSUPPORTED, "Unsupported: Multidimensional cells/interfaces.");
nrangep->nextp()->unlinkFrBackWithNext()->deleteTree();
}
return VN_CAST(nrangep, Range);
@ -120,8 +120,6 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstNodeRange* nra
if (rangep && isPacked) {
arrayp
= new AstPackArrayDType(rangep->fileline(), VFlagChildDType(), arrayp, rangep);
} else if (VN_IS(nrangep, QueueRange)) {
arrayp = new AstQueueDType(nrangep->fileline(), VFlagChildDType(), arrayp, NULL);
} else if (rangep
&& (VN_IS(rangep->leftp(), Unbounded)
|| VN_IS(rangep->rightp(), Unbounded))) {
@ -132,12 +130,11 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstNodeRange* nra
rangep);
} else if (VN_IS(nrangep, UnsizedRange)) {
arrayp = new AstUnsizedArrayDType(nrangep->fileline(), VFlagChildDType(), arrayp);
} else if (VN_IS(nrangep, AssocRange)) {
AstAssocRange* arangep = VN_CAST(nrangep, AssocRange);
AstNodeDType* keyp = arangep->keyDTypep();
keyp->unlinkFrBack();
arrayp
= new AstAssocArrayDType(nrangep->fileline(), VFlagChildDType(), arrayp, keyp);
} else if (VN_IS(nrangep, BracketRange)) {
AstBracketRange* arangep = VN_CAST(nrangep, BracketRange);
AstNode* keyp = arangep->elementsp()->unlinkFrBack();
arrayp = new AstBracketArrayDType(nrangep->fileline(), VFlagChildDType(), arrayp,
keyp);
} else {
UASSERT_OBJ(0, nrangep, "Expected range or unsized range");
}
@ -154,7 +151,7 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name,
<< GRAMMARP->m_varIO << " dt=" << (dtypep ? "set" : "") << endl);
if (GRAMMARP->m_varIO == VDirection::NONE && GRAMMARP->m_varDecl == AstVarType::PORT) {
// Just a port list with variable name (not v2k format); AstPort already created
if (dtypep) fileline->v3error("Unsupported: Ranges ignored in port-lists");
if (dtypep) fileline->v3warn(E_UNSUPPORTED, "Unsupported: Ranges ignored in port-lists");
return NULL;
}
if (GRAMMARP->m_varDecl == AstVarType::WREAL) {
@ -173,7 +170,7 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name,
if (GRAMMARP->m_varIO.isAny()) {
type = AstVarType::PORT;
} else {
fileline->v3fatalSrc("Unknown signal type declared");
fileline->v3fatalSrc("Unknown signal type declared: " << type.ascii());
}
}
if (type == AstVarType::GENVAR) {

View File

@ -34,6 +34,8 @@
#include "V3PreShell.h"
#include "V3LanguageWords.h"
#include "V3ParseBison.h" // Generated by bison
#include <sstream>
//======================================================================
@ -43,9 +45,6 @@ V3ParseImp* V3ParseImp::s_parsep = NULL;
int V3ParseSym::s_anonNum = 0;
extern void yyerror(const char*);
extern void yyerrorf(const char* format, ...);
//######################################################################
// Parser constructor
@ -70,27 +69,27 @@ V3ParseImp::~V3ParseImp() {
//######################################################################
// Parser utility methods
void V3ParseImp::ppline(const char* textp) {
// Handle `line directive
void V3ParseImp::lexPpline(const char* textp) {
// Handle lexer `line directive
FileLine* prevFl = copyOrSameFileLine();
int enterExit;
fileline()->lineDirective(textp, enterExit /*ref*/);
lexFileline()->lineDirective(textp, enterExit /*ref*/);
if (enterExit == 1) { // Enter
fileline()->parent(prevFl);
lexFileline()->parent(prevFl);
} else if (enterExit == 2) { // Exit
FileLine* upFl = fileline()->parent();
FileLine* upFl = lexFileline()->parent();
if (upFl) upFl = upFl->parent();
if (upFl) fileline()->parent(upFl);
if (upFl) lexFileline()->parent(upFl);
}
}
void V3ParseImp::timescalePreproc(FileLine* fl, const char* textp) {
void V3ParseImp::lexTimescaleParse(FileLine* fl, const char* textp) {
// Parse `timescale of <number><units> / <number><units>
VTimescale unit;
VTimescale prec;
VTimescale::parseSlashed(fl, textp, unit /*ref*/, prec /*ref*/);
m_timeLastUnit = v3Global.opt.timeComputeUnit(unit);
v3Global.rootp()->timeprecisionMerge(fileline(), prec);
v3Global.rootp()->timeprecisionMerge(fl, prec);
}
void V3ParseImp::timescaleMod(FileLine* fl, AstNodeModule* modp, bool unitSet, double unitVal,
bool precSet, double precVal) {
@ -119,37 +118,39 @@ void V3ParseImp::timescaleMod(FileLine* fl, AstNodeModule* modp, bool unitSet, d
fl->v3error("timeunit/timeprecision not under a module");
}
}
v3Global.rootp()->timeprecisionMerge(fileline(), prec);
v3Global.rootp()->timeprecisionMerge(fl, prec);
}
void V3ParseImp::verilatorCmtLintSave() { m_lintState.push_back(*parsep()->fileline()); }
void V3ParseImp::lexVerilatorCmtLintSave(const FileLine* fl) { m_lexLintState.push_back(*fl); }
void V3ParseImp::verilatorCmtLintRestore() {
if (m_lintState.empty()) {
yyerrorf("/*verilator lint_restore*/ without matching save.");
void V3ParseImp::lexVerilatorCmtLintRestore(FileLine* fl) {
if (m_lexLintState.empty()) {
fl->v3error("/*verilator lint_restore*/ without matching save");
return;
}
parsep()->fileline()->warnStateFrom(m_lintState.back());
m_lintState.pop_back();
fl->warnStateFrom(m_lexLintState.back());
m_lexLintState.pop_back();
}
void V3ParseImp::verilatorCmtLint(const char* textp, bool warnOff) {
void V3ParseImp::lexVerilatorCmtLint(FileLine* fl, const char* textp, bool warnOff) {
const char* sp = textp;
while (*sp && !isspace(*sp)) sp++;
while (*sp && isspace(*sp)) sp++;
while (*sp && !isspace(*sp)) sp++;
while (*sp && isspace(*sp)) sp++;
while (*sp && !isspace(*sp)) ++sp;
while (*sp && isspace(*sp)) ++sp;
while (*sp && !isspace(*sp)) ++sp;
while (*sp && isspace(*sp)) ++sp;
string msg = sp;
string::size_type pos;
if ((pos = msg.find('*')) != string::npos) msg.erase(pos);
if (!(parsep()->fileline()->warnOff(msg, warnOff))) {
if (!parsep()->optFuture(msg)) {
yyerrorf("Unknown verilator lint message code: %s, in %s", msg.c_str(), textp);
// Use parsep()->lexFileline() as want to affect later FileLine's warnings
if (!(parsep()->lexFileline()->warnOff(msg, warnOff))) {
if (!v3Global.opt.isFuture(msg)) {
fl->v3error("Unknown verilator lint message code: '" << msg << "', in '" << textp
<< "'");
}
}
}
void V3ParseImp::verilatorCmtBad(const char* textp) {
void V3ParseImp::lexVerilatorCmtBad(FileLine* fl, const char* textp) {
string cmtparse = textp;
if (cmtparse.substr(0, strlen("/*verilator")) == "/*verilator") {
cmtparse.replace(0, strlen("/*verilator"), "");
@ -157,10 +158,12 @@ void V3ParseImp::verilatorCmtBad(const char* textp) {
while (isspace(cmtparse[0])) cmtparse.replace(0, 1, "");
string cmtname;
for (int i = 0; isalnum(cmtparse[i]); i++) { cmtname += cmtparse[i]; }
if (!parsep()->optFuture(cmtname)) yyerrorf("Unknown verilator comment: %s", textp);
if (!v3Global.opt.isFuture(cmtname)) {
fl->v3error("Unknown verilator comment: '" << textp << "'");
}
}
void V3ParseImp::errorPreprocDirective(const char* textp) {
void V3ParseImp::lexErrorPreprocDirective(FileLine* fl, const char* textp) {
// Find all `preprocessor spelling candidates
// Can't make this static as might get more defines later when read cells
VSpellCheck speller;
@ -171,43 +174,19 @@ void V3ParseImp::errorPreprocDirective(const char* textp) {
}
V3PreShell::candidateDefines(&speller);
string suggest = speller.bestCandidateMsg(textp);
fileline()->v3error("Define or directive not defined: '"
<< textp << "'\n"
<< (suggest.empty() ? "" : fileline()->warnMore() + suggest));
fl->v3error("Define or directive not defined: '"
<< textp << "'\n"
<< (suggest.empty() ? "" : fl->warnMore() + suggest));
}
void V3ParseImp::tag(const char* text) {
if (m_tagNodep) {
string tmp = text + strlen("/*verilator tag ");
string::size_type pos;
if ((pos = tmp.rfind("*/")) != string::npos) { tmp.erase(pos); }
m_tagNodep->tag(tmp);
}
string V3ParseImp::lexParseTag(const char* textp) {
string tmp = textp + strlen("/*verilator tag ");
string::size_type pos;
if ((pos = tmp.rfind("*/")) != string::npos) { tmp.erase(pos); }
return tmp;
}
double V3ParseImp::parseDouble(const char* textp, size_t length, bool* successp) {
char* strgp = new char[length + 1];
char* dp = strgp;
if (successp) *successp = true;
for (const char* sp = textp; sp < (textp + length); ++sp) {
if (*sp != '_') *dp++ = *sp;
}
*dp++ = '\0';
char* endp = strgp;
double d = strtod(strgp, &endp);
size_t parsed_len = endp - strgp;
if (parsed_len != strlen(strgp)) {
if (successp) {
*successp = false;
} else {
yyerrorf("Syntax error parsing real: %s", strgp);
}
}
VL_DO_DANGLING(delete[] strgp, strgp);
return d;
}
double V3ParseImp::parseTimenum(const char* textp) {
double V3ParseImp::lexParseTimenum(const char* textp) {
size_t length = strlen(textp);
char* strgp = new char[length + 1];
char* dp = strgp;
@ -295,8 +274,9 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i
string modname = V3Os::filenameNonExt(modfilename);
UINFO(2, __FUNCTION__ << ": " << modname << (inLibrary ? " [LIB]" : "") << endl);
m_fileline = new FileLine(fileline);
m_fileline->newContent();
m_lexFileline = new FileLine(fileline);
m_lexFileline->newContent();
m_bisonLastFileline = m_lexFileline;
m_inLibrary = inLibrary;
// Preprocess into m_ppBuffer
@ -344,7 +324,7 @@ void V3ParseImp::lexFile(const string& modname) {
// Prepare for lexing
UINFO(3, "Lexing " << modname << endl);
s_parsep = this;
fileline()->warnResetDefault(); // Reenable warnings on each file
lexFileline()->warnResetDefault(); // Reenable warnings on each file
lexDestroy(); // Restart from clean slate.
lexNew();
@ -352,6 +332,246 @@ void V3ParseImp::lexFile(const string& modname) {
if (bisonParse()) v3fatal("Cannot continue\n");
}
void V3ParseImp::tokenPull() {
// Pull token from lex into the pipeline
// This corrupts yylval, must save/restore if required
// Fetch next token from prefetch or real lexer
yylexReadTok(); // sets yylval
m_tokensAhead.push_back(yylval);
}
const V3ParseBisonYYSType* V3ParseImp::tokenPeekp(size_t depth) {
// Look ahead "depth" number of tokens in the input stream
// Returns pointer to token, which is no longer valid after changing m_tokensAhead
while (m_tokensAhead.size() <= depth) tokenPull();
return &m_tokensAhead.at(depth);
}
size_t V3ParseImp::tokenPipeScanParam(size_t depth) {
// Search around IEEE parameter_value_assignment to see if :: follows
// Return location of following token, or input if not found
// yaID [ '#(' ... ')' ]
if (tokenPeekp(depth)->token != '#') return depth;
if (tokenPeekp(depth + 1)->token != '(') return depth;
depth += 2; // Past the (
int parens = 1; // Count first (
while (true) {
int tok = tokenPeekp(depth)->token;
if (tok == 0) {
UINFO(9, "tokenPipeScanParam hit EOF; probably syntax error to come");
break;
} else if (tok == '(') {
++parens;
} else if (tok == ')') {
--parens;
if (parens == 0) {
++depth;
break;
}
}
++depth;
}
return depth;
}
void V3ParseImp::tokenPipeline() {
// called from bison's "yylex", has a "this"
if (m_tokensAhead.empty()) tokenPull(); // corrupts yylval
yylval = m_tokensAhead.front();
m_tokensAhead.pop_front();
int token = yylval.token;
// If a paren, read another
if (token == '(' //
|| token == yCONST__LEX //
|| token == yGLOBAL__LEX //
|| token == yLOCAL__LEX //
|| token == yNEW__LEX //
|| token == ySTATIC__LEX //
|| token == yVIRTUAL__LEX //
|| token == yWITH__LEX //
|| token == yaID__LEX //
) {
if (debugFlex() >= 6) {
cout << " tokenPipeline: reading ahead to find possible strength" << endl;
}
V3ParseBisonYYSType curValue = yylval; // Remember value, as about to read ahead
const V3ParseBisonYYSType* nexttokp = tokenPeekp(0);
int nexttok = nexttokp->token;
yylval = curValue;
// Now potentially munge the current token
if (token == '('
&& (nexttok == ygenSTRENGTH || nexttok == ySUPPLY0 || nexttok == ySUPPLY1)) {
token = yP_PAR__STRENGTH;
} else if (token == yCONST__LEX) {
if (nexttok == yREF) {
token = yCONST__REF;
} else {
token = yCONST__ETC;
}
} else if (token == yGLOBAL__LEX) {
if (nexttok == yCLOCKING) {
token = yGLOBAL__CLOCKING;
} else if (v3Global.opt.pedantic()) {
token = yGLOBAL__ETC;
}
// Avoid 2009 "global" conflicting with old code when we can
else {
token = yaID__LEX;
yylval.strp = V3ParseImp::parsep()->newString("global");
}
} else if (token == yLOCAL__LEX) {
if (nexttok == yP_COLONCOLON) {
token = yLOCAL__COLONCOLON;
} else {
token = yLOCAL__ETC;
}
} else if (token == yNEW__LEX) {
if (nexttok == '(') {
token = yNEW__PAREN;
} else {
token = yNEW__ETC;
}
} else if (token == ySTATIC__LEX) {
if (nexttok == yCONSTRAINT) {
token = ySTATIC__CONSTRAINT;
} else {
token = ySTATIC__ETC;
}
} else if (token == yVIRTUAL__LEX) {
if (nexttok == yCLASS) {
token = yVIRTUAL__CLASS;
} else if (nexttok == yINTERFACE) {
token = yVIRTUAL__INTERFACE;
} else if (nexttok == yaID__ETC //
|| nexttok == yaID__LEX) {
// || nexttok == yaID__aINTERFACE // but we may not know interfaces yet.
token = yVIRTUAL__anyID;
} else {
token = yVIRTUAL__ETC;
}
} else if (token == yWITH__LEX) {
if (nexttok == '(') {
token = yWITH__PAREN;
} else if (nexttok == '[') {
token = yWITH__BRA;
} else if (nexttok == '{') {
token = yWITH__CUR;
} else {
token = yWITH__ETC;
}
} else if (token == yaID__LEX) {
if (nexttok == yP_COLONCOLON) {
token = yaID__CC;
} else if (nexttok == '#') {
V3ParseBisonYYSType curValue = yylval; // Remember value, as about to read ahead
{
size_t depth = tokenPipeScanParam(0);
if (tokenPeekp(depth)->token == yP_COLONCOLON) { token = yaID__CC; }
}
yylval = curValue;
}
}
// If add to above "else if", also add to "if (token" further above
}
yylval.token = token;
// effectively returns yylval
}
void V3ParseImp::tokenPipelineSym() {
// If an id, change the type based on symbol table
// Note above sometimes converts yGLOBAL to a yaID__LEX
tokenPipeline(); // sets yylval
int token = yylval.token;
if (token == yaID__LEX || token == yaID__CC) {
VSymEnt* foundp;
if (VSymEnt* look_underp = V3ParseImp::parsep()->symp()->nextId()) {
UINFO(7, " tokenPipelineSym: next id lookup forced under " << look_underp << endl);
// if (debug() >= 7) V3ParseImp::parsep()->symp()->dump(cout, " -symtree: ");
foundp = look_underp->findIdFallback(*(yylval.strp));
// "consume" it. Must set again if want another token under temp scope
V3ParseImp::parsep()->symp()->nextId(NULL);
} else {
UINFO(7, " tokenPipelineSym: find upward "
<< V3ParseImp::parsep()->symp()->symCurrentp() << " for '"
<< *(yylval.strp) << "'" << endl);
// if (debug()>=9) V3ParseImp::parsep()->symp()->symCurrentp()->dump(cout,
// " -findtree: ", true);
foundp = V3ParseImp::parsep()->symp()->symCurrentp()->findIdFallback(*(yylval.strp));
}
if (foundp) {
AstNode* scp = foundp->nodep();
yylval.scp = scp;
UINFO(7, " tokenPipelineSym: Found " << scp << endl);
if (token == yaID__LEX) { // i.e. not yaID__CC
if (VN_IS(scp, Typedef)) {
token = yaID__aTYPE;
} else if (VN_IS(scp, TypedefFwd)) {
token = yaID__aTYPE;
} else if (VN_IS(scp, Class)) {
token = yaID__aTYPE;
} else if (VN_IS(scp, Package)) {
token = yaID__ETC;
} else {
token = yaID__ETC;
}
}
} else if ((token == yaID__LEX || token == yaID__CC)
&& (*(yylval.strp) == "mailbox" // IEEE-standard class
|| *(yylval.strp) == "process" // IEEE-standard class
|| *(yylval.strp) == "semaphore")) { // IEEE-standard class
yylval.scp = NULL;
if (token == yaID__LEX) token = yaID__aTYPE;
} else { // Not found
yylval.scp = NULL;
if (token == yaID__CC) {
// IEEE does require this, but we may relax this as UVM breaks it, so allow bbox
// for today
if (!v3Global.opt.bboxUnsup()) {
// We'll get a parser error eventually but might not be obvious
// is missing package, and this confuses people
static int warned = false;
if (!warned++) {
yylval.fl->v3error(
"Package/class '" + *yylval.strp
+ "' not found, and needs to be predeclared (IEEE 1800-2017 26.3)");
}
}
} else if (token == yaID__LEX) {
token = yaID__ETC;
}
}
}
yylval.token = token;
// effectively returns yylval
}
int V3ParseImp::tokenToBison() {
// Called as global since bison doesn't have our pointer
tokenPipelineSym(); // sets yylval
m_bisonLastFileline = yylval.fl;
// yylval.scp = NULL; // Symbol table not yet needed - no packages
if (debugFlex() >= 6 || debugBison() >= 6) { // --debugi-flex and --debugi-bison
cout << "tokenToBison " << yylval << endl;
}
return yylval.token;
}
//======================================================================
// V3ParseBisonYYSType functions
std::ostream& operator<<(std::ostream& os, const V3ParseBisonYYSType& rhs) {
os << "TOKEN {" << rhs.fl->filenameLetters() << rhs.fl->asciiLineCol() << "}";
os << "=" << rhs.token << " " << V3ParseImp::tokenName(rhs.token);
if (rhs.token == yaID__ETC //
|| rhs.token == yaID__CC //
|| rhs.token == yaID__LEX //
|| rhs.token == yaID__aTYPE) {
os << " strp='" << *(rhs.strp) << "'";
}
return os;
}
//======================================================================
// V3Parse functions

View File

@ -26,6 +26,7 @@
#include "V3Parse.h"
#include "V3ParseSym.h"
#include <algorithm>
#include <deque>
class V3Lexer;
@ -40,6 +41,62 @@ typedef enum { uniq_NONE, uniq_UNIQUE, uniq_UNIQUE0, uniq_PRIORITY } V3UniqState
typedef enum { iprop_NONE, iprop_CONTEXT, iprop_PURE } V3ImportProperty;
//============================================================================
// Member qualifiers
struct VMemberQualifiers {
union {
uint32_t m_flags;
struct {
uint32_t m_local : 1; // Local class item (ignored until warning implemented)
uint32_t m_protected : 1; // Protected class item (ignored until warning implemented)
uint32_t m_rand : 1; // Rand property/member qualifier (ignored until supported)
uint32_t m_randc : 1; // Randc property/member qualifier (ignored until supported)
uint32_t m_virtual : 1; // Virtual property/method qualifier
uint32_t m_automatic : 1; // Automatic property/method qualifier
uint32_t m_const : 1; // Const property/method qualifier
uint32_t m_static : 1; // Static class method
};
};
static VMemberQualifiers none() {
VMemberQualifiers q;
q.m_flags = 0;
return q;
}
static VMemberQualifiers combine(const VMemberQualifiers& a, const VMemberQualifiers& b) {
VMemberQualifiers q;
q.m_flags = a.m_flags | b.m_flags;
return q;
}
void applyToNodes(AstNodeFTask* nodesp) const {
for (AstNodeFTask* nodep = nodesp; nodep; nodep = VN_CAST(nodep->nextp(), NodeFTask)) {
// Ignored for now: m_local
// Ignored for now: m_protected
if (m_virtual) nodep->isVirtual(true);
if (m_automatic) nodep->lifetime(VLifetime::AUTOMATIC);
if (m_static) nodep->lifetime(VLifetime::STATIC);
if (m_const || m_rand || m_randc) {
nodep->v3error("Syntax error: 'const'/'rand'/'randc' not allowed before "
"function/task declaration");
}
}
}
void applyToNodes(AstVar* nodesp) const {
for (AstVar* nodep = nodesp; nodep; nodep = VN_CAST(nodep->nextp(), Var)) {
// Ignored for now: m_local
// Ignored for now: m_protected
// Ignored for now: m_rand
// Ignored for now: m_randc
if (m_automatic) nodep->lifetime(VLifetime::AUTOMATIC);
if (m_static) nodep->lifetime(VLifetime::STATIC);
if (m_const) nodep->isConst(true);
if (m_virtual) {
nodep->v3error("Syntax error: 'virtual' not allowed before var declaration");
}
}
}
};
//============================================================================
// Parser YYSType, e.g. for parser's yylval
// We can't use bison's %union as we want to pass the fileline with all tokens
@ -54,6 +111,7 @@ struct V3ParseBisonYYSType {
int cint;
double cdouble;
bool cbool;
VMemberQualifiers qualifiers;
V3UniqState uniqstate;
V3ImportProperty iprop;
VSigning::en signstate;
@ -78,7 +136,7 @@ struct V3ParseBisonYYSType {
AstNodeFTask* ftaskp;
AstNodeFTaskRef* ftaskrefp;
AstNodeRange* rangep;
AstNodeSenItem* senitemp;
AstSenItem* senitemp;
AstNodeVarRef* varnodep;
AstPackage* packagep;
AstPackageRef* packagerefp;
@ -92,6 +150,7 @@ struct V3ParseBisonYYSType {
AstVarRef* varrefp;
};
};
std::ostream& operator<<(std::ostream& os, const V3ParseBisonYYSType& rhs);
#define YYSTYPE V3ParseBisonYYSType
@ -105,26 +164,23 @@ class V3ParseImp {
V3Lexer* m_lexerp; // Current FlexLexer
static V3ParseImp* s_parsep; // Current THIS, bison() isn't class based
FileLine* m_fileline; // Filename/linenumber currently active
FileLine* m_lexFileline; // Filename/linenumber currently active for lexing
FileLine* m_bisonLastFileline; // Filename/linenumber of last token
bool m_inCellDefine; // Inside a `celldefine
bool m_inLibrary; // Currently reading a library vs. regular file
int m_inBeginKwd; // Inside a `begin_keywords
int m_lastVerilogState; // Last LEX state in `begin_keywords
int m_lexKwdDepth; // Inside a `begin_keywords
int m_lexKwdLast; // Last LEX state in `begin_keywords
VOptionBool m_unconnectedDrive; // Last unconnected drive
int m_prevLexToken; // previous parsed token (for lexer)
bool m_ahead; // aheadval is valid
V3ParseBisonYYSType m_aheadVal; // ahead token value
V3ParseBisonYYSType m_curBisonVal; // current token for error reporting
V3ParseBisonYYSType m_prevBisonVal; // previous token for error reporting
int m_lexPrevToken; // previous parsed token (for lexer)
std::deque<V3ParseBisonYYSType> m_tokensAhead; // Tokens we parsed ahead of parser
std::deque<string*> m_stringps; // Created strings for later cleanup
std::deque<V3Number*> m_numberps; // Created numbers for later cleanup
std::deque<FileLine> m_lintState; // Current lint state for save/restore
std::deque<FileLine> m_lexLintState; // Current lint state for save/restore
std::deque<string> m_ppBuffers; // Preprocessor->lex buffer of characters to process
string m_tag; // Contents (if any) of current verilator tag
AstNode* m_tagNodep; // Points to the node to set to m_tag or NULL to not set.
VTimescale m_timeLastUnit; // Last `timescale's unit
@ -140,47 +196,54 @@ public:
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel("flex");
return level;
}
static int debug() { return debugBison() ? debugFlex() : 0; }
static int debug() {
static int level = -1;
if (VL_UNLIKELY(level < 0))
level = std::max(std::max(debugBison(), debugFlex()),
v3Global.opt.debugSrcLevel("V3ParseImp"));
return level;
}
// Functions called by lex rules:
int yylexThis();
static bool optFuture(const string& flag) { return v3Global.opt.isFuture(flag); }
void ppline(const char* textp);
void linenoInc() { fileline()->linenoInc(); }
void verilatorCmtLint(const char* textp, bool warnOff);
void verilatorCmtLintSave();
void verilatorCmtLintRestore();
void verilatorCmtBad(const char* textp);
void errorPreprocDirective(const char* textp);
void tag(const char* text);
void tagNodep(AstNode* nodep) { m_tagNodep = nodep; }
AstNode* tagNodep() const { return m_tagNodep; }
void timescalePreproc(FileLine* fl, const char* textp);
void lexTimescaleParse(FileLine* fl, const char* textp);
void timescaleMod(FileLine* fl, AstNodeModule* modp, bool unitSet, double unitVal,
bool precSet, double precVal);
VTimescale timeLastUnit() const { return m_timeLastUnit; }
static double parseTimenum(const char* text);
static double parseDouble(const char* text, size_t length, bool* successp = NULL);
void pushBeginKeywords(int state) {
m_inBeginKwd++;
m_lastVerilogState = state;
FileLine* lexFileline() const { return m_lexFileline; }
FileLine* lexCopyOrSameFileLine() { return lexFileline()->copyOrSameFileLine(); }
static void lexErrorPreprocDirective(FileLine* fl, const char* textp);
static string lexParseTag(const char* textp);
static double lexParseTimenum(const char* text);
void lexPpline(const char* textp);
void lexVerilatorCmtLint(FileLine* fl, const char* textp, bool warnOff);
void lexVerilatorCmtLintSave(const FileLine* fl);
void lexVerilatorCmtLintRestore(FileLine* fl);
static void lexVerilatorCmtBad(FileLine* fl, const char* textp);
void lexPushKeywords(int state) {
++m_lexKwdDepth;
m_lexKwdLast = state;
}
bool popBeginKeywords() {
if (m_inBeginKwd) {
m_inBeginKwd--;
bool lexPopKeywords() {
if (m_lexKwdDepth) {
--m_lexKwdDepth;
return true;
} else {
return false;
}
}
int lastVerilogState() const { return m_lastVerilogState; }
int lexKwdLastState() const { return m_lexKwdLast; }
static const char* tokenName(int tok);
void ppPushText(const string& text) {
m_ppBuffers.push_back(text);
if (fileline()->contentp()) fileline()->contentp()->pushText(text);
if (lexFileline()->contentp()) lexFileline()->contentp()->pushText(text);
}
size_t ppInputToLex(char* buf, size_t max_size);
@ -188,6 +251,7 @@ public:
// TODO: Many of these functions are the old interface; they'd be better as non-static
// and called as READP->newString(...) etc.
// These can be called by either parser or lexer, as not lex/parser-position aware
string* newString(const string& text) {
// Allocate a string, remembering it so we can reclaim storage at lex end
string* strp = new string(text);
@ -211,12 +275,13 @@ public:
return nump;
}
// Bison sometimes needs error context without a token, so remember last token's line
// Only use this if do not have and cannot get a token-relevent fileline
FileLine* bisonLastFileline() const { return m_bisonLastFileline; }
// Return next token, for bison, since bison isn't class based, use a global THIS
FileLine* fileline() const { return m_fileline; }
AstNetlist* rootp() const { return m_rootp; }
FileLine* copyOrSameFileLine() { return fileline()->copyOrSameFileLine(); }
bool inCellDefine() const { return m_inCellDefine; }
void inCellDefine(bool flag) { m_inCellDefine = flag; }
FileLine* copyOrSameFileLine() { return bisonLastFileline()->copyOrSameFileLine(); }
bool inLibrary() const { return m_inLibrary; }
VOptionBool unconnectedDrive() const { return m_unconnectedDrive; }
void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; }
@ -228,10 +293,8 @@ public:
void lexNew();
void lexDestroy();
static int stateVerilogRecent(); // Parser -> lexer communication
int prevLexToken() const { return m_prevLexToken; } // Parser -> lexer communication
int lexPrevToken() const { return m_lexPrevToken; } // Parser -> lexer communication
size_t flexPpInputToLex(char* buf, size_t max_size) { return ppInputToLex(buf, max_size); }
V3ParseBisonYYSType curBisonVal() const { return m_curBisonVal; }
V3ParseBisonYYSType prevBisonVal() const { return m_prevBisonVal; }
//==== Symbol tables
V3ParseSym* symp() { return m_symp; }
@ -242,35 +305,34 @@ public:
: m_rootp(rootp)
, m_filterp(filterp)
, m_symp(parserSymp) {
m_fileline = NULL;
m_lexFileline = NULL;
m_lexerp = NULL;
m_inCellDefine = false;
m_inLibrary = false;
m_inBeginKwd = 0;
m_lastVerilogState = stateVerilogRecent();
m_prevLexToken = 0;
m_ahead = false;
m_curBisonVal.token = 0;
m_prevBisonVal.token = 0;
// m_aheadVal not used as m_ahead = false, and not all compilers support initing it
m_lexKwdDepth = 0;
m_lexKwdLast = stateVerilogRecent();
m_lexPrevToken = 0;
m_tagNodep = NULL;
m_timeLastUnit = v3Global.opt.timeDefaultUnit();
}
~V3ParseImp();
void parserClear();
void unputString(const char* textp, size_t length);
void lexUnputString(const char* textp, size_t length);
// METHODS
// Preprocess and read the Verilog file specified into the netlist database
int lexToBison(); // Pass token to bison
int tokenToBison(); // Pass token to bison
void parseFile(FileLine* fileline, const string& modfilename, bool inLibrary,
const string& errmsg);
private:
void lexFile(const string& modname);
int yylexReadTok();
void lexToken(); // Internal; called from lexToBison
void yylexReadTok();
void tokenPull();
void tokenPipeline(); // Internal; called from tokenToBison
void tokenPipelineSym();
size_t tokenPipeScanParam(size_t depth);
const V3ParseBisonYYSType* tokenPeekp(size_t depth);
void preprocDumps(std::ostream& os);
};

View File

@ -46,16 +46,16 @@ public:
}
};
void V3ParseImp::unputString(const char* textp, size_t length) {
void V3ParseImp::lexUnputString(const char* textp, size_t length) {
parsep()->m_lexerp->unputString(textp, length);
}
int V3ParseImp::yylexReadTok() {
void V3ParseImp::yylexReadTok() {
// Call yylex() remembering last non-whitespace token
parsep()->fileline()->startToken();
parsep()->lexFileline()->startToken();
int token = parsep()->m_lexerp->yylex();
m_prevLexToken = token; // Save so can find '#' to parse following number
return token;
m_lexPrevToken = token; // Save so can find '#' to parse following number
yylval.token = token;
}
//######################################################################

View File

@ -100,6 +100,13 @@ public:
reinsert(nodep, parentp);
pushScope(symp);
}
void pushNewUnderNodeOrCurrent(AstNode* nodep, AstNode* parentp) {
if (parentp) {
pushNewUnder(nodep, findNewTable(parentp));
} else {
pushNewUnder(nodep, NULL);
}
}
void pushScope(VSymEnt* symp) {
m_sympStack.push_back(symp);
m_symCurrentp = symp;
@ -138,11 +145,19 @@ public:
return NULL;
}
}
void importExtends(AstNode* classp) {
// Import from package::id_or_star to this
VSymEnt* symp = getTable(classp);
UASSERT_OBJ(symp, classp, // Internal problem, because we earlier found it
"Extends class package not found");
// Walk old sym table and reinsert into current table
// We let V3LinkDot report the error instead of us
symCurrentp()->importFromClass(&m_syms, symp);
}
void importItem(AstNode* packagep, const string& id_or_star) {
// Import from package::id_or_star to this
VSymEnt* symp = getTable(packagep);
UASSERT_OBJ(symp, packagep,
// Internal problem, because we earlier found pkg to label it an ID__aPACKAGE
UASSERT_OBJ(symp, packagep, // Internal problem, because we earlier found it
"Import package not found");
// Walk old sym table and reinsert into current table
// We let V3LinkDot report the error instead of us
@ -151,8 +166,7 @@ public:
void exportItem(AstNode* packagep, const string& id_or_star) {
// Export from this the remote package::id_or_star
VSymEnt* symp = getTable(packagep);
UASSERT_OBJ(symp, packagep,
// Internal problem, because we earlier found pkg to label it an ID__aPACKAGE
UASSERT_OBJ(symp, packagep, // Internal problem, because we earlier found it
"Export package not found");
symCurrentp()->exportFromPackage(&m_syms, symp, id_or_star);
}

View File

@ -1,8 +1,3 @@
%option noyywrap align interactive
%option stack
%option noc++
%option prefix="V3PreLex"
%{
/**************************************************************************
* DESCRIPTION: Verilator: Flex verilog preprocessor
*
@ -20,6 +15,16 @@
* Do not use Flex in C++ mode. It has bugs with yyunput() which result in
* lost characters.
**************************************************************************/
/* clang-format off */
%option noyywrap align interactive
%option stack
%option noc++
%option prefix="V3PreLex"
%{
#ifdef NEVER_JUST_FOR_CLANG_FORMAT
}
#endif
#include "V3PreProc.h"
#include "V3PreLex.h"
@ -27,17 +32,22 @@
# include <io.h> // for isatty
#endif
V3PreLex* V3PreLex::s_currentLexp = NULL; // Current lexing point
/* clang-format on */
V3PreLex* V3PreLex::s_currentLexp = NULL; // Current lexing point
#define LEXP V3PreLex::s_currentLexp
#define YY_INPUT(buf,result,max_size) \
#define YY_INPUT(buf, result, max_size) \
do { result = LEXP->inputToLex(buf, max_size); } while (false)
// Accessors, because flex keeps changing the type of yyleng
char* yyourtext() { return yytext; }
size_t yyourleng() { return yyleng; }
void yyourtext(const char* textp, size_t size) { yytext=(char*)textp; yyleng=size; }
void yyourtext(const char* textp, size_t size) {
yytext = (char*)textp;
yyleng = size;
}
// FL_FWD only tracks columns; preproc uses linenoInc() to track lines, so
// insertion of a \n does not mess up line count
@ -46,12 +56,13 @@ void yyourtext(const char* textp, size_t size) { yytext=(char*)textp; yyleng=siz
#define FL_BRK (LEXP->curFilelinep()->startToken())
// Prevent conflicts from perl version
static void linenoInc() {LEXP->linenoInc();}
static void linenoInc() { LEXP->linenoInc(); }
static bool pedantic() { return LEXP->m_pedantic; }
static void yyerror(char* msg) { LEXP->curFilelinep()->v3error(msg); }
static void yyerrorf(const char* msg) { LEXP->curFilelinep()->v3error(msg); }
static void appendDefValue(const char* t, size_t l) { LEXP->appendDefValue(t, l); }
/* clang-format off */
/**********************************************************************/
%}
@ -308,6 +319,7 @@ bom [\357\273\277]
<INITIAL>[\r] { FL_FWDC; FL_BRK; }
<INITIAL>. { FL_FWDC; return VP_TEXT; }
%%
// clang-format on
void V3PreLex::pushStateDefArg(int level) {
// Enter define substitution argument state
@ -336,12 +348,15 @@ void V3PreLex::pushStateIncFilename() {
yymore();
}
void V3PreLex::debug(int level) { yy_flex_debug = level; }
int V3PreLex::debug() { return yy_flex_debug; }
void V3PreLex::debug(int level) {
yy_flex_debug = level; }
int V3PreLex::debug() {
return yy_flex_debug; }
int V3PreLex::lex() {
V3PreLex::s_currentLexp = this; // Tell parser where to get/put data
m_tokFilelinep = curFilelinep(); // Remember token start location, may be updated by the lexer later
// Remember token start location, may be updated by the lexer later
m_tokFilelinep = curFilelinep();
return yylex();
}
@ -354,30 +369,32 @@ size_t V3PreLex::inputToLex(char* buf, size_t max_size) {
//
VPreStream* streamp = curStreamp();
if (debug() >= 10) {
cout<<"- pp:inputToLex ITL s="<<max_size<<" bs="<<streamp->m_buffers.size()<<endl;
cout << "- pp:inputToLex ITL s=" << max_size << " bs=" << streamp->m_buffers.size()
<< endl;
dumpStack();
}
// For testing, use really small chunks
//if (max_size > 13) max_size=13;
again:
// if (max_size > 13) max_size=13;
again:
size_t got = 0;
// Get from this stream
while (got < max_size // Haven't got enough
&& !streamp->m_buffers.empty()) { // And something buffered
string front = curStreamp()->m_buffers.front(); streamp->m_buffers.pop_front();
string front = curStreamp()->m_buffers.front();
streamp->m_buffers.pop_front();
size_t len = front.length();
if (len > (max_size-got)) { // Front string too big
len = (max_size-got);
if (len > (max_size - got)) { // Front string too big
len = (max_size - got);
string remainder = front.substr(len);
front = front.substr(0, len);
streamp->m_buffers.push_front(remainder); // Put back remainder for next time
}
strncpy(buf+got, front.c_str(), len);
strncpy(buf + got, front.c_str(), len);
got += len;
}
if (!got) { // end of stream; try "above" file
bool again = false;
string forceOut = endOfStream(again/*ref*/);
string forceOut = endOfStream(again /*ref*/);
streamp = curStreamp(); // May have been updated
if (forceOut != "") {
if (forceOut.length() > max_size) {
@ -388,13 +405,15 @@ size_t V3PreLex::inputToLex(char* buf, size_t max_size) {
}
} else {
if (streamp->m_eof) {
if (yy_flex_debug) cout<<"- EOF\n";
if (yy_flex_debug) cout << "- EOF\n";
}
got = 0; // 0=EOF/EOS - although got was already 0.
if (again) goto again;
}
}
if (debug() >= 10) { cout<<"- pp::inputToLex got="<<got<<" '"<<string(buf, got)<<"'"<<endl; }
if (debug() >= 10) {
cout << "- pp::inputToLex got=" << got << " '" << string(buf, got) << "'" << endl;
}
return got;
}
@ -402,7 +421,7 @@ string V3PreLex::endOfStream(bool& againr) {
// Switch to file or next unputString
againr = false;
if (yy_flex_debug) {
cout<<"-EOS state="<<curStreamp()->m_termState<<" at "<<curFilelinep()<<endl;
cout << "-EOS state=" << curStreamp()->m_termState << " at " << curFilelinep() << endl;
}
if (curStreamp()->m_eof) return ""; // Don't delete the final "EOF" stream
bool exited_file = curStreamp()->m_file;
@ -424,18 +443,15 @@ string V3PreLex::endOfStream(bool& againr) {
// immediately.
curStreamp()->m_termState = 1;
return "\n"; // Exit old file
}
else if (curStreamp()->m_termState == 1) {
} else if (curStreamp()->m_termState == 1) {
// Now the EOF - can't be sent with other characters
curStreamp()->m_termState = 2;
return ""; // End of file
}
else if (curStreamp()->m_termState == 2) {
} else if (curStreamp()->m_termState == 2) {
// Now ending `line
curStreamp()->m_termState = 3;
return curFilelinep()->lineDirectiveStrg(2); // Exit old file
}
else {
} else {
// Final shutdown phase for a stream, we can finally change the
// current fileline to the new stream
curStreamp()->m_termState = 0;
@ -518,7 +534,7 @@ void V3PreLex::scanBytesBack(const string& str) {
string V3PreLex::currentUnreadChars() {
// WARNING - Peeking at internals
ssize_t left = (yy_n_chars - (yy_c_buf_p -currentBuffer()->yy_ch_buf));
ssize_t left = (yy_n_chars - (yy_c_buf_p - currentBuffer()->yy_ch_buf));
if (left > 0) { // left may be -1 at EOS
*(yy_c_buf_p) = (yy_hold_char);
return string(yy_c_buf_p, left);
@ -536,25 +552,24 @@ int V3PreLex::currentStartState() const {
}
void V3PreLex::lineDirective(const char* textp) {
curFilelinep()->lineDirective(textp, m_enterExit/*ref*/);
curFilelinep()->lineDirective(textp, m_enterExit /*ref*/);
// Make sure we have a dependency on whatever file was specified
V3File::addSrcDepend(curFilelinep()->filename());
}
void V3PreLex::warnBackslashSpace() {
// Make fileline highlight the specific backslash and space
curFilelinep()->v3warn(BSSPACE, "Backslash followed by whitespace, perhaps the whitespace is accidental?");
curFilelinep()->v3warn(
BSSPACE, "Backslash followed by whitespace, perhaps the whitespace is accidental?");
}
void V3PreLex::dumpSummary() {
cout<<"- pp::dumpSummary curBuf="<<cvtToHex(currentBuffer());
cout << "- pp::dumpSummary curBuf=" << cvtToHex(currentBuffer());
#ifdef FLEX_DEBUG // Else peeking at internals may cause portability issues
ssize_t left = (yy_n_chars
- (yy_c_buf_p
-currentBuffer()->yy_ch_buf));
cout<<" left="<<std::dec<<left;
ssize_t left = (yy_n_chars - (yy_c_buf_p - currentBuffer()->yy_ch_buf));
cout << " left=" << std::dec << left;
#endif
cout<<endl;
cout << endl;
}
void V3PreLex::dumpStack() {
@ -563,13 +578,10 @@ void V3PreLex::dumpStack() {
std::stack<VPreStream*> tmpstack = LEXP->m_streampStack;
while (!tmpstack.empty()) {
VPreStream* streamp = tmpstack.top();
cout<<"- bufferStack["<<cvtToHex(streamp)<<"]: "
<<" at="<<streamp->m_curFilelinep
<<" nBuf="<<streamp->m_buffers.size()
<<" size0="<<(streamp->m_buffers.empty() ? 0 : streamp->m_buffers.front().length())
<<(streamp->m_eof?" [EOF]":"")
<<(streamp->m_file?" [FILE]":"");
cout<<endl;
cout << "- bufferStack[" << cvtToHex(streamp) << "]: "
<< " at=" << streamp->m_curFilelinep << " nBuf=" << streamp->m_buffers.size()
<< " size0=" << (streamp->m_buffers.empty() ? 0 : streamp->m_buffers.front().length())
<< (streamp->m_eof ? " [EOF]" : "") << (streamp->m_file ? " [FILE]" : "") << endl;
tmpstack.pop();
}
}

View File

@ -364,8 +364,8 @@ private:
virtual void visit(AstVar* nodep) VL_OVERRIDE {
if (!nodep->isIO()) return;
if (VN_IS(nodep->dtypep(), UnpackArrayDType)) {
nodep->v3error("Unsupported: unpacked arrays with protect-lib on "
<< nodep->prettyNameQ());
nodep->v3warn(E_UNSUPPORTED, "Unsupported: unpacked arrays with protect-lib on "
<< nodep->prettyNameQ());
}
if (nodep->direction() == VDirection::INPUT) {
if (nodep->isUsedClock() || nodep->attrClocker() == VVarAttrClocker::CLOCKER_YES) {
@ -376,8 +376,8 @@ private:
} else if (nodep->direction() == VDirection::OUTPUT) {
handleOutput(nodep);
} else {
nodep->v3error(
"Unsupported: protect-lib port direction: " << nodep->direction().ascii());
nodep->v3warn(E_UNSUPPORTED, "Unsupported: protect-lib port direction: "
<< nodep->direction().ascii());
}
}

View File

@ -13,17 +13,7 @@
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************
// V3Block's Transformations:
//
// Note this can be called multiple times.
// Create a IBLOCK(initial), SBLOCK(combo)
// ALWAYS: Remove any-edges from sense list
// If no POS/NEG in senselist, Fold into SBLOCK(combo)
// Else fold into SBLOCK(sequent).
// OPTIMIZE: When support async clocks, fold into that block if possible
// INITIAL: Move into IBLOCK
// WIRE: Move into SBLOCK(combo)
//
// AstSenTree related utilities.
//*************************************************************************
#ifndef _V3SENTREE_H_
@ -32,14 +22,9 @@
#include "config_build.h"
#include "verilatedos.h"
#include "V3Global.h"
#include "V3Ast.h"
#include "V3Hashed.h"
#include <cstdarg>
#include <map>
#include <algorithm>
#include <vector>
#include VL_INCLUDE_UNORDERED_SET
//######################################################################
@ -50,22 +35,16 @@ class SenTreeSet {
// Hash table of sensitive blocks.
private:
// TYPES
class HashSenTree {
public:
HashSenTree() {}
struct HashSenTree {
size_t operator()(const AstSenTree* kp) const {
return V3Hashed::uncachedHash(kp).fullValue();
}
// Copying required for OSX's libc++
};
class EqSenTree {
public:
EqSenTree() {}
struct EqSenTree {
bool operator()(const AstSenTree* ap, const AstSenTree* bp) const {
return ap->sameTree(bp);
}
// Copying required for OSX's libc++
};
// MEMBERS
@ -78,76 +57,57 @@ public:
// METHODS
void add(AstSenTree* nodep) { m_trees.insert(nodep); }
AstSenTree* find(AstSenTree* likep) {
AstSenTree* resultp = NULL;
Set::iterator it = m_trees.find(likep);
if (it != m_trees.end()) resultp = *it;
return resultp;
}
void clear() { m_trees.clear(); }
private:
VL_UNCOPYABLE(SenTreeSet);
};
class SenTreeFinder : public AstNVisitor {
class SenTreeFinder {
private:
// STATE
AstTopScope* m_topscopep; // Top scope to add statement to
SenTreeSet m_trees; // Set of sensitive blocks, for folding
AstTopScope* m_topScopep; // Top scope to add global SenTrees to
SenTreeSet m_trees; // Set of global SenTrees
// VISITORS
VL_DEBUG_FUNC; // Declare debug()
VL_UNCOPYABLE(SenTreeFinder);
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
// Only do the top
if (nodep->isTop()) iterateChildren(nodep);
}
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
m_topscopep = nodep;
iterateChildren(nodep);
// Don't clear topscopep, the namer persists beyond this visit
}
virtual void visit(AstScope* nodep) VL_OVERRIDE {
// But no SenTrees under TopScope's scope
}
// Memorize existing block names
virtual void visit(AstActive* nodep) VL_OVERRIDE {
// Don't grab SenTrees under Actives, only those that are global (under Scope directly)
iterateChildren(nodep);
}
virtual void visit(AstSenTree* nodep) VL_OVERRIDE { //
m_trees.add(nodep);
}
virtual void visit(AstNodeStmt*) VL_OVERRIDE {} // Accelerate
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
public:
// CONSTRUCTORS
SenTreeFinder()
: m_topScopep(NULL) {}
// METHODS
public:
void clear() {
m_topscopep = NULL;
m_trees.clear();
}
AstSenTree* getSenTree(AstSenTree* sensesp) {
// Return a global sentree that matches given sense list.
AstSenTree* treep = m_trees.find(sensesp);
AstSenTree* getSenTree(AstSenTree* senTreep) {
// Return a global SenTree that matches given SenTree. If no such global
// SenTree exists, create one and add it to the stored TopScope.
AstSenTree* treep = m_trees.find(senTreep);
// Not found, form a new one
if (!treep) {
UASSERT(m_topscopep, "Never called main()");
treep = sensesp->cloneTree(false);
m_topscopep->addStmtsp(treep);
UASSERT(m_topScopep, "Never called init()");
treep = senTreep->cloneTree(false);
m_topScopep->addStmtsp(treep);
UINFO(8, " New SENTREE " << treep << endl);
m_trees.add(treep);
// Note blocks may have also been added above in the Active visitor
}
return treep;
}
public:
// CONSTRUCTORS
SenTreeFinder() { clear(); }
virtual ~SenTreeFinder() {}
void main(AstTopScope* nodep) { iterate(nodep); }
void init(AstTopScope* topScopep) {
// Keep hold of top scope so we can add global SenTrees later
m_topScopep = topScopep;
// Gather existing global SenTrees
for (AstNode* nodep = topScopep->stmtsp(); nodep; nodep = nodep->nextp()) {
if (AstSenTree* senTreep = VN_CAST(nodep, SenTree)) m_trees.add(senTreep);
}
}
};
#endif // Guard

View File

@ -122,8 +122,6 @@
#include <map>
#include <set>
#include <vector>
#include VL_INCLUDE_UNORDERED_MAP
#include VL_INCLUDE_UNORDERED_SET
struct SplitVarImpl {
static AstNodeAssign* newAssign(FileLine* fileline, AstNode* lhsp, AstNode* rhsp,
@ -175,10 +173,7 @@ struct SplitVarImpl {
if (const char* reason = cannotSplitVarTypeReason(varp->varType())) return reason;
if (const char* reason = cannotSplitVarDirectionReason(varp->direction())) return reason;
if (varp->isSigPublic()) return "it is public";
if (varp->isInoutish()) return "it is bidirectional";
if (varp->isUsedLoopIdx()) return "it is used as a loop variable";
if (varp->isGenVar()) return "it is genvar";
if (varp->isParam()) return "it is parameter";
return NULL;
}
@ -228,6 +223,15 @@ const char* const SplitVarImpl::notSplitMsg
// AstVarRef -> Create a temporary variable and refer the variable
// AstSliceSel -> Create a temporary variable and refer the variable
// Compare AstNode* to get deterministic ordering when showing messages.
struct AstNodeComparator {
bool operator()(const AstNode* ap, const AstNode* bp) const {
const int lineComp = ap->fileline()->operatorCompare(*bp->fileline());
if (lineComp != 0) return lineComp < 0;
return ap < bp;
}
};
class UnpackRef {
// m_nodep is called in this context (AstNodeStmt, AstCell, AstNodeFTask, or AstAlways)
AstNode* m_contextp;
@ -277,19 +281,14 @@ public:
}
bool lvalue() const { return m_lvalue; }
bool ftask() const { return m_ftask; }
bool operator<(const UnpackRef& other) const {
return AstNodeComparator()(m_nodep, other.m_nodep);
}
};
class UnpackRefMap {
public:
struct Hash {
size_t operator()(const UnpackRef& r) const { return reinterpret_cast<size_t>(r.nodep()); }
};
struct Compare {
bool operator()(const UnpackRef& a, const UnpackRef& b) const {
return a.nodep() == b.nodep();
}
};
typedef std::map<AstVar*, vl_unordered_set<UnpackRef, Hash, Compare> > MapType;
typedef std::map<AstVar*, std::set<UnpackRef>, AstNodeComparator> MapType;
typedef MapType::iterator MapIt;
typedef MapType::value_type::second_type::iterator SetIt;
@ -336,30 +335,14 @@ public:
MapIt end() { return m_map.end(); }
};
// Compare AstNode* to get deterministic ordering when showing messages.
struct AstNodeComparator {
bool operator()(const AstNode* ap, const AstNode* bp) const {
const FileLine* afp = ap->fileline();
const FileLine* bfp = bp->fileline();
if (afp->firstLineno() != bfp->firstLineno())
return afp->firstLineno() < bfp->firstLineno();
if (afp->firstColumn() != bfp->firstColumn())
return afp->firstColumn() < bfp->firstColumn();
// Don't comapre its filename because it is expensive.
// Line number and column is practically enough.
// The comparison of raw pointer here is just in case.
// The comparison of this pointer may differ on different run,
// but this is just warning message order. (mostly for CI)
// Verilated result is same anyway.
return ap < bp;
}
};
// Found nodes for SplitPackedVarVisitor
struct RefsInModule {
std::set<AstVar*> m_vars;
std::set<AstVarRef*> m_refs;
std::set<AstSel*> m_sels;
typedef std::set<AstVar*, AstNodeComparator> VarSet;
typedef std::set<AstVarRef*, AstNodeComparator> VarRefSet;
typedef std::set<AstSel*, AstNodeComparator> SelSet;
VarSet m_vars;
VarRefSet m_refs;
SelSet m_sels;
public:
void add(AstVar* nodep) { m_vars.insert(nodep); }
@ -381,12 +364,10 @@ public:
v.iterate(nodep);
}
void visit(AstNVisitor* visitor) {
for (std::set<AstVar*>::iterator it = m_vars.begin(), it_end = m_vars.end(); it != it_end;
++it) {
for (VarSet::iterator it = m_vars.begin(), it_end = m_vars.end(); it != it_end; ++it) {
visitor->iterate(*it);
}
for (std::set<AstSel*>::iterator it = m_sels.begin(), it_end = m_sels.end(); it != it_end;
++it) {
for (SelSet::iterator it = m_sels.begin(), it_end = m_sels.end(); it != it_end; ++it) {
// If m_refs includes VarRef from ArraySel, remove it
// because the VarRef would not be visited in SplitPackedVarVisitor::visit(AstSel*).
if (AstVarRef* refp = VN_CAST((*it)->fromp(), VarRef)) {
@ -399,8 +380,7 @@ public:
UASSERT_OBJ(reinterpret_cast<uintptr_t>((*it)->op1p()) != 1, *it, "stale");
visitor->iterate(*it);
}
for (std::set<AstVarRef*>::iterator it = m_refs.begin(), it_end = m_refs.end();
it != it_end; ++it) {
for (VarRefSet::iterator it = m_refs.begin(), it_end = m_refs.end(); it != it_end; ++it) {
UASSERT_OBJ(reinterpret_cast<uintptr_t>((*it)->op1p()) != 1, *it, "stale");
visitor->iterate(*it);
}
@ -894,15 +874,16 @@ class PackedVarRef {
AstBasicDType* m_basicp; // Cache the ptr since varp->dtypep()->basicp() is expensive
bool m_dedupDone;
static void dedupRefs(std::vector<PackedVarRefEntry>& refs) {
vl_unordered_map<AstNode*, size_t> nodes;
// Use raw pointer to dedup
typedef std::map<AstNode*, size_t, AstNodeComparator> NodeIndices;
NodeIndices nodes;
for (size_t i = 0; i < refs.size(); ++i) {
nodes.insert(std::make_pair(refs[i].nodep(), i));
}
std::vector<PackedVarRefEntry> vect;
vect.reserve(nodes.size());
for (vl_unordered_map<AstNode*, size_t>::const_iterator it = nodes.begin(),
it_end = nodes.end();
it != it_end; ++it) {
for (NodeIndices::const_iterator it = nodes.begin(), it_end = nodes.end(); it != it_end;
++it) {
vect.push_back(refs[it->second]);
}
refs.swap(vect);
@ -983,24 +964,12 @@ public:
};
class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl {
typedef std::map<AstVar*, PackedVarRef, AstNodeComparator> PackedVarRefMap;
AstNetlist* m_netp;
AstNodeModule* m_modp; // Current module (just for log)
int m_numSplit; // Total number of split variables
// key:variable to be split. value:location where the variable is referenced.
vl_unordered_map<AstVar*, PackedVarRef> m_refs;
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
UASSERT_OBJ(m_modp == NULL, m_modp, "Nested module declaration");
if (!VN_IS(nodep, Module)) {
UINFO(5, "Skip " << nodep->prettyNameQ() << "\n");
return;
}
UASSERT_OBJ(m_refs.empty(), nodep, "The last module didn't finish split()");
m_modp = nodep;
UINFO(3, "Start analyzing module " << nodep->prettyName() << '\n');
iterateChildren(nodep);
split();
m_modp = NULL;
}
PackedVarRefMap m_refs;
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
if (!cannotSplitTaskReason(nodep)) iterateChildren(nodep);
}
@ -1017,7 +986,7 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl {
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
AstVar* varp = nodep->varp();
visit(varp);
vl_unordered_map<AstVar*, PackedVarRef>::iterator refit = m_refs.find(varp);
PackedVarRefMap::iterator refit = m_refs.find(varp);
if (refit == m_refs.end()) return; // variable without split_var metacomment
UASSERT_OBJ(varp->attrSplitVar(), varp, "split_var attribute must be attached");
UASSERT_OBJ(!nodep->packagep(), nodep,
@ -1036,7 +1005,7 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl {
}
AstVar* varp = vrefp->varp();
vl_unordered_map<AstVar*, PackedVarRef>::iterator refit = m_refs.find(varp);
PackedVarRefMap::iterator refit = m_refs.find(varp);
if (refit == m_refs.end()) {
iterateChildren(nodep);
return; // Variable without split_var metacomment
@ -1198,9 +1167,8 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl {
}
// Do the actual splitting operation
void split() {
for (vl_unordered_map<AstVar*, PackedVarRef>::iterator it = m_refs.begin(),
it_end = m_refs.end();
it != it_end; ++it) {
for (PackedVarRefMap::iterator it = m_refs.begin(), it_end = m_refs.end(); it != it_end;
++it) {
it->second.dedup();
AstVar* varp = it->first;
UINFO(3, "In module " << m_modp->name() << " var " << varp->prettyNameQ()
@ -1246,7 +1214,7 @@ public:
, m_modp(NULL)
, m_numSplit(0) {
// If you want ignore refs and walk the tne entire AST,
// just call iterate(nodep) and disable the following for-loop.
// just call iterateChildren(m_modp) and split() for each module
for (SplitVarRefsMap::iterator it = refs.begin(), it_end = refs.end(); it != it_end;
++it) {
m_modp = it->first;

View File

@ -121,6 +121,24 @@ bool VString::isWhitespace(const string& str) {
return true;
}
double VString::parseDouble(const string& str, bool* successp) {
char* strgp = new char[str.size() + 1];
char* dp = strgp;
if (successp) *successp = true;
for (const char* sp = str.c_str(); *sp; ++sp) {
if (*sp != '_') *dp++ = *sp;
}
*dp++ = '\0';
char* endp = strgp;
double d = strtod(strgp, &endp);
size_t parsed_len = endp - strgp;
if (parsed_len != strlen(strgp)) {
if (successp) *successp = false;
}
VL_DO_DANGLING(delete[] strgp, strgp);
return d;
}
//######################################################################
// VHashSha256

View File

@ -89,6 +89,8 @@ public:
static string removeWhitespace(const string& str);
// Return true if only whitespace or ""
static bool isWhitespace(const string& str);
// Return double by parsing string
static double parseDouble(const string& str, bool* successp);
};
//######################################################################

View File

@ -181,8 +181,10 @@ public:
}
private:
void importOneSymbol(VSymGraph* graphp, const string& name, const VSymEnt* srcp) {
if (srcp->exported() && !findIdFlat(name)) { // Don't insert over existing entry
void importOneSymbol(VSymGraph* graphp, const string& name, const VSymEnt* srcp,
bool honorExport) {
if ((!honorExport || srcp->exported())
&& !findIdFlat(name)) { // Don't insert over existing entry
VSymEnt* symp = new VSymEnt(graphp, srcp);
symp->exported(false); // Can't reimport an import without an export
symp->imported(true);
@ -198,15 +200,25 @@ private:
}
public:
void importFromClass(VSymGraph* graphp, const VSymEnt* srcp) {
// Import tokens from source symbol table into this symbol table
// Used for classes in early parsing only to handle "extends"
for (IdNameMap::const_iterator it = srcp->m_idNameMap.begin();
it != srcp->m_idNameMap.end(); ++it) {
importOneSymbol(graphp, it->first, it->second, false);
}
}
void importFromPackage(VSymGraph* graphp, const VSymEnt* srcp, const string& id_or_star) {
// Import tokens from source symbol table into this symbol table
if (id_or_star != "*") {
IdNameMap::const_iterator it = srcp->m_idNameMap.find(id_or_star);
if (it != srcp->m_idNameMap.end()) importOneSymbol(graphp, it->first, it->second);
if (it != srcp->m_idNameMap.end()) {
importOneSymbol(graphp, it->first, it->second, true);
}
} else {
for (IdNameMap::const_iterator it = srcp->m_idNameMap.begin();
it != srcp->m_idNameMap.end(); ++it) {
importOneSymbol(graphp, it->first, it->second);
importOneSymbol(graphp, it->first, it->second, true);
}
}
}

View File

@ -846,11 +846,12 @@ private:
newPortp->funcLocal(true);
dpip->addArgsp(newPortp);
if (!portp->basicp()) {
portp->v3error(
portp->v3warn(
E_UNSUPPORTED,
"Unsupported: DPI argument of type "
<< portp->basicp()->prettyTypeName() << endl
<< portp->warnMore()
<< "... For best portability, use bit, byte, int, or longint");
<< portp->basicp()->prettyTypeName() << endl
<< portp->warnMore()
<< "... For best portability, use bit, byte, int, or longint");
// We don't warn on logic either, although the 4-stateness is lost.
// That's what other simulators do.
}
@ -971,9 +972,10 @@ private:
}
} else {
if (portp->isWide()) {
nodep->v3error("Unsupported: Public functions with return > 64 bits wide.\n"
+ V3Error::warnMore()
+ "... Suggest make it an output argument instead?");
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Public functions with return > 64 bits wide.\n"
+ V3Error::warnMore()
+ "... Suggest make it an output argument instead?");
}
}
@ -1265,7 +1267,8 @@ private:
if (v3Global.opt.protectIds() && nodep->taskPublic()) {
// We always call protect() on names, we don't check if public or not
// Hence any external references wouldn't be able to find the refed public object.
nodep->v3error("Unsupported: Using --protect-ids with public function");
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Using --protect-ids with public function");
}
if (modes > 1) {
nodep->v3error("Cannot mix DPI import, DPI export, class methods, and/or public "
@ -1463,9 +1466,10 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp)
// Problem otherwise is we might have a varref, task
// call, or something else that only makes sense in the
// domain of the function, not the callee.
nodep->v3error("Unsupported: Non-constant default value in missing argument "
<< portp->prettyNameQ() << " in function call to "
<< nodep->taskp()->prettyTypeName());
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Non-constant default value in missing argument "
<< portp->prettyNameQ() << " in function call to "
<< nodep->taskp()->prettyTypeName());
newvaluep = new AstConst(nodep->fileline(), AstConst::Unsized32(), 0);
} else {
newvaluep = newvaluep->cloneTree(true);

View File

@ -380,8 +380,9 @@ class TristateVisitor : public TristateBaseVisitor {
invarp->name() + "__en", invarp);
UINFO(9, " newenv " << newp << endl);
if (!m_modp) {
invarp->v3error("Unsupported: Creating tristate signal not underneath a module: "
<< invarp->prettyNameQ());
invarp->v3warn(E_UNSUPPORTED,
"Unsupported: Creating tristate signal not underneath a module: "
<< invarp->prettyNameQ());
} else {
m_modp->addStmtp(newp);
}
@ -397,8 +398,9 @@ class TristateVisitor : public TristateBaseVisitor {
invarp->name() + "__out", invarp);
UINFO(9, " newout " << newp << endl);
if (!m_modp) {
invarp->v3error("Unsupported: Creating tristate signal not underneath a module: "
<< invarp->prettyNameQ());
invarp->v3warn(E_UNSUPPORTED,
"Unsupported: Creating tristate signal not underneath a module: "
<< invarp->prettyNameQ());
} else {
m_modp->addStmtp(newp);
}
@ -412,7 +414,8 @@ class TristateVisitor : public TristateBaseVisitor {
"__Vtriunconn" + cvtToStr(m_unique++), dtypep);
UINFO(9, " newunc " << newp << endl);
if (!m_modp) {
newp->v3error("Unsupported: Creating tristate signal not underneath a module");
newp->v3warn(E_UNSUPPORTED,
"Unsupported: Creating tristate signal not underneath a module");
} else {
m_modp->addStmtp(newp);
}
@ -447,10 +450,11 @@ class TristateVisitor : public TristateBaseVisitor {
varp->user3p(pullp); // save off to indicate the pull direction
} else {
if (oldpullp->direction() != pullp->direction()) {
pullp->v3error("Unsupported: Conflicting pull directions.\n"
<< pullp->warnContextPrimary() << endl
<< oldpullp->warnOther() << "... Location of conflicting pull.\n"
<< oldpullp->warnContextSecondary());
pullp->v3warn(E_UNSUPPORTED, "Unsupported: Conflicting pull directions.\n"
<< pullp->warnContextPrimary() << endl
<< oldpullp->warnOther()
<< "... Location of conflicting pull.\n"
<< oldpullp->warnContextSecondary());
}
}
}
@ -460,14 +464,16 @@ class TristateVisitor : public TristateBaseVisitor {
// The best way would be to visit the tree again and find any user1p()
// pointers that did not get picked up and expanded.
if (m_alhs && nodep->user1p()) {
nodep->v3error("Unsupported LHS tristate construct: " << nodep->prettyTypeName());
nodep->v3warn(E_UNSUPPORTED,
"Unsupported LHS tristate construct: " << nodep->prettyTypeName());
}
// Ignore Var's because they end up adjacent to statements
if ((nodep->op1p() && nodep->op1p()->user1p() && !VN_IS(nodep->op1p(), Var))
|| (nodep->op2p() && nodep->op2p()->user1p() && !VN_IS(nodep->op1p(), Var))
|| (nodep->op3p() && nodep->op3p()->user1p() && !VN_IS(nodep->op1p(), Var))
|| (nodep->op4p() && nodep->op4p()->user1p() && !VN_IS(nodep->op1p(), Var))) {
nodep->v3error("Unsupported tristate construct: " << nodep->prettyTypeName());
nodep->v3warn(E_UNSUPPORTED,
"Unsupported tristate construct: " << nodep->prettyTypeName());
}
}
@ -678,7 +684,8 @@ class TristateVisitor : public TristateBaseVisitor {
}
} else {
if (m_alhs && nodep->user1p()) {
nodep->v3error("Unsupported LHS tristate construct: " << nodep->prettyTypeName());
nodep->v3warn(E_UNSUPPORTED,
"Unsupported LHS tristate construct: " << nodep->prettyTypeName());
return;
}
iterateChildren(nodep);
@ -689,8 +696,8 @@ class TristateVisitor : public TristateBaseVisitor {
// error.
AstNode* condp = nodep->condp();
if (condp->user1p()) {
condp->v3error("Unsupported: don't know how to deal with "
"tristate logic in the conditional expression");
condp->v3warn(E_UNSUPPORTED, "Unsupported: don't know how to deal with "
"tristate logic in the conditional expression");
}
AstNode* expr1p = nodep->expr1p();
AstNode* expr2p = nodep->expr2p();
@ -732,8 +739,8 @@ class TristateVisitor : public TristateBaseVisitor {
iterateChildren(nodep);
UINFO(9, dbgState() << nodep << endl);
if (nodep->lsbp()->user1p()) {
nodep->v3error(
"Unsupported RHS tristate construct: " << nodep->prettyTypeName());
nodep->v3warn(E_UNSUPPORTED, "Unsupported RHS tristate construct: "
<< nodep->prettyTypeName());
}
if (nodep->fromp()->user1p()) { // SEL(VARREF, lsb)
AstNode* en1p = getEnp(nodep->fromp());
@ -804,7 +811,8 @@ class TristateVisitor : public TristateBaseVisitor {
} else {
if (debug() >= 9) nodep->backp()->dumpTree(cout, "-bufif: ");
if (m_alhs) {
nodep->v3error("Unsupported LHS tristate construct: " << nodep->prettyTypeName());
nodep->v3warn(E_UNSUPPORTED,
"Unsupported LHS tristate construct: " << nodep->prettyTypeName());
return;
}
m_tgraph.didProcess(nodep);
@ -834,7 +842,8 @@ class TristateVisitor : public TristateBaseVisitor {
associateLogic(nodep->rhsp(), nodep);
} else {
if (m_alhs && nodep->user1p()) {
nodep->v3error("Unsupported LHS tristate construct: " << nodep->prettyTypeName());
nodep->v3warn(E_UNSUPPORTED,
"Unsupported LHS tristate construct: " << nodep->prettyTypeName());
return;
}
// ANDs and Z's have issues. Earlier optimizations convert
@ -956,13 +965,14 @@ class TristateVisitor : public TristateBaseVisitor {
}
void visitEqNeqWild(AstNodeBiop* nodep) {
if (!VN_IS(nodep->rhsp(), Const)) {
nodep->v3error( // Says spac.
"Unsupported: RHS of ==? or !=? must be constant to be synthesizable");
nodep->v3warn(E_UNSUPPORTED, // Says spac.
"Unsupported: RHS of ==? or !=? must be constant to be synthesizable");
// rhs we want to keep X/Z intact, so otherwise ignore
}
iterateAndNextNull(nodep->lhsp());
if (nodep->lhsp()->user1p()) {
nodep->v3error("Unsupported LHS tristate construct: " << nodep->prettyTypeName());
nodep->v3warn(E_UNSUPPORTED,
"Unsupported LHS tristate construct: " << nodep->prettyTypeName());
return;
}
}
@ -982,7 +992,7 @@ class TristateVisitor : public TristateBaseVisitor {
}
if (!varrefp) {
if (debug() >= 4) nodep->dumpTree(cout, "- ");
nodep->v3error("Unsupported pullup/down (weak driver) construct.");
nodep->v3warn(E_UNSUPPORTED, "Unsupported pullup/down (weak driver) construct.");
} else {
if (m_graphing) {
varrefp->lvalue(true);
@ -1115,8 +1125,8 @@ class TristateVisitor : public TristateBaseVisitor {
if (!outModVarp) {
// At top, no need for __out as might be input only. Otherwise resolvable.
if (!m_modp->isTop()) {
nodep->v3error(
"Unsupported: tristate in top-level IO: " << nodep->prettyNameQ());
nodep->v3warn(E_UNSUPPORTED, "Unsupported: tristate in top-level IO: "
<< nodep->prettyNameQ());
}
} else {
AstNode* outexprp = nodep->exprp()->cloneTree(false); // Note has lvalue() set
@ -1160,8 +1170,8 @@ class TristateVisitor : public TristateBaseVisitor {
// pinReconnect should have converted this
exprrefp = VN_CAST(outpinp->exprp(), VarRef);
if (!exprrefp) {
nodep->v3error("Unsupported tristate port expression: "
<< nodep->exprp()->prettyTypeName());
nodep->v3warn(E_UNSUPPORTED, "Unsupported tristate port expression: "
<< nodep->exprp()->prettyTypeName());
}
}
} else {
@ -1169,8 +1179,8 @@ class TristateVisitor : public TristateBaseVisitor {
exprrefp = VN_CAST(outAssignp->rhsp(),
VarRef); // This should be the same var as the output pin
if (!exprrefp) {
nodep->v3error("Unsupported tristate port expression: "
<< nodep->exprp()->prettyTypeName());
nodep->v3warn(E_UNSUPPORTED, "Unsupported tristate port expression: "
<< nodep->exprp()->prettyTypeName());
}
}
if (exprrefp) {

View File

@ -210,8 +210,8 @@ private:
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
AstNode* newp;
if (!VN_IS(rhsp, Const)) {
nodep->v3error("Unsupported: RHS of ==? or !=? must be "
"constant to be synthesizable"); // Says spec.
nodep->v3warn(E_UNSUPPORTED, "Unsupported: RHS of ==? or !=? must be "
"constant to be synthesizable"); // Says spec.
// Replace with anything that won't cause more errors
newp = new AstEq(nodep->fileline(), lhsp, rhsp);
} else {

View File

@ -59,7 +59,8 @@ private:
// VISITORS
bool cantUnroll(AstNode* nodep, const char* reason) {
if (m_generate) nodep->v3error("Unsupported: Can't unroll generate for; " << reason);
if (m_generate)
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Can't unroll generate for; " << reason);
UINFO(3, " Can't Unroll: " << reason << " :" << nodep << endl);
// if (debug() >= 9) nodep->dumpTree(cout, "-cant-");
V3Stats::addStatSum(string("Unrolling gave up, ") + reason, 1);
@ -112,7 +113,7 @@ private:
// Assignment of next value check
AstAssign* incAssp = VN_CAST(incp, Assign);
if (!incAssp) return cantUnroll(nodep, "no increment assignment");
UASSERT_OBJ(!incAssp->nextp(), nodep, "increment shouldn't be a list");
if (incAssp->nextp()) return cantUnroll(nodep, "multiple increments");
m_forVarp = VN_CAST(initAssp->lhsp(), VarRef)->varp();
m_forVscp = VN_CAST(initAssp->lhsp(), VarRef)->varScopep();

View File

@ -479,8 +479,8 @@ private:
&& (VN_IS(vdtypep, AssocArrayDType) //
|| VN_IS(vdtypep, DynArrayDType) //
|| VN_IS(vdtypep, QueueDType))) {
nodep->v3error("Unsupported: Concatenation to form " << vdtypep->prettyDTypeNameQ()
<< "data type");
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Concatenation to form "
<< vdtypep->prettyDTypeNameQ() << "data type");
}
iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH);
@ -564,10 +564,18 @@ private:
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
} else {
nodep->v3error("Unsupported: fork statements");
nodep->v3warn(E_UNSUPPORTED, "Unsupported: fork statements");
// TBD might support only normal join, if so complain about other join flavors
}
}
virtual void visit(AstDisableFork* nodep) VL_OVERRIDE {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: disable fork statements");
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
virtual void visit(AstWaitFork* nodep) VL_OVERRIDE {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: wait fork statements");
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
}
virtual void visit(AstToLowerN* nodep) VL_OVERRIDE {
if (m_vup->prelim()) {
iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH);
@ -589,8 +597,8 @@ private:
if (vdtypep
&& (VN_IS(vdtypep, AssocArrayDType) || VN_IS(vdtypep, DynArrayDType)
|| VN_IS(vdtypep, QueueDType) || VN_IS(vdtypep, UnpackArrayDType))) {
nodep->v3error("Unsupported: Replication to form " << vdtypep->prettyDTypeNameQ()
<< " data type");
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Replication to form "
<< vdtypep->prettyDTypeNameQ() << " data type");
}
iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH);
iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH);
@ -746,8 +754,8 @@ private:
int width = nodep->widthConst();
UASSERT_OBJ(nodep->dtypep(), nodep, "dtype wasn't set"); // by V3WidthSel
if (VN_IS(nodep->lsbp(), Const) && nodep->msbConst() < nodep->lsbConst()) {
nodep->v3error("Unsupported: MSB < LSB of bit extract: "
<< nodep->msbConst() << "<" << nodep->lsbConst());
nodep->v3warn(E_UNSUPPORTED, "Unsupported: MSB < LSB of bit extract: "
<< nodep->msbConst() << "<" << nodep->lsbConst());
width = (nodep->lsbConst() - nodep->msbConst() + 1);
nodep->dtypeSetLogicSized(width, VSigning::UNSIGNED);
nodep->widthp()->replaceWith(new AstConst(nodep->widthp()->fileline(), width));
@ -1061,9 +1069,9 @@ private:
}
virtual void visit(AstUnbounded* nodep) VL_OVERRIDE {
nodep->dtypeSetSigned32(); // Used in int context
if (!VN_IS(nodep->backp(), IsUnbounded)
if (!VN_IS(nodep->backp(), IsUnbounded) && !VN_IS(nodep->backp(), BracketArrayDType)
&& !(VN_IS(nodep->backp(), Var) && VN_CAST(nodep->backp(), Var)->isParam())) {
nodep->v3error("Unsupported/illegal unbounded ('$') in this context.");
nodep->v3warn(E_UNSUPPORTED, "Unsupported/illegal unbounded ('$') in this context.");
}
}
virtual void visit(AstIsUnbounded* nodep) VL_OVERRIDE {
@ -1083,7 +1091,7 @@ private:
AstNodeDType* expDTypep = m_vup->dtypeOverridep(nodep->dtypep());
nodep->dtypeFrom(expDTypep); // Assume user knows the rules; go with the flow
if (nodep->width() > 64) {
nodep->v3error("Unsupported: $c can't generate wider than 64 bits");
nodep->v3warn(E_UNSUPPORTED, "Unsupported: $c can't generate wider than 64 bits");
}
}
}
@ -1267,7 +1275,7 @@ private:
break;
}
case AstAttrType::DIM_BITS: {
nodep->v3error("Unsupported: $bits for queue");
nodep->v3warn(E_UNSUPPORTED, "Unsupported: $bits for queue");
break;
}
default: nodep->v3error("Unhandled attribute type");
@ -1332,9 +1340,8 @@ private:
// DTYPES
virtual void visit(AstNodeArrayDType* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep));
// Iterate into subDTypep() to resolve that type and update pointer.
nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep()));
nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
// Cleanup array size
userIterateAndNext(nodep->rangep(), WidthVP(SELF, BOTH).p());
nodep->dtypep(nodep); // The array itself, not subDtype
@ -1349,29 +1356,52 @@ private:
}
virtual void visit(AstAssocArrayDType* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep));
if (nodep->keyChildDTypep()) {
nodep->keyDTypep(moveDTypeEdit(nodep, nodep->keyChildDTypep()));
}
// Iterate into subDTypep() to resolve that type and update pointer.
nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep()));
nodep->keyDTypep(iterateEditDTypep(nodep, nodep->keyDTypep()));
nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
nodep->keyDTypep(iterateEditMoveDTypep(nodep, nodep->keyDTypep()));
nodep->dtypep(nodep); // The array itself, not subDtype
UINFO(4, "dtWidthed " << nodep << endl);
}
virtual void visit(AstBracketArrayDType* nodep) VL_OVERRIDE {
// Type inserted only because parser didn't know elementsp() type
// Resolve elementsp's type
userIterateChildren(nodep, WidthVP(SELF, BOTH).p());
// We must edit when dtype still under normal nodes and before type table
// See notes in iterateEditMoveDTypep
AstNodeDType* childp = nodep->childDTypep();
childp->unlinkFrBack();
AstNode* elementsp = nodep->elementsp()->unlinkFrBack();
AstNode* newp;
if (VN_IS(elementsp, Unbounded)) {
newp = new AstQueueDType(nodep->fileline(), VFlagChildDType(), childp, NULL);
VL_DO_DANGLING(elementsp->deleteTree(), elementsp);
} else if (AstNodeDType* keyp = VN_CAST(elementsp, NodeDType)) {
newp = new AstAssocArrayDType(nodep->fileline(), VFlagChildDType(), childp, keyp);
} else {
// Must be expression that is constant, but we'll determine that later
newp = new AstUnpackArrayDType(
nodep->fileline(), VFlagChildDType(), childp,
new AstRange(nodep->fileline(), new AstConst(elementsp->fileline(), 0),
new AstSub(elementsp->fileline(), elementsp,
new AstConst(elementsp->fileline(), 1))));
}
nodep->replaceWith(newp);
VL_DO_DANGLING(nodep->deleteTree(), nodep);
// Normally parent's iteration would cover this, but we might have entered by a specific
// visit
VL_DO_DANGLING(userIterate(newp, NULL), newp);
}
virtual void visit(AstDynArrayDType* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep));
// Iterate into subDTypep() to resolve that type and update pointer.
nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep()));
nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
nodep->dtypep(nodep); // The array itself, not subDtype
UINFO(4, "dtWidthed " << nodep << endl);
}
virtual void visit(AstQueueDType* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep));
// Iterate into subDTypep() to resolve that type and update pointer.
nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep()));
nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
nodep->dtypep(nodep); // The array itself, not subDtype
if (VN_IS(nodep->boundp(), Unbounded)) {
nodep->boundp()->unlinkFrBack()->deleteTree(); // NULL will represent unbounded
@ -1380,9 +1410,8 @@ private:
}
virtual void visit(AstUnsizedArrayDType* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep));
// Iterate into subDTypep() to resolve that type and update pointer.
nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep()));
nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
// Cleanup array size
nodep->dtypep(nodep); // The array itself, not subDtype
UINFO(4, "dtWidthed " << nodep << endl);
@ -1412,12 +1441,8 @@ private:
}
virtual void visit(AstConstDType* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
// Move any childDTypep to instead be in global AstTypeTable.
// This way if this node gets deleted and some other dtype points to it
// it won't become a dead pointer. This doesn't change the object pointed to.
if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep));
// Iterate into subDTypep() to resolve that type and update pointer.
nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep()));
nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
userIterateChildren(nodep, NULL);
nodep->dtypep(nodep); // Should already be set, but be clear it's not the subDType
nodep->widthFromSub(nodep->subDTypep());
@ -1444,8 +1469,14 @@ private:
}
userIterateChildren(nodep, NULL);
if (nodep->subDTypep()) {
nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep()));
// Normally iterateEditMoveDTypep iterate would work, but the refs are under
// the TypeDef which will upset iterateEditMoveDTypep as it can't find it under
// this node's childDTypep
userIterate(nodep->subDTypep(), NULL);
nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
nodep->typedefp(NULL); // Note until line above subDTypep() may have followed this
// Widths are resolved, but special iterate to check for recurstion
userIterate(nodep->subDTypep(), NULL);
}
// Effectively nodep->dtypeFrom(nodep->dtypeSkipRefp());
// But might be recursive, so instead manually recurse into the referenced type
@ -1457,17 +1488,22 @@ private:
}
virtual void visit(AstTypedef* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
if (nodep->childDTypep()) nodep->dtypep(moveChildDTypeEdit(nodep));
nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
userIterateChildren(nodep, NULL);
nodep->dtypep(iterateEditDTypep(nodep, nodep->subDTypep()));
}
virtual void visit(AstParamTypeDType* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
if (nodep->childDTypep()) nodep->dtypep(moveChildDTypeEdit(nodep));
nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
userIterateChildren(nodep, NULL);
nodep->dtypep(iterateEditDTypep(nodep, nodep->subDTypep()));
nodep->widthFromSub(nodep->subDTypep());
}
virtual void visit(AstCastDynamic* nodep) VL_OVERRIDE {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: $cast. Suggest try static cast.");
AstNode* newp = new AstConst(nodep->fileline(), 1);
newp->dtypeSetSigned32(); // Spec says integer return
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
virtual void visit(AstCastParse* nodep) VL_OVERRIDE {
// nodep->dtp could be data type, or a primary_constant
// Don't iterate lhsp, will deal with that once convert the type
@ -1480,13 +1516,13 @@ private:
VL_DO_DANGLING(pushDeletep(nodep), nodep);
userIterate(newp, m_vup);
} else {
nodep->v3error("Unsupported: Cast to " << nodep->dtp()->prettyTypeName());
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Cast to " << nodep->dtp()->prettyTypeName());
nodep->replaceWith(nodep->lhsp()->unlinkFrBack());
}
}
virtual void visit(AstCast* nodep) VL_OVERRIDE {
if (nodep->childDTypep()) nodep->dtypep(moveChildDTypeEdit(nodep));
nodep->dtypep(iterateEditDTypep(nodep, nodep->dtypep()));
nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
// if (debug()) nodep->dumpTree(cout, " CastPre: ");
userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p());
// When more general casts are supported, the cast elimination will be done later.
@ -1538,7 +1574,8 @@ private:
AstBasicDType* underDtp = VN_CAST(nodep->lhsp()->dtypep(), BasicDType);
if (!underDtp) underDtp = nodep->lhsp()->dtypep()->basicp();
if (!underDtp) {
nodep->v3error("Unsupported: Size-changing cast on non-basic data type");
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Size-changing cast on non-basic data type");
underDtp = VN_CAST(nodep->findLogicBoolDType(), BasicDType);
}
// A cast propagates its size to the lower expression and is included in the maximum
@ -1593,8 +1630,7 @@ private:
}
nodep->doingWidth(true);
// Make sure dtype is sized
if (nodep->childDTypep()) nodep->dtypep(moveChildDTypeEdit(nodep));
nodep->dtypep(iterateEditDTypep(nodep, nodep->dtypep()));
nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
UASSERT_OBJ(nodep->dtypep(), nodep, "No dtype determined for var");
if (AstUnsizedArrayDType* unsizedp = VN_CAST(nodep->dtypeSkipRefp(), UnsizedArrayDType)) {
if (!(m_ftaskp && m_ftaskp->dpiImport())) {
@ -1608,7 +1644,8 @@ private:
&& !(VN_IS(nodep->dtypeSkipRefp(), BasicDType)
|| VN_IS(nodep->dtypeSkipRefp(), NodeArrayDType)
|| VN_IS(nodep->dtypeSkipRefp(), NodeUOrStructDType))) {
nodep->v3error("Unsupported: Inputs and outputs must be simple data types");
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Inputs and outputs must be simple data types");
}
if (VN_IS(nodep->dtypep()->skipRefToConstp(), ConstDType)) nodep->isConst(true);
// Parameters if implicit untyped inherit from what they are assigned to
@ -1724,8 +1761,7 @@ private:
virtual void visit(AstEnumDType* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
UINFO(5, " ENUMDTYPE " << nodep << endl);
if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep));
nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep()));
nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
nodep->dtypep(nodep);
nodep->widthFromSub(nodep->subDTypep());
// Assign widths
@ -1926,22 +1962,26 @@ private:
virtual void visit(AstClass* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return;
userIterateChildren(nodep, NULL); // First size all members
if (nodep->isVirtual()) nodep->v3warn(E_UNSUPPORTED, "Unsupported: virtual class");
nodep->repairCache();
}
virtual void visit(AstClassRefDType* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return;
// TODO this maybe eventually required to properly resolve members,
// though causes problems with t_class_forward.v, so for now avoided
// userIterateChildren(nodep->classp(), NULL);
}
virtual void visit(AstClassExtends* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return;
nodep->v3error("Unsupported: class extends"); // Member/meth access breaks
nodep->v3warn(E_UNSUPPORTED, "Unsupported: class extends"); // Member/meth access breaks
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
// if (nodep->childDTypep()) {
// nodep->dtypep(moveChildDTypeEdit(nodep)); // data_type '{ pattern }
// }
// nodep->dtypep(iterateEditMoveDTypep(nodep)); // data_type '{ pattern }
// userIterateChildren(nodep, NULL);
}
virtual void visit(AstMemberDType* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep));
// Iterate into subDTypep() to resolve that type and update pointer.
nodep->refDTypep(iterateEditDTypep(nodep, nodep->subDTypep()));
nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
nodep->dtypep(nodep); // The member itself, not subDtype
nodep->widthFromSub(nodep->subDTypep());
}
@ -2084,9 +2124,10 @@ private:
} else if (basicp && basicp->isString()) {
methodCallString(nodep, basicp);
} else {
nodep->v3error("Unsupported: Member call on object '"
<< nodep->fromp()->prettyTypeName() << "' which is a '"
<< nodep->fromp()->dtypep()->prettyTypeName() << "'");
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Member call on object '"
<< nodep->fromp()->prettyTypeName()
<< "' which is a '"
<< nodep->fromp()->dtypep()->prettyTypeName() << "'");
}
}
void methodOkArguments(AstMethodCall* nodep, int minArg, int maxArg) {
@ -2200,7 +2241,8 @@ private:
if (vconstp->toUQuad() >= msbdim) msbdim = vconstp->toUQuad();
}
if (adtypep->itemsp()->width() > 64 || msbdim >= (1 << 16)) {
nodep->v3error("Unsupported: enum next/prev method on enum with > 10 bits");
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: enum next/prev method on enum with > 10 bits");
return;
}
}
@ -2285,8 +2327,8 @@ private:
void methodCallLValue(AstMethodCall* nodep, AstNode* childp, bool lvalue) {
AstNodeVarRef* varrefp = VN_CAST(childp, NodeVarRef);
if (!varrefp) {
nodep->v3error("Unsupported: Non-variable on LHS of built-in method '"
<< nodep->prettyName() << "'");
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Non-variable on LHS of built-in method '"
<< nodep->prettyName() << "'");
} else {
if (lvalue) varrefp->lvalue(true);
}
@ -2315,8 +2357,8 @@ private:
NULL);
newp->makeStatement();
} else {
nodep->v3error("Unsupported/unknown built-in dynamic array method "
<< nodep->prettyNameQ());
nodep->v3warn(E_UNSUPPORTED, "Unsupported/unknown built-in dynamic array method "
<< nodep->prettyNameQ());
}
if (newp) {
newp->didWidth(true);
@ -2360,8 +2402,9 @@ private:
newp->didWidth(true);
newp->makeStatement();
} else {
nodep->v3error("Unsupported: Queue .delete(index) method, as is O(n) "
"complexity and slow.");
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Queue .delete(index) method, as is O(n) "
"complexity and slow.");
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
"erase", index_exprp->unlinkFrBack());
newp->protect(false);
@ -2380,7 +2423,8 @@ private:
newp->protect(false);
newp->makeStatement();
} else {
nodep->v3error(
nodep->v3warn(
E_UNSUPPORTED,
"Unsupported: Queue .insert method, as is O(n) complexity and slow.");
newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
nodep->name(), index_exprp->unlinkFrBack());
@ -2407,8 +2451,8 @@ private:
newp->protect(false);
newp->makeStatement();
} else {
nodep->v3error("Unsupported/unknown built-in associative array method "
<< nodep->prettyNameQ());
nodep->v3warn(E_UNSUPPORTED, "Unsupported/unknown built-in associative array method "
<< nodep->prettyNameQ());
}
if (newp) {
newp->didWidth(true);
@ -2671,16 +2715,17 @@ private:
virtual void visit(AstPattern* nodep) VL_OVERRIDE {
if (nodep->didWidthAndSet()) return;
UINFO(9, "PATTERN " << nodep << endl);
if (nodep->childDTypep())
nodep->dtypep(moveChildDTypeEdit(nodep)); // data_type '{ pattern }
if (nodep->childDTypep()) { // data_type '{ pattern }
nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
}
if (!nodep->dtypep() && m_vup->dtypeNullp()) { // Get it from parent assignment/pin/etc
nodep->dtypep(m_vup->dtypep());
}
AstNodeDType* dtypep = nodep->dtypep();
if (!dtypep) {
nodep->v3error("Unsupported/Illegal: Assignment pattern"
" member not underneath a supported construct: "
<< nodep->backp()->prettyTypeName());
nodep->v3warn(E_UNSUPPORTED, "Unsupported/Illegal: Assignment pattern"
" member not underneath a supported construct: "
<< nodep->backp()->prettyTypeName());
return;
}
{
@ -2737,9 +2782,10 @@ private:
} else if (VN_IS(dtypep, BasicDType) && VN_CAST(dtypep, BasicDType)->isRanged()) {
VL_DO_DANGLING(patternBasic(nodep, dtypep, defaultp), nodep);
} else {
nodep->v3error(
nodep->v3warn(
E_UNSUPPORTED,
"Unsupported: Assignment pattern applies against non struct/union data type: "
<< dtypep->prettyDTypeNameQ());
<< dtypep->prettyDTypeNameQ());
}
}
}
@ -3113,7 +3159,7 @@ private:
if (AstBasicDType* basicp = nodep->rhsp()->dtypep()->basicp()) {
if (basicp->isEventValue()) {
// see t_event_copy.v for commentary on the mess involved
nodep->v3error("Unsupported: assignment of event data type");
nodep->v3warn(E_UNSUPPORTED, "Unsupported: assignment of event data type");
}
}
if (AstNewDynamic* dynp = VN_CAST(nodep->rhsp(), NewDynamic)) {
@ -3442,15 +3488,17 @@ private:
= VN_CAST(nodep->memp()->dtypep()->skipRefp(), UnpackArrayDType)) {
subp = adtypep->subDTypep();
} else {
nodep->memp()->v3error("Unsupported: "
<< nodep->verilogKwd()
<< " into other than unpacked or associative array");
nodep->memp()->v3warn(E_UNSUPPORTED,
"Unsupported: "
<< nodep->verilogKwd()
<< " into other than unpacked or associative array");
}
if (subp
&& (!subp->skipRefp()->basicp()
|| !subp->skipRefp()->basicp()->keyword().isIntNumeric())) {
nodep->memp()->v3error("Unsupported: " << nodep->verilogKwd()
<< " array values must be integral");
nodep->memp()->v3warn(E_UNSUPPORTED,
"Unsupported: " << nodep->verilogKwd()
<< " array values must be integral");
}
userIterateAndNext(nodep->lsbp(), WidthVP(SELF, BOTH).p());
userIterateAndNext(nodep->msbp(), WidthVP(SELF, BOTH).p());
@ -3546,11 +3594,12 @@ private:
<< conDTypep->prettyDTypeNameQ() << " data type." << endl);
} else if (nodep->modVarp()->isTristate()) {
if (pinwidth != conwidth) {
nodep->v3error("Unsupported: " << ucfirst(nodep->prettyOperatorName())
<< " to inout signal requires " << pinwidth
<< " bits, but connection's "
<< nodep->exprp()->prettyTypeName()
<< " generates " << conwidth << " bits.");
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: " << ucfirst(nodep->prettyOperatorName())
<< " to inout signal requires " << pinwidth
<< " bits, but connection's "
<< nodep->exprp()->prettyTypeName()
<< " generates " << conwidth << " bits.");
// otherwise would need some mess to force both sides to proper size
}
}
@ -3646,11 +3695,14 @@ private:
// Grab width from the output variable (if it's a function)
if (nodep->didWidth()) return;
if (nodep->doingWidth()) {
nodep->v3error("Unsupported: Recursive function or task call");
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Recursive function or task call");
nodep->dtypeSetLogicBool();
nodep->didWidth(true);
return;
}
if (nodep->isVirtual() || nodep->pureVirtual()) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'virtual' class method");
}
// Function hasn't been widthed, so make it so.
// Would use user1 etc, but V3Width called from too many places to spend a user
nodep->doingWidth(true);
@ -3802,10 +3854,11 @@ private:
<< portp->prettyTypeName() << " but connection is "
<< pinp->prettyTypeName() << ".");
} else if (portp->isWritable() && pinp->width() != portp->width()) {
pinp->v3error("Unsupported: Function output argument "
<< portp->prettyNameQ() << " requires " << portp->width()
<< " bits, but connection's " << pinp->prettyTypeName()
<< " generates " << pinp->width() << " bits.");
pinp->v3warn(E_UNSUPPORTED, "Unsupported: Function output argument "
<< portp->prettyNameQ() << " requires "
<< portp->width() << " bits, but connection's "
<< pinp->prettyTypeName() << " generates "
<< pinp->width() << " bits.");
// otherwise would need some mess to force both sides to proper size
// (get an ASSIGN with EXTEND on the lhs instead of rhs)
}
@ -4948,32 +5001,48 @@ private:
//----------------------------------------------------------------------
// METHODS - data types
AstNodeDType* moveDTypeEdit(AstNode* nodep, AstNodeDType* dtnodep) {
// DTypes at parse time get added as a e.g. childDType to some node types such as AstVars.
// Move type to global scope, so removing/changing a variable won't lose the dtype.
UASSERT_OBJ(dtnodep, nodep, "Caller should check for NULL before calling moveDTypeEdit");
UINFO(9, "moveDTypeEdit " << dtnodep << endl);
dtnodep->unlinkFrBack(); // Make non-child
v3Global.rootp()->typeTablep()->addTypesp(dtnodep);
AstNodeDType* iterateEditMoveDTypep(AstNode* parentp, AstNodeDType* dtnodep) {
UASSERT_OBJ(dtnodep, parentp, "Caller should check for NULL before computing dtype");
// Iterate into a data type to resolve that type.
// The data type may either:
// 1. Be a child (typically getChildDTypep() returns it)
// DTypes at parse time get added as these to some node types
// such as AstVars.
// This function will move it to global scope (that is #2
// will now apply).
// 2. Be under the Netlist and pointed to by an Ast member variable
// (typically refDTypep() or dtypep() returns it)
// so removing/changing a variable won't lose the dtype
// Case #1 above applies?
bool child1 = (parentp->getChildDTypep() == dtnodep);
bool child2 = (parentp->getChild2DTypep() == dtnodep);
if (child1 || child2) {
UINFO(9, "iterateEditMoveDTypep child iterating " << dtnodep << endl);
// Iterate, this might edit the dtypes which means dtnodep now lost
VL_DO_DANGLING(userIterate(dtnodep, NULL), dtnodep);
// Figure out the new dtnodep, remained a child of parent so find it there
dtnodep = child1 ? parentp->getChildDTypep() : parentp->getChild2DTypep();
UASSERT_OBJ(dtnodep, parentp, "iterateEditMoveDTypep lost pointer to child");
UASSERT_OBJ(dtnodep->didWidth(), parentp,
"iterateEditMoveDTypep didn't get width resolution of "
<< dtnodep->prettyTypeName());
// Move to under netlist
UINFO(9, "iterateEditMoveDTypep child moving " << dtnodep << endl);
dtnodep->unlinkFrBack();
v3Global.rootp()->typeTablep()->addTypesp(dtnodep);
}
if (!dtnodep->didWidth()) {
UINFO(9, "iterateEditMoveDTypep pointer iterating " << dtnodep << endl);
// See notes in visit(AstBracketArrayDType*)
UASSERT_OBJ(!VN_IS(dtnodep, BracketArrayDType), parentp,
"Brackets should have been iterated as children");
userIterate(dtnodep, NULL);
UASSERT_OBJ(dtnodep->didWidth(), parentp,
"iterateEditMoveDTypep didn't get width resolution");
}
return dtnodep;
}
AstNodeDType* moveChildDTypeEdit(AstNode* nodep) {
return moveDTypeEdit(nodep, nodep->getChildDTypep());
}
AstNodeDType* iterateEditDTypep(AstNode* parentp, AstNodeDType* nodep) {
// Iterate into a data type to resolve that type. This process
// may eventually create a new data type, but not today
// it may make a new datatype, need subChildDType() to point to it;
// maybe we have user5p indicate a "replace me with" pointer.
// Need to be careful with "implicit" types though.
//
// Alternative is to have WidthVP return information.
// or have a call outside of normal visitor land.
// or have a m_return type (but need to return if width called multiple times)
UASSERT_OBJ(nodep, parentp, "Null dtype when widthing dtype");
userIterate(nodep, NULL);
return nodep;
}
AstConst* dimensionValue(FileLine* fileline, AstNodeDType* nodep, AstAttrType attrType,
int dim) {

View File

@ -276,7 +276,9 @@ private:
} else if (VN_IS(ddtypep, BasicDType) && ddtypep->isString()) {
// SELBIT(string, index) -> GETC(string, index)
AstNodeVarRef* varrefp = VN_CAST(fromp, NodeVarRef);
if (!varrefp) nodep->v3error("Unsupported: String array operation on non-variable");
if (!varrefp)
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: String array operation on non-variable");
AstNode* newp;
if (varrefp && varrefp->lvalue()) {
newp = new AstGetcRefN(nodep->fileline(), fromp, rhsp);
@ -499,7 +501,7 @@ private:
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
} else {
nodep->v3error("Unsupported: Slice of non-constant bounds");
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Slice of non-constant bounds");
}
} else if (VN_IS(ddtypep, BasicDType) || VN_IS(ddtypep, PackArrayDType)
|| (VN_IS(ddtypep, NodeUOrStructDType)

View File

@ -104,6 +104,10 @@ static void process() {
// Sort modules by level so later algorithms don't need to care
V3LinkLevel::modSortByLevel();
V3Error::abortIfErrors();
if (v3Global.opt.debugExitParse()) {
cout << "--debug-exit-parse: Exiting after parse\n";
exit(0);
}
// Convert parseref's to varrefs, and other directly post parsing fixups
V3LinkParse::linkParse(v3Global.rootp());
@ -580,20 +584,15 @@ static void verilate(const string& argString) {
FileLine::deleteAllRemaining();
}
static void execBuildJob() {
UASSERT(v3Global.opt.build(), "--build is not specified.");
UASSERT(v3Global.opt.gmake(), "--build requires GNU Make.");
UASSERT(!v3Global.opt.cmake(), "--build cannot use CMake.");
UINFO(1, "Start Build\n");
static string buildMakeCmd(const string& makefile, const string& target) {
const V3StringList& makeFlags = v3Global.opt.makeFlags();
const int jobs = v3Global.opt.buildJobs();
UASSERT(jobs >= 0, "-j option parser in V3Options.cpp filters out negative value");
std::stringstream cmd;
std::ostringstream cmd;
cmd << v3Global.opt.getenvMAKE();
cmd << " -C " << v3Global.opt.makeDir();
cmd << " -f " << v3Global.opt.prefix() << ".mk";
cmd << " -f " << makefile;
if (jobs == 0) {
cmd << " -j";
} else if (jobs > 1) {
@ -602,8 +601,18 @@ static void execBuildJob() {
for (V3StringList::const_iterator it = makeFlags.begin(); it != makeFlags.end(); ++it) {
cmd << ' ' << *it;
}
if (!target.empty()) { cmd << ' ' << target; }
const std::string cmdStr = cmd.str();
return cmd.str();
}
static void execBuildJob() {
UASSERT(v3Global.opt.build(), "--build is not specified.");
UASSERT(v3Global.opt.gmake(), "--build requires GNU Make.");
UASSERT(!v3Global.opt.cmake(), "--build cannot use CMake.");
UINFO(1, "Start Build\n");
const string cmdStr = buildMakeCmd(v3Global.opt.prefix() + ".mk", "");
const int exit_code = V3Os::system(cmdStr);
if (exit_code != 0) {
v3error(cmdStr << " exitted with " << exit_code << std::endl);

View File

@ -80,7 +80,7 @@ using std::make_pair;
// Define if SystemC found
// - If defined, the default search path has it, so support is always enabled.
// - If undef, not system-wide, user can set SYSTEMC_INCLUDE.
#undef HAVE_SYSTEMC_H
#undef HAVE_SYSTEMC
//**********************************************************************
//**** OS and compiler specifics

View File

@ -13,73 +13,61 @@
* SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
*
*************************************************************************/
/* clang-format off */
%option interactive c++ stack noyywrap
%{
/* %option nodefault */
#ifdef NEVER_JUST_FOR_CLANG_FORMAT
}
#endif
// clang-format on
#include "V3Number.h"
#include "V3ParseImp.h" // Defines YYTYPE; before including bison header
#include "V3ParseBison.h" // Generated by bison
extern void yyerror(const char*);
extern void yyerrorf(const char* format, ...);
#define STATE_VERILOG_RECENT S17 // State name for most recent Verilog Version
#define PARSEP V3ParseImp::parsep()
#define SYMP PARSEP->symp()
#define YY_INPUT(buf, result, max_size) \
do { result = PARSEP->flexPpInputToLex(buf, max_size); } while (false)
do { result = PARSEP->flexPpInputToLex(buf, max_size); } while (false)
//======================================================================
#define FL_FWD (PARSEP->fileline()->forwardToken(yytext, yyleng, true))
#define FL_FWD (PARSEP->lexFileline()->forwardToken(yytext, yyleng, true))
// Use this to break between tokens whereever not return'ing a token (e.g. skipping inside lexer)
#define FL_BRK (PARSEP->fileline()->startToken())
#define FL_BRK (PARSEP->lexFileline()->startToken())
#define CRELINE() (PARSEP->copyOrSameFileLine())
#define CRELINE() (PARSEP->lexCopyOrSameFileLine())
#define FL do { FL_FWD; yylval.fl = CRELINE(); } while (false)
#define FL \
do { \
FL_FWD; \
yylval.fl = CRELINE(); \
} while (false)
#define ERROR_RSVD_WORD(language) \
do { FL_FWD; \
yyerrorf("Unsupported: " language " reserved word not implemented: '%s'", yytext); \
FL_BRK; } while(0)
do { \
FL; \
yylval.fl->v3warn(E_UNSUPPORTED, "Unsupported: " << language \
<< " reserved word not implemented: '" \
<< yytext << "'"); \
FL_BRK; \
} while (0)
//======================================================================
void yyerror(const char* errmsg) {
PARSEP->fileline()->v3error(errmsg);
static const char* const colonmsg = "syntax error, unexpected ::, ";
// tokens;
if (0 == strncmp(errmsg, colonmsg, strlen(colonmsg))
&& PARSEP->prevBisonVal().token == yaID__ETC
&& PARSEP->curBisonVal().token == yP_COLONCOLON) {
static int warned = false;
if (!warned++) {
std::cerr << PARSEP->fileline()->warnMore()
<< ("... Perhaps '" + *PARSEP->prevBisonVal().strp
+ "' is a package which needs to be predeclared? (IEEE 1800-2017 26.3)")
<< std::endl;
}
}
}
void yyerrorf(const char* format, ...) {
const int maxlen = 2000;
char msg[maxlen];
va_list ap;
va_start(ap, format);
VL_VSNPRINTF(msg, maxlen, format, ap);
msg[maxlen - 1] = '\0';
va_end(ap);
yyerror(msg);
static double lexParseDouble(FileLine* fl, const char* textp, size_t length) {
string text = std::string(textp, length);
bool success = false;
double d = VString::parseDouble(text, &success);
if (!success) fl->v3error("Syntax error parsing real: '" << textp << "'");
return d;
}
// clang-format off
/**********************************************************************/
%}
@ -181,6 +169,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"$atanh" { FL; return yD_ATANH; }
"$bitstoreal" { FL; return yD_BITSTOREAL; }
"$bitstoshortreal" { FL; return yD_BITSTOSHORTREAL; }
"$cast" { FL; return yD_CAST; }
"$ceil" { FL; return yD_CEIL; }
"$cos" { FL; return yD_COS; }
"$cosh" { FL; return yD_COSH; }
@ -276,6 +265,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"$writeb" { FL; return yD_WRITEB; }
"$writeh" { FL; return yD_WRITEH; }
"$writeo" { FL; return yD_WRITEO; }
"$writememb" { FL; return yD_WRITEMEMB; }
"$writememh" { FL; return yD_WRITEMEMH; }
/* Keywords */
"always" { FL; return yALWAYS; }
@ -301,7 +291,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"endmodule" { FL; return yENDMODULE; }
"endprimitive" { FL; return yENDPRIMITIVE; }
"endspecify" { FL; return yENDSPECIFY; }
"endtable" { FL_FWD; yyerrorf("Syntax error: ENDTABLE outside of TABLE"); FL_BRK; }
"endtable" { FL; yylval.fl->v3error("Syntax error: ENDTABLE outside of TABLE"); FL_BRK; }
"endtask" { FL; return yENDTASK; }
"event" { FL; return yEVENT; }
"for" { FL; return yFOR; }
@ -406,7 +396,9 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"design" { ERROR_RSVD_WORD("Verilog 2001-config"); }
"endconfig" { ERROR_RSVD_WORD("Verilog 2001-config"); }
"incdir" { ERROR_RSVD_WORD("Verilog 2001-config"); }
"include" { FL_FWD; yyerrorf("Unsupported: Verilog 2001-config reserved word not implemented; suggest you want `include instead: %s", yytext); FL_BRK; }
"include" { FL; yylval.fl->v3warn(E_UNSUPPORTED, "Unsupported: Verilog 2001-config reserved word not implemented;"
" suggest you want `include instead: '" << yytext << "'");
FL_BRK; }
"instance" { ERROR_RSVD_WORD("Verilog 2001-config"); }
"liblist" { ERROR_RSVD_WORD("Verilog 2001-config"); }
"library" { ERROR_RSVD_WORD("Verilog 2001-config"); }
@ -446,6 +438,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"$unpacked_dimensions" { FL; return yD_UNPACKED_DIMENSIONS; }
"$warning" { FL; return yD_WARNING; }
/* SV2005 Keywords */
/* Note assert_strobe was in SystemVerilog 3.1, but removed for SystemVerilog 2005 */
"$unit" { FL; return yD_UNIT; } /* Yes, a keyword, not task */
"alias" { FL; return yALIAS; }
"always_comb" { FL; return yALWAYS_COMB; }
@ -453,7 +446,10 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"always_latch" { FL; return yALWAYS_LATCH; }
"assert" { FL; return yASSERT; }
"assume" { FL; return yASSUME; }
"before" { FL; return yBEFORE; }
"bind" { FL; return yBIND; }
"bins" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"binsof" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"bit" { FL; return yBIT; }
"break" { FL; return yBREAK; }
"byte" { FL; return yBYTE; }
@ -461,32 +457,45 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"class" { FL; return yCLASS; }
"clocking" { FL; return yCLOCKING; }
"const" { FL; return yCONST__LEX; }
"constraint" { FL; return yCONSTRAINT; }
"context" { FL; return yCONTEXT; }
"continue" { FL; return yCONTINUE; }
"cover" { FL; return yCOVER; }
"covergroup" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"coverpoint" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"cross" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"dist" { FL; return yDIST; }
"do" { FL; return yDO; }
"endclass" { FL; return yENDCLASS; }
"endclocking" { FL; return yENDCLOCKING; }
"endgroup" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"endinterface" { FL; return yENDINTERFACE; }
"endpackage" { FL; return yENDPACKAGE; }
"endprogram" { FL; return yENDPROGRAM; }
"endproperty" { FL; return yENDPROPERTY; }
"endsequence" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"enum" { FL; return yENUM; }
"expect" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"export" { FL; return yEXPORT; }
"extends" { FL; return yEXTENDS; }
"extern" { FL; return yEXTERN; }
"final" { FL; return yFINAL; }
"first_match" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"forkjoin" { FL; return yFORKJOIN; }
"iff" { FL; return yIFF; }
"ignore_bins" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"illegal_bins" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"import" { FL; return yIMPORT; }
"inside" { FL; return yINSIDE; }
"int" { FL; return yINT; }
"interface" { FL; return yINTERFACE; }
"intersect" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"join_any" { FL; return yJOIN_ANY; }
"join_none" { FL; return yJOIN_NONE; }
"local" { FL; return yLOCAL__LEX; }
"logic" { FL; return yLOGIC; }
"longint" { FL; return yLONGINT; }
"matches" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"modport" { FL; return yMODPORT; }
"new" { FL; return yNEW__LEX; }
"null" { FL; return yNULL; }
@ -500,16 +509,22 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"rand" { FL; return yRAND; }
"randc" { FL; return yRANDC; }
"randcase" { FL; return yRANDCASE; }
"randomize" { FL; return yRANDOMIZE; }
"randsequence" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"ref" { FL; return yREF; }
"restrict" { FL; return yRESTRICT; }
"return" { FL; return yRETURN; }
"sequence" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"shortint" { FL; return ySHORTINT; }
"shortreal" { FL; return ySHORTREAL; }
"static" { FL; return ySTATIC__ETC; }
"solve" { FL; return ySOLVE; }
"static" { FL; return ySTATIC__LEX; }
"string" { FL; return ySTRING; }
"struct" { FL; return ySTRUCT; }
"super" { FL; return ySUPER; }
"tagged" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"this" { FL; return yTHIS; }
"throughout" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"timeprecision" { FL; return yTIMEPRECISION; }
"timeunit" { FL; return yTIMEUNIT; }
"type" { FL; return yTYPE; }
@ -519,46 +534,20 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"var" { FL; return yVAR; }
"virtual" { FL; return yVIRTUAL__LEX; }
"void" { FL; return yVOID; }
/* Generic unsupported warnings */
/* Note assert_strobe was in SystemVerilog 3.1, but removed for SystemVerilog 2005 */
"before" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"bins" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"binsof" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"constraint" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"covergroup" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"coverpoint" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"cross" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"dist" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"endgroup" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"endsequence" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"expect" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"first_match" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"ignore_bins" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"illegal_bins" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"intersect" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"matches" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"randomize" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"randsequence" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"sequence" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"solve" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"tagged" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"throughout" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"wait_order" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"wildcard" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"with" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
"with" { FL; return yWITH__LEX; }
"within" { ERROR_RSVD_WORD("SystemVerilog 2005"); }
}
/* SystemVerilog 2009 */
<S09,S12,S17,SAX>{
/* Keywords */
"global" { FL; return yGLOBAL__LEX; }
"unique0" { FL; return yUNIQUE0; }
/* Generic unsupported warnings */
"accept_on" { ERROR_RSVD_WORD("SystemVerilog 2009"); }
"checker" { ERROR_RSVD_WORD("SystemVerilog 2009"); }
"endchecker" { ERROR_RSVD_WORD("SystemVerilog 2009"); }
"eventually" { ERROR_RSVD_WORD("SystemVerilog 2009"); }
"global" { FL; return yGLOBAL__LEX; }
"implies" { ERROR_RSVD_WORD("SystemVerilog 2009"); }
"let" { ERROR_RSVD_WORD("SystemVerilog 2009"); }
"nexttime" { ERROR_RSVD_WORD("SystemVerilog 2009"); }
@ -571,6 +560,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"strong" { ERROR_RSVD_WORD("SystemVerilog 2009"); }
"sync_accept_on" { ERROR_RSVD_WORD("SystemVerilog 2009"); }
"sync_reject_on" { ERROR_RSVD_WORD("SystemVerilog 2009"); }
"unique0" { FL; return yUNIQUE0; }
"until" { ERROR_RSVD_WORD("SystemVerilog 2009"); }
"until_with" { ERROR_RSVD_WORD("SystemVerilog 2009"); }
"untyped" { ERROR_RSVD_WORD("SystemVerilog 2009"); }
@ -583,7 +573,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"implements" { FL; return yIMPLEMENTS; }
"interconnect" { ERROR_RSVD_WORD("SystemVerilog 2012"); }
"nettype" { ERROR_RSVD_WORD("SystemVerilog 2012"); }
"soft" { ERROR_RSVD_WORD("SystemVerilog 2012"); }
"soft" { FL; return ySOFT; }
}
/* System Verilog 2017 */
@ -697,10 +687,18 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
<V95,V01,V05,VA5,S05,S09,S12,S17,SAX>{
"/*verilator"{ws}*"*/" { FL_FWD; FL_BRK; } /* Ignore empty comments, may be `endif // verilator */
"/*verilator clock_enable*/" { FL; return yVL_CLOCK_ENABLE; }
"/*verilator clocker*/" { FL; return yVL_CLOCKER; }
"/*verilator coverage_block_off*/" { FL; return yVL_COVERAGE_BLOCK_OFF; }
"/*verilator coverage_off*/" { FL_FWD; PARSEP->lexFileline()->coverageOn(false); FL_BRK; }
"/*verilator coverage_on*/" { FL_FWD; PARSEP->lexFileline()->coverageOn(true); FL_BRK; }
"/*verilator full_case*/" { FL; return yVL_FULL_CASE; }
"/*verilator inline_module*/" { FL; return yVL_INLINE_MODULE; }
"/*verilator isolate_assignments*/" { FL; return yVL_ISOLATE_ASSIGNMENTS; }
"/*verilator lint_off"[^*]*"*/" { FL; PARSEP->lexVerilatorCmtLint(yylval.fl, yytext, true); FL_BRK; }
"/*verilator lint_on"[^*]*"*/" { FL; PARSEP->lexVerilatorCmtLint(yylval.fl, yytext, false); FL_BRK; }
"/*verilator lint_restore*/" { FL; PARSEP->lexVerilatorCmtLintRestore(PARSEP->lexFileline()); FL_BRK; }
"/*verilator lint_save*/" { FL; PARSEP->lexVerilatorCmtLintSave(PARSEP->lexFileline()); FL_BRK; }
"/*verilator no_clocker*/" { FL; return yVL_NO_CLOCKER; }
"/*verilator no_inline_module*/" { FL; return yVL_NO_INLINE_MODULE; }
"/*verilator no_inline_task*/" { FL; return yVL_NO_INLINE_TASK; }
"/*verilator parallel_case*/" { FL; return yVL_PARALLEL_CASE; }
@ -709,25 +707,18 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"/*verilator public_flat_rd*/" { FL; return yVL_PUBLIC_FLAT_RD; }
"/*verilator public_flat_rw*/" { FL; return yVL_PUBLIC_FLAT_RW; } // The @(edge) is converted by the preproc
"/*verilator public_module*/" { FL; return yVL_PUBLIC_MODULE; }
"/*verilator split_var*/" { FL; return yVL_SPLIT_VAR; }
"/*verilator sc_clock*/" { FL; return yVL_CLOCK; }
"/*verilator clocker*/" { FL; return yVL_CLOCKER; }
"/*verilator no_clocker*/" { FL; return yVL_NO_CLOCKER; }
"/*verilator sc_bv*/" { FL; return yVL_SC_BV; }
"/*verilator sc_clock*/" { FL; return yVL_CLOCK; }
"/*verilator sformat*/" { FL; return yVL_SFORMAT; }
"/*verilator split_var*/" { FL; return yVL_SPLIT_VAR; }
"/*verilator systemc_clock*/" { FL; return yVL_CLOCK; }
"/*verilator tracing_off*/" { FL_FWD; PARSEP->fileline()->tracingOn(false); FL_BRK; }
"/*verilator tracing_on*/" { FL_FWD; PARSEP->fileline()->tracingOn(true); FL_BRK; }
"/*verilator coverage_off*/" { FL_FWD; PARSEP->fileline()->coverageOn(false); FL_BRK; }
"/*verilator coverage_on*/" { FL_FWD; PARSEP->fileline()->coverageOn(true); FL_BRK; }
"/*verilator lint_off"[^*]*"*/" { FL_FWD; PARSEP->verilatorCmtLint(yytext, true); FL_BRK; }
"/*verilator lint_on"[^*]*"*/" { FL_FWD; PARSEP->verilatorCmtLint(yytext, false); FL_BRK; }
"/*verilator lint_restore*/" { FL_FWD; PARSEP->verilatorCmtLintRestore(); FL_BRK; }
"/*verilator lint_save*/" { FL_FWD; PARSEP->verilatorCmtLintSave(); FL_BRK; }
"/*verilator tag"[^*]*"*/" { FL_FWD; PARSEP->tag(yytext); FL_BRK; }
"/*verilator tag"[^*]*"*/" { FL; yylval.strp = PARSEP->newString(V3ParseImp::lexParseTag(yytext));
return yVL_TAG; }
"/*verilator tracing_off*/" { FL_FWD; PARSEP->lexFileline()->tracingOn(false); FL_BRK; }
"/*verilator tracing_on*/" { FL_FWD; PARSEP->lexFileline()->tracingOn(true); FL_BRK; }
"/**/" { FL_FWD; FL_BRK; }
"/*"[^*]+"*/" { FL_FWD; PARSEP->verilatorCmtBad(yytext); FL_BRK; }
"/*"[^*]+"*/" { FL; V3ParseImp::lexVerilatorCmtBad(yylval.fl, yytext); FL_BRK; }
}
/************************************************************************/
@ -797,7 +788,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"-:" { FL; return yP_MINUSCOLON; }
".*" { FL; return yP_DOTSTAR; }
":+" { FL; yyless(1);
PARSEP->fileline()->v3warn(COLONPLUS, "Perhaps instead of ':+' the intent was '+:'?");
yylval.fl->v3warn(COLONPLUS, "Perhaps instead of ':+' the intent was '+:'?");
return ':'; }
}
@ -855,12 +846,12 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
\" { yy_push_state(STRING); yymore(); }
{vnum} {
/* "# 1'b0" is a delay value so must lex as "#" "1" "'b0" */
if (PARSEP->prevLexToken()=='#') {
if (PARSEP->lexPrevToken()=='#') {
int shortlen = 0;
while (isdigit(yytext[shortlen])) shortlen++;
if (shortlen) {
// Push rest past numbers for later parse
PARSEP->unputString(yytext+shortlen, yyleng-shortlen);
PARSEP->lexUnputString(yytext+shortlen, yyleng-shortlen);
// Return is stuff before the tick
yyleng = shortlen;
yytext[yyleng] = '\0';
@ -876,15 +867,15 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
return yaINTNUM;
}
[0-9][_0-9]*(\.[_0-9]+)([eE][-+]?[_0-9]+)? {
FL; yylval.cdouble = PARSEP->parseDouble(yytext, yyleng);
FL; yylval.cdouble = lexParseDouble(yylval.fl, yytext, yyleng);
return yaFLOATNUM;
}
[0-9][_0-9]*(\.[_0-9]+)?([eE][-+]?[_0-9]+) {
FL; yylval.cdouble = PARSEP->parseDouble(yytext, yyleng);
FL; yylval.cdouble = lexParseDouble(yylval.fl, yytext, yyleng);
return yaFLOATNUM;
}
[0-9][_0-9]*(\.[_0-9]+)?(fs|ps|ns|us|ms|s) {
FL; yylval.cdouble = PARSEP->parseTimenum(yytext);
FL; yylval.cdouble = V3ParseImp::lexParseTimenum(yytext);
return yaTIMENUM;
}
1step {
@ -895,9 +886,10 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
/************************************************************************/
/* STRINGS */
<STRING><<EOF>> { FL_FWD; yyerrorf("EOF in unterminated string");
<STRING><<EOF>> { FL; yylval.fl->v3error("EOF in unterminated string");
yyleng = 0; yy_pop_state(); FL_BRK; yyterminate(); }
<STRING>{crnl} { FL_FWD; yyerrorf("Unterminated string"); FL_BRK; }
<STRING>{crnl} { FL; yylval.fl->v3error("Unterminated string");
FL_BRK; }
<STRING>\\{crnl} { yymore(); }
<STRING>\\. { yymore(); }
<STRING>\" { yy_pop_state();
@ -912,7 +904,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
<ATTRMODE>"*)" { FL_FWD; yy_pop_state(); FL_BRK; }
<ATTRMODE>{word} { yymore(); }
<ATTRMODE>. { yymore(); }
<ATTRMODE><<EOF>> { FL_FWD; yyerrorf("EOF in (*");
<ATTRMODE><<EOF>> { FL; yylval.fl->v3error("EOF in (*");
yyleng = 0; yy_pop_state(); FL_BRK; yyterminate(); }
/************************************************************************/
@ -928,9 +920,9 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
<TABLE>{crnl} { yymore(); }
<TABLE>";" { FL; yylval.strp = PARSEP->newString(yytext, yyleng); return yaTABLELINE; }
<TABLE>"endtable" { yy_pop_state(); FL; return yENDTABLE; }
<TABLE>"`line"{ws}+[^\n\r]*{crnl} { FL_FWD; PARSEP->ppline(yytext); FL_BRK; }
<TABLE>"`line"{ws}+[^\n\r]*{crnl} { FL_FWD; PARSEP->lexPpline(yytext); FL_BRK; }
<TABLE>. { yymore(); }
<TABLE><<EOF>> { FL_FWD; yyerrorf("EOF in TABLE");
<TABLE><<EOF>> { FL; yylval.fl->v3error("EOF in TABLE");
yyleng = 0; yy_pop_state(); FL_BRK; yyterminate(); }
/************************************************************************/
@ -941,58 +933,62 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
<V95,V01,V05,VA5,S05,S09,S12,S17,SAX,VLT,SYSCHDR,SYSCINT,SYSCIMP,SYSCIMPH,SYSCCTOR,SYSCDTOR,IGNORE>{
"`accelerate" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
"`autoexpand_vectornets" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
"`celldefine" { FL_FWD; PARSEP->inCellDefine(true); FL_BRK; }
"`celldefine" { FL_FWD; PARSEP->lexFileline()->celldefineOn(true); FL_BRK; }
"`default_decay_time"{ws}+[^\n\r]* { FL_FWD; FL_BRK; } // Verilog spec - delays only
"`default_nettype"{ws}+"wire" { FL_FWD; PARSEP->fileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, true); FL_BRK; }
"`default_nettype"{ws}+"none" { FL_FWD; PARSEP->fileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, false); FL_BRK; }
"`default_nettype"{ws}+[a-zA-Z0-9]* { FL_FWD; yyerrorf("Unsupported: `default_nettype of other than none or wire: %s", yytext); FL_BRK; }
"`default_trireg_strength"{ws}+[^\n\r]* { FL_FWD; yyerrorf("Unsupported: Verilog optional directive not implemented: %s", yytext); FL_BRK; }
"`default_nettype"{ws}+"wire" { FL_FWD; PARSEP->lexFileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, true); FL_BRK; }
"`default_nettype"{ws}+"none" { FL_FWD; PARSEP->lexFileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, false); FL_BRK; }
"`default_nettype"{ws}+[a-zA-Z0-9]* { FL; yylval.fl->v3warn(E_UNSUPPORTED, "Unsupported: `default_nettype of other than none or wire: '"
<< yytext << "'");
FL_BRK; }
"`default_trireg_strength"{ws}+[^\n\r]* { FL; yylval.fl->v3warn(E_UNSUPPORTED, "Unsupported: Verilog optional directive not implemented: '"
<< yytext << "'");
FL_BRK; }
"`delay_mode_distributed" { FL_FWD; FL_BRK; } // Verilog spec - delays only
"`delay_mode_path" { FL_FWD; FL_BRK; } // Verilog spec - delays only
"`delay_mode_unit" { FL_FWD; FL_BRK; } // Verilog spec - delays only
"`delay_mode_zero" { FL_FWD; FL_BRK; } // Verilog spec - delays only
"`disable_portfaults" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
"`enable_portfaults" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
"`endcelldefine" { FL_FWD; PARSEP->inCellDefine(false); FL_BRK; }
"`endcelldefine" { FL_FWD; PARSEP->lexFileline()->celldefineOn(false); FL_BRK; }
"`endprotect" { FL_FWD; FL_BRK; }
"`expand_vectornets" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
"`inline" { FL_FWD; FL_BRK; }
"`line"{ws}+[^\n\r]*{crnl} { FL_FWD; PARSEP->ppline(yytext); FL_BRK; }
"`line"{ws}+[^\n\r]*{crnl} { FL_FWD; PARSEP->lexPpline(yytext); FL_BRK; }
"`noaccelerate" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
"`noexpand_vectornets" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
"`noremove_gatenames" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
"`noremove_netnames" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
"`nosuppress_faults" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
"`nounconnected_drive" { FL_FWD; PARSEP->unconnectedDrive(VOptionBool::OPT_DEFAULT_FALSE); FL_BRK; }
"`nounconnected_drive" { FL; return yaT_NOUNCONNECTED; }
"`portcoerce" { FL_FWD; FL_BRK; }
"`pragma"{ws}*[^\n\r]* { FL_FWD; FL_BRK; } // Verilog 2005
"`protect" { FL_FWD; FL_BRK; }
"`remove_gatenames" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
"`remove_netnames" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
"`resetall" { FL; PARSEP->fileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, true);
"`resetall" { FL; PARSEP->lexFileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, true);
return yaT_RESETALL; } // Rest handled by preproc
"`suppress_faults" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
"`timescale"{ws}+[^\n\r]* { FL_FWD; PARSEP->timescalePreproc(PARSEP->fileline(),
yytext + strlen("`timescale"));
"`timescale"{ws}+[^\n\r]* { FL; PARSEP->lexTimescaleParse(yylval.fl,
yytext + strlen("`timescale"));
FL_BRK; }
"`unconnected_drive"{ws}+"pull0" { FL_FWD; PARSEP->unconnectedDrive(VOptionBool::OPT_FALSE); FL_BRK; }
"`unconnected_drive"{ws}+"pull1" { FL_FWD; PARSEP->unconnectedDrive(VOptionBool::OPT_TRUE); FL_BRK; }
"`unconnected_drive" { FL_FWD; yyerrorf("Bad `unconnected_drive syntax"); FL_BRK; }
"`unconnected_drive"{ws}+"pull0" { FL; return yaT_UNCONNECTED_PULL0; }
"`unconnected_drive"{ws}+"pull1" { FL; return yaT_UNCONNECTED_PULL1; }
"`unconnected_drive" { FL; yylval.fl->v3error("Bad `unconnected_drive syntax"); FL_BRK; }
"`uselib"{ws}+[^\n\r]* { FL_FWD; FL_BRK; } // Verilog-XL compatibility
/* See also setLanguage below */
"`begin_keywords"[ \t]*\"1364-1995\" { FL_FWD; yy_push_state(V95); PARSEP->pushBeginKeywords(YY_START); FL_BRK; }
"`begin_keywords"[ \t]*\"1364-2001\" { FL_FWD; yy_push_state(V01); PARSEP->pushBeginKeywords(YY_START); FL_BRK; }
"`begin_keywords"[ \t]*\"1364-2001-noconfig\" { FL_FWD; yy_push_state(V01); PARSEP->pushBeginKeywords(YY_START); FL_BRK; }
"`begin_keywords"[ \t]*\"1364-2005\" { FL_FWD; yy_push_state(V05); PARSEP->pushBeginKeywords(YY_START); FL_BRK; }
"`begin_keywords"[ \t]*\"VAMS[-0-9.]*\" { FL_FWD; yy_push_state(VA5); PARSEP->pushBeginKeywords(YY_START); FL_BRK; }
"`begin_keywords"[ \t]*\"1800-2005\" { FL_FWD; yy_push_state(S05); PARSEP->pushBeginKeywords(YY_START); FL_BRK; }
"`begin_keywords"[ \t]*\"1800-2009\" { FL_FWD; yy_push_state(S09); PARSEP->pushBeginKeywords(YY_START); FL_BRK; }
"`begin_keywords"[ \t]*\"1800-2012\" { FL_FWD; yy_push_state(S12); PARSEP->pushBeginKeywords(YY_START); FL_BRK; }
"`begin_keywords"[ \t]*\"1800-2017\" { FL_FWD; yy_push_state(S17); PARSEP->pushBeginKeywords(YY_START); FL_BRK; }
"`begin_keywords"[ \t]*\"1800[+]VAMS\" { FL_FWD; yy_push_state(SAX); PARSEP->pushBeginKeywords(YY_START); FL_BRK; } /*Latest SV*/
"`end_keywords" { FL_FWD; yy_pop_state();
if (!PARSEP->popBeginKeywords()) yyerrorf("`end_keywords when not inside `begin_keywords block");
"`begin_keywords"[ \t]*\"1364-1995\" { FL_FWD; yy_push_state(V95); PARSEP->lexPushKeywords(YY_START); FL_BRK; }
"`begin_keywords"[ \t]*\"1364-2001\" { FL_FWD; yy_push_state(V01); PARSEP->lexPushKeywords(YY_START); FL_BRK; }
"`begin_keywords"[ \t]*\"1364-2001-noconfig\" { FL_FWD; yy_push_state(V01); PARSEP->lexPushKeywords(YY_START); FL_BRK; }
"`begin_keywords"[ \t]*\"1364-2005\" { FL_FWD; yy_push_state(V05); PARSEP->lexPushKeywords(YY_START); FL_BRK; }
"`begin_keywords"[ \t]*\"VAMS[-0-9.]*\" { FL_FWD; yy_push_state(VA5); PARSEP->lexPushKeywords(YY_START); FL_BRK; }
"`begin_keywords"[ \t]*\"1800-2005\" { FL_FWD; yy_push_state(S05); PARSEP->lexPushKeywords(YY_START); FL_BRK; }
"`begin_keywords"[ \t]*\"1800-2009\" { FL_FWD; yy_push_state(S09); PARSEP->lexPushKeywords(YY_START); FL_BRK; }
"`begin_keywords"[ \t]*\"1800-2012\" { FL_FWD; yy_push_state(S12); PARSEP->lexPushKeywords(YY_START); FL_BRK; }
"`begin_keywords"[ \t]*\"1800-2017\" { FL_FWD; yy_push_state(S17); PARSEP->lexPushKeywords(YY_START); FL_BRK; }
"`begin_keywords"[ \t]*\"1800[+]VAMS\" { FL_FWD; yy_push_state(SAX); PARSEP->lexPushKeywords(YY_START); FL_BRK; } /*Latest SV*/
"`end_keywords" { FL; yy_pop_state();
if (!PARSEP->lexPopKeywords()) yylval.fl->v3error("`end_keywords when not inside `begin_keywords block");
FL_BRK; }
/* Verilator */
@ -1003,12 +999,12 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"`systemc_implementation" { FL_FWD; BEGIN SYSCIMP; FL_BRK; }
"`systemc_interface" { FL_FWD; BEGIN SYSCINT; FL_BRK; }
"`verilator_config" { FL_FWD; BEGIN VLT; FL_BRK; }
"`verilog" { FL_FWD; BEGIN PARSEP->lastVerilogState(); FL_BRK; }
"`verilog" { FL_FWD; BEGIN PARSEP->lexKwdLastState(); FL_BRK; }
/* Errors */
"<<<<<<<"[^\n\r]* { FL_FWD; yyerrorf("version control conflict marker in file"); FL_BRK; }
"======="[^\n\r]* { FL_FWD; yyerrorf("version control conflict marker in file"); FL_BRK; }
">>>>>>>"[^\n\r]* { FL_FWD; yyerrorf("version control conflict marker in file"); FL_BRK; }
"<<<<<<<"[^\n\r]* { FL; yylval.fl->v3error("version control conflict marker in file"); FL_BRK; }
"======="[^\n\r]* { FL; yylval.fl->v3error("version control conflict marker in file"); FL_BRK; }
">>>>>>>"[^\n\r]* { FL; yylval.fl->v3error("version control conflict marker in file"); FL_BRK; }
/* If add to this list also add to V3LanguageWords.h */
}
@ -1031,157 +1027,17 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
/* Default rules - leave last */
<V95,V01,V05,VA5,S05,S09,S12,S17,SAX,VLT>{
"`"[a-zA-Z_0-9]+ { FL_FWD; PARSEP->errorPreprocDirective(yytext); FL_BRK; }
"`"[a-zA-Z_0-9]+ { FL; V3ParseImp::lexErrorPreprocDirective(yylval.fl, yytext); FL_BRK; }
"//"[^\n]* { FL_FWD; FL_BRK; } /* throw away single line comments */
. { FL; return yytext[0]; } /* return single char ops. */
}
/* Catch all - absolutely last */
<*>.|\n { FL_FWD; yyerrorf("Missing verilog.l rule: Default rule invoked in state %d: %s", YY_START, yytext); FL_BRK; }
<*>.|\n { FL; yylval.fl->v3error("Missing verilog.l rule: Default rule invoked in state "
<< YY_START << " '" << yytext << "'");
FL_BRK; }
%%
// Avoid code here as cl format misindents
// For implementation functions see V3ParseImp.cpp
int V3ParseImp::stateVerilogRecent() { return STATE_VERILOG_RECENT; }
void V3ParseImp::lexToken() {
// called from lexToBison, has a "this"
// Fetch next token from prefetch or real lexer
int token;
if (m_ahead) {
// We prefetched an extra token, give it back
m_ahead = false;
token = m_aheadVal.token;
yylval = m_aheadVal;
} else {
// Parse new token
token = yylexReadTok();
// yylval // Set by yylexReadTok()
}
// If a paren, read another
if (token == '(' //
|| token == yCONST__LEX //
|| token == yGLOBAL__LEX //
|| token == yLOCAL__LEX //
|| token == yNEW__LEX //
|| token == yVIRTUAL__LEX
// Never put yID_* here; below symbol table resolution would break
) {
if (debugFlex() >= 6) {
cout << " lexToken: reading ahead to find possible strength" << endl;
}
V3ParseBisonYYSType curValue = yylval; // Remember value, as about to read ahead
int nexttok = yylexReadTok();
m_ahead = true;
m_aheadVal = yylval;
m_aheadVal.token = nexttok;
yylval = curValue;
// Now potentially munge the current token
if (token == '('
&& (nexttok == ygenSTRENGTH || nexttok == ySUPPLY0 || nexttok == ySUPPLY1)) {
token = yP_PAR__STRENGTH;
} else if (token == yCONST__LEX) {
if (nexttok == yREF) {
token = yCONST__REF;
} else {
token = yCONST__ETC;
}
} else if (token == yGLOBAL__LEX) {
if (nexttok == yCLOCKING) {
token = yGLOBAL__CLOCKING;
} else if (v3Global.opt.pedantic()) {
token = yGLOBAL__ETC;
}
// Avoid 2009 "global" conflicting with old code when we can
else {
token = yaID__LEX;
yylval.strp = PARSEP->newString("global");
}
} else if (token == yLOCAL__LEX) {
if (nexttok == yP_COLONCOLON) {
token = yLOCAL__COLONCOLON;
} else {
token = yLOCAL__ETC;
}
} else if (token == yNEW__LEX) {
if (nexttok == '(') {
token = yNEW__PAREN;
} else {
token = yNEW__ETC;
}
} else if (token == yVIRTUAL__LEX) {
if (nexttok == yCLASS) {
token = yVIRTUAL__CLASS;
} else if (nexttok == yINTERFACE) {
token = yVIRTUAL__INTERFACE;
} else if (nexttok == yaID__ETC //
|| nexttok == yaID__LEX) {
// || nexttok == yaID__aINTERFACE // but we may not know interfaces yet.
token = yVIRTUAL__anyID;
} else {
token = yVIRTUAL__ETC;
}
}
// If add to above "else if", also add to "if (token" further above
}
// If an id, change the type based on symbol table
// Note above sometimes converts yGLOBAL to a yaID__LEX
if (token == yaID__LEX) {
VSymEnt* foundp;
if (VSymEnt* look_underp = SYMP->nextId()) {
UINFO(7, " lexToken: next id lookup forced under " << look_underp << endl);
foundp = look_underp->findIdFallback(*(yylval.strp));
// "consume" it. Must set again if want another token under temp scope
SYMP->nextId(NULL);
} else {
UINFO(7, " lexToken: find upward " << SYMP->symCurrentp() << " for '"
<< *(yylval.strp) << "'" << endl);
// if (debug()>=9) SYMP->symCurrentp()->dump(cout," -findtree: ", true);
foundp = SYMP->symCurrentp()->findIdFallback(*(yylval.strp));
}
if (foundp) {
AstNode* scp = foundp->nodep();
yylval.scp = scp;
UINFO(7, " lexToken: Found " << scp << endl);
if (VN_IS(scp, Typedef)) {
token = yaID__aTYPE;
} else if (VN_IS(scp, TypedefFwd)) {
token = yaID__aTYPE;
} else if (VN_IS(scp, Class)) {
token = yaID__aTYPE;
}
// Packages (and class static references) we could
// alternatively determine by looking for an yaID__LEX followed
// by yP_COLONCOLON (but we can't lookahead after an yaID__LEX
// as described above.)
else if (VN_IS(scp, Package)) {
token = yaID__aPACKAGE;
} else {
token = yaID__ETC;
}
} else { // Not found
yylval.scp = NULL;
token = yaID__ETC;
}
}
yylval.token = token;
// effectively returns yylval
}
int V3ParseImp::lexToBison() {
// Called as global since bison doesn't have our pointer
lexToken(); // sets yylval
m_prevBisonVal = m_curBisonVal;
m_curBisonVal = yylval;
// yylval.scp = NULL; // Symbol table not yet needed - no packages
if (debugFlex() >= 6 || debugBison() >= 6) { // --debugi-flex and --debugi-bison
cout << " {" << yylval.fl->filenameLetters() << yylval.fl->asciiLineCol()
<< "} lexToBison TOKEN=" << yylval.token << " " << tokenName(yylval.token);
if (yylval.token == yaID__ETC //
|| yylval.token == yaID__LEX //
|| yylval.token == yaID__aTYPE) {
cout << " strp='" << *(yylval.strp) << "'";
}
cout << endl;
}
return yylval.token;
}

File diff suppressed because it is too large Load Diff

View File

@ -1 +1 @@
source ../src/.gdbinit
source ~/SandBox/homecvs/v4/verilator/src/.gdbinit

View File

@ -9,7 +9,8 @@ BEGIN {
if (!$ENV{VERILATOR_ROOT} && -x "../bin/verilator") {
$ENV{VERILATOR_ROOT} = Cwd::getcwd()."/..";
}
$ENV{MAKE} ||= "make"
$ENV{MAKE} ||= "make";
$ENV{CXX} ||= "c++";
}
use Getopt::Long;
@ -1156,7 +1157,7 @@ sub compile {
if ($param{make_pli}) {
$self->oprint("Compile vpi\n") if $self->{verbose};
my @cmd = ('c++', @{$param{pli_flags}}, "-DIS_VPI",
my @cmd = ($ENV{CXX}, @{$param{pli_flags}}, "-DIS_VPI",
"$self->{t_dir}/$self->{pli_filename}");
$self->_run(logfile=>"$self->{obj_dir}/pli_compile.log",
@ -2193,12 +2194,12 @@ sub fst2vcd {
my $fn1 = shift;
my $fn2 = shift;
if (!-r $fn1) { $self->error("File does not exist $fn1\n"); return 0; }
my $cmd = qq{fst2vcd --help};
my $cmd = qq{fst2vcd -h};
print "\t$cmd\n" if $::Debug;
my $out = `$cmd`;
if (!$out || $out !~ /Usage:/) { $self->skip("No fst2vcd installed\n"); return 1; }
$cmd = qq{fst2vcd -e "$fn1" -o "$fn2"};
$cmd = qq{fst2vcd -e -f "$fn1" -o "$fn2"};
print "\t$cmd\n"; # Always print to help debug race cases
$out = `$cmd`;
return 1;
@ -2208,6 +2209,7 @@ sub fst_identical {
my $self = (ref $_[0]? shift : $Self);
my $fn1 = shift;
my $fn2 = shift;
return 0 if $self->errors || $self->skips || $self->unsupporteds;
my $tmp = $fn1.".vcd";
fst2vcd($fn1, $tmp);
return vcd_identical($tmp, $fn2);

View File

@ -67,8 +67,8 @@ public:
}
// return absolute scope of obj
static const char* rooted(const char* obj) {
static string buf;
ostringstream os;
static std::string buf;
std::ostringstream os;
os<<top()<<"."<<obj;
buf = os.str();
return buf.c_str();

View File

@ -1,4 +1,4 @@
%Error: t/t_alias2_unsup.v:39:4: Unsupported: alias statements
%Error-UNSUPPORTED: t/t_alias2_unsup.v:39:4: Unsupported: alias statements
39 | alias b = {a[3:0],a[7:4]};
| ^~~~~
%Error: Exiting due to

View File

@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(simulator => 1);
scenarios(linter => 1);
lint(
fails => $Self->{vlt_all},

View File

@ -1,4 +1,4 @@
%Error: t/t_alias_unsup.v:46:4: Unsupported: alias statements
%Error-UNSUPPORTED: t/t_alias_unsup.v:46:4: Unsupported: alias statements
46 | alias {a[7:0],a[15:8],a[23:16],a[31:24]} = b;
| ^~~~~
%Error: Exiting due to

View File

@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(simulator => 1);
scenarios(linter => 1);
lint(
fails => $Self->{vlt_all},

View File

@ -1,5 +1,5 @@
%Error: t/t_assoc_pattern_unsup.v:19:11: Unsupported: Assignment pattern applies against non struct/union data type: 'string[string]'
: ... In instance t
%Error-UNSUPPORTED: t/t_assoc_pattern_unsup.v:19:11: Unsupported: Assignment pattern applies against non struct/union data type: 'string[string]'
: ... In instance t
19 | a = '{ "f": "fooed", "b": "bared", default: "defaulted" };
| ^~
%Error: Exiting due to

View File

@ -1,2 +1,4 @@
%Error: Unsupported: [*] wildcard associative arrays
%Error-UNSUPPORTED: t/t_assoc_wildcard_unsup.v:25:19: Unsupported: [*] wildcard associative arrays
25 | string a [*];
| ^~
%Error: Exiting due to

View File

@ -9,35 +9,43 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(vlt_all => 1);
top_filename("t/t_case_huge.v");
compile(
verilator_flags2 => ["--stats --prof-cfuncs -CFLAGS '-pg' -LDFLAGS '-pg'"],
);
file_grep($Self->{stats}, qr/Optimizations, Tables created\s+(\d+)/i, 10);
file_grep($Self->{stats}, qr/Optimizations, Combined CFuncs\s+(\d+)/i, 10);
unlink $_ foreach (glob "$Self->{obj_dir}/gmon.out.*");
setenv('GMON_OUT_PREFIX', "$Self->{obj_dir}/gmon.out");
execute(
check_finished => 1,
);
my $gmon_path;
$gmon_path = $_ foreach (glob "$Self->{obj_dir}/gmon.out.*");
$gmon_path or error("Profiler did not create a gmon.out");
(my $gmon_base = $gmon_path) =~ s!.*[/\\]!!;
run(cmd => ["cd $Self->{obj_dir} && gprof $Self->{VM_PREFIX} $gmon_base > gprof.out"],
check_finished => 0);
run(cmd => ["cd $Self->{obj_dir} && $ENV{VERILATOR_ROOT}/bin/verilator_profcfunc gprof.out > cfuncs.out"],
check_finished => 0);
file_grep("$Self->{obj_dir}/cfuncs.out", qr/Overall summary by/);
if ($ENV{VERILATOR_TEST_NO_GPROF}) {
skip("Skipping due to VERILATOR_TEST_NO_GPROF");
} else {
dotest();
}
ok(1);
sub dotest {
compile(
verilator_flags2 => ["--stats --prof-cfuncs -CFLAGS '-pg' -LDFLAGS '-pg'"],
);
file_grep($Self->{stats}, qr/Optimizations, Tables created\s+(\d+)/i, 10);
file_grep($Self->{stats}, qr/Optimizations, Combined CFuncs\s+(\d+)/i, 10);
unlink $_ foreach (glob "$Self->{obj_dir}/gmon.out.*");
setenv('GMON_OUT_PREFIX', "$Self->{obj_dir}/gmon.out");
execute(
check_finished => 1,
);
my $gmon_path;
$gmon_path = $_ foreach (glob "$Self->{obj_dir}/gmon.out.*");
$gmon_path or error("Profiler did not create a gmon.out");
(my $gmon_base = $gmon_path) =~ s!.*[/\\]!!;
run(cmd => ["cd $Self->{obj_dir} && gprof $Self->{VM_PREFIX} $gmon_base > gprof.out"],
check_finished => 0);
run(cmd => ["cd $Self->{obj_dir} && $ENV{VERILATOR_ROOT}/bin/verilator_profcfunc gprof.out > cfuncs.out"],
check_finished => 0);
file_grep("$Self->{obj_dir}/cfuncs.out", qr/Overall summary by/);
}
1;

View File

@ -0,0 +1,9 @@
%Error-UNSUPPORTED: t/t_castdyn.v:12:11: Unsupported: $cast. Suggest try static cast.
: ... In instance t
12 | i = $cast(a, b);
| ^~~~~
%Error-UNSUPPORTED: t/t_castdyn.v:14:7: Unsupported: $cast. Suggest try static cast.
: ... In instance t
14 | $cast(a, b);
| ^~~~~
%Error: Exiting due to

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