'Merge from master for release.'
This commit is contained in:
commit
dd03d0f3c9
32
.travis.yml
32
.travis.yml
|
|
@ -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
28
Changes
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
793
bin/verilator
793
bin/verilator
File diff suppressed because it is too large
Load Diff
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
##############################################################################
|
||||
|
|
|
|||
47
configure.ac
47
configure.ac
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 --------------------------------------"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(); }
|
||||
|
||||
//======================================================================
|
||||
//======================================================================
|
||||
//======================================================================
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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) \
|
||||
{ \
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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::
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
46
src/V3Ast.h
46
src/V3Ast.h
|
|
@ -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(); }
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
254
src/V3AstNodes.h
254
src/V3AstNodes.h
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
128
src/V3Const.cpp
128
src/V3Const.cpp
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
129
src/V3EmitC.cpp
129
src/V3EmitC.cpp
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "V3Os.h"
|
||||
|
||||
#include <cerrno>
|
||||
#include <climits> // PATH_MAX (especially on FreeBSD)
|
||||
#include <cstdarg>
|
||||
#include <dirent.h>
|
||||
#include <fstream>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
166
src/V3ParseImp.h
166
src/V3ParseImp.h
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
102
src/V3PreLex.l
102
src/V3PreLex.l
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
289
src/V3Width.cpp
289
src/V3Width.cpp
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
402
src/verilog.l
402
src/verilog.l
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
2090
src/verilog.y
2090
src/verilog.y
File diff suppressed because it is too large
Load Diff
|
|
@ -1 +1 @@
|
|||
source ../src/.gdbinit
|
||||
source ~/SandBox/homecvs/v4/verilator/src/.gdbinit
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue