mirror of
https://github.com/verilator/verilator.git
synced 2026-10-06 01:54:01 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5e4ca4b76a | ||
|
|
1e938d0e90 | ||
|
|
f3704f4c05 | ||
|
|
8800efe953 | ||
|
|
a320c4584e | ||
|
|
3841850168 | ||
|
|
beb3885840 | ||
|
|
06967c0c46 | ||
|
|
9a382c572c | ||
|
|
44b6c371db | ||
|
|
00970be996 | ||
|
|
aca4ab015f | ||
|
|
68b63d5783 | ||
|
|
4b499f2bb1 | ||
|
|
ed17581f92 | ||
|
|
a46c4ec912 | ||
|
|
930cbeec17 | ||
|
|
10689ffaba | ||
|
|
29b0ea0af9 | ||
|
|
57d00946be | ||
|
|
ef51de72c9 | ||
|
|
c807bf1e0e | ||
|
|
2525b3fb05 | ||
|
|
9163ce0f6e | ||
|
|
d776638f53 | ||
|
|
83fff41312 | ||
|
|
dd7d9bc95b | ||
|
|
f8eabbc100 | ||
|
|
7ed18ac62d | ||
|
|
3ac707c645 | ||
|
|
8e9a1e0bf3 | ||
|
|
bc31b5d27a | ||
|
|
936738b750 | ||
|
|
7c3048ab9c | ||
|
|
64719f3ace | ||
|
|
a11a5f04d5 | ||
|
|
eb5c035dde | ||
|
|
c3887efbf3 | ||
|
|
495585830d | ||
|
|
6715cb9880 | ||
|
|
41b167d23c | ||
|
|
7ea8b54210 | ||
|
|
bcea39a858 | ||
|
|
fb560abac4 | ||
|
|
ba93a08b40 | ||
|
|
2be6b3481c | ||
|
|
6ef44a6fbb | ||
|
|
2afe40a0b5 | ||
|
|
e57d004718 | ||
|
|
d780d0aabb | ||
|
|
0f9e3f0767 | ||
|
|
381972c923 | ||
|
|
845d7ad718 | ||
|
|
f1b6c0c559 | ||
|
|
e39eddf3fe | ||
|
|
72218fb475 | ||
|
|
9a3e497c22 | ||
|
|
85d510cd48 | ||
|
|
786c65ea5f | ||
|
|
10e6f61125 | ||
|
|
cdd06e7236 | ||
|
|
48603c0ee2 | ||
|
|
63f30492be | ||
|
|
0e8772290d | ||
|
|
6cfc5798b0 | ||
|
|
6be275f5d4 |
@@ -3,6 +3,60 @@ Revision history for Verilator
|
|||||||
The contributors that suggested a given feature are shown in []. [by ...]
|
The contributors that suggested a given feature are shown in []. [by ...]
|
||||||
indicates the contributor was also the author of the fix; Thanks!
|
indicates the contributor was also the author of the fix; Thanks!
|
||||||
|
|
||||||
|
* Verilator 3.803 2010/07/10
|
||||||
|
|
||||||
|
*** Fix preprocessor preservation of newlines across macro substitutions.
|
||||||
|
|
||||||
|
**** Fix preprocessor stringification of nested macros.
|
||||||
|
|
||||||
|
**** Fix some constant parameter functions causing crash, bug253. [Nick Bowler]
|
||||||
|
|
||||||
|
**** Fix do {...} while() not requiring final semicolon.
|
||||||
|
|
||||||
|
* Verilator 3.802 2010/05/01
|
||||||
|
|
||||||
|
*** Support runtime access to public signal names.
|
||||||
|
|
||||||
|
*** Add /*verilator public_flat_rw*/ for timing-specific public access.
|
||||||
|
|
||||||
|
*** Fix word size to match uint64_t on -m64 systems, bug238. [Joe Eiler]
|
||||||
|
|
||||||
|
**** Improve error handling on slices of arrays, bug226. [by Byron Bradley]
|
||||||
|
|
||||||
|
**** Report errors when extra underscores used in meta-comments.
|
||||||
|
|
||||||
|
**** Fix bit reductions on multi-packed dimensions, bug227. [by Byron Bradley]
|
||||||
|
|
||||||
|
**** Fix removing $fscanf if assigned to unused var, bug248. [Ashutosh Das]
|
||||||
|
|
||||||
|
**** Fix "make install" with configure outside srcdir. [Stefan Wallentowitz]
|
||||||
|
|
||||||
|
**** Fix loop unroller out of memory; change --unroll-stmts. [Ashutosh Das]
|
||||||
|
|
||||||
|
**** Fix trace files with empty modules crashing some viewers.
|
||||||
|
|
||||||
|
**** Fix parsing single files > 2GB. [Jeffrey Short]
|
||||||
|
|
||||||
|
**** Fix installing data files as non-executable, bug168. [by Ahmed El-Mahmoudy]
|
||||||
|
|
||||||
|
* Verilator 3.801 2010/03/17
|
||||||
|
|
||||||
|
*** Support "break", "continue", "return".
|
||||||
|
|
||||||
|
*** Support "`default_nettype none|wire". [Dominic Plunkett]
|
||||||
|
|
||||||
|
**** Skip SystemC tests if not installed. [Iztok Jeras]
|
||||||
|
|
||||||
|
**** Fix clock-gates with non-AND complex logic, bug220. [Ashutosh Das]
|
||||||
|
|
||||||
|
**** Fix flushing VCD buffers on $stop. [Ashutosh Das]
|
||||||
|
|
||||||
|
**** Fix Mac OS-X compile issues, bug217. [Joshua Wise, Trevor Williams]
|
||||||
|
|
||||||
|
**** Fix make uninstall, bug216. [Iztok Jeras]
|
||||||
|
|
||||||
|
**** Fix parametrized defines with empty arguments.
|
||||||
|
|
||||||
* Verilator 3.800 2010/02/07
|
* Verilator 3.800 2010/02/07
|
||||||
|
|
||||||
Application visible changes:
|
Application visible changes:
|
||||||
|
|||||||
+96
-40
@@ -118,7 +118,7 @@ DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING COPYING.LESSER \
|
|||||||
src/.*ignore src/*.in src/*.cpp src/*.[chly] src/astgen src/bisonpre src/*fix \
|
src/.*ignore src/*.in src/*.cpp src/*.[chly] src/astgen src/bisonpre src/*fix \
|
||||||
src/*.pl src/*.pod \
|
src/*.pl src/*.pod \
|
||||||
test_*/.*ignore test_*/Makefile* test_*/*.cpp \
|
test_*/.*ignore test_*/Makefile* test_*/*.cpp \
|
||||||
test_*/*.pl test_*/*.v test_*/*.vc test_*/vlint \
|
test_*/*.pl test_*/*.v test_*/*.vc test_*/*.vh test_*/vlint \
|
||||||
test_verilated/vgen*.pl \
|
test_verilated/vgen*.pl \
|
||||||
test_regress/t/*.cpp \
|
test_regress/t/*.cpp \
|
||||||
test_regress/t/*.h \
|
test_regress/t/*.h \
|
||||||
@@ -134,10 +134,9 @@ INST_PROJ_FILES = \
|
|||||||
bin/verilator \
|
bin/verilator \
|
||||||
bin/verilator_includer \
|
bin/verilator_includer \
|
||||||
bin/verilator_profcfunc \
|
bin/verilator_profcfunc \
|
||||||
include/verilated.[chv]* \
|
|
||||||
include/verilated.mk \
|
include/verilated.mk \
|
||||||
include/verilatedos.[chv]* \
|
include/*.[chv]* \
|
||||||
include/verilated_*.[chv]* \
|
include/vltstd/*.[chv]* \
|
||||||
|
|
||||||
INST_PROJ_BIN_FILES = \
|
INST_PROJ_BIN_FILES = \
|
||||||
verilator_bin \
|
verilator_bin \
|
||||||
@@ -145,8 +144,6 @@ INST_PROJ_BIN_FILES = \
|
|||||||
|
|
||||||
DISTFILES := $(DISTFILES_INC)
|
DISTFILES := $(DISTFILES_INC)
|
||||||
|
|
||||||
VL_INST_MAN_FILES = verilator.1
|
|
||||||
|
|
||||||
ifeq ($(OBJCACHE_JOBS),)
|
ifeq ($(OBJCACHE_JOBS),)
|
||||||
ifneq ($(OBJCACHE_HOSTS),)
|
ifneq ($(OBJCACHE_HOSTS),)
|
||||||
export OBJCACHE_JOBS := -j $(shell objcache --jobs "$(OBJCACHE_HOSTS)")
|
export OBJCACHE_JOBS := -j $(shell objcache --jobs "$(OBJCACHE_HOSTS)")
|
||||||
@@ -238,11 +235,29 @@ internals.txt: internals.pod
|
|||||||
-rm -f $@
|
-rm -f $@
|
||||||
$(POD2TEXT) --loose $< > $@
|
$(POD2TEXT) --loose $< > $@
|
||||||
|
|
||||||
# See uninstall also
|
# See uninstall also - don't put wildcards in this variable, it might uninstall other stuff
|
||||||
VL_INST_BIN_FILES = verilator verilator_bin verilator_bin_dbg \
|
VL_INST_BIN_FILES = verilator verilator_bin verilator_bin_dbg \
|
||||||
verilator_includer verilator_profcfunc
|
verilator_includer verilator_profcfunc
|
||||||
# Some scripts go into both the search path and pkgdatadir,
|
# Some scripts go into both the search path and pkgdatadir,
|
||||||
# so they can be found by the user, and under $VERILATOR_ROOT.
|
# so they can be found by the user, and under $VERILATOR_ROOT.
|
||||||
|
|
||||||
|
# See uninstall also - don't put wildcards in this variable, it might uninstall other stuff
|
||||||
|
VL_INST_MAN_FILES = verilator.1
|
||||||
|
|
||||||
|
VL_INST_INC_BLDDIR_FILES = \
|
||||||
|
include/verilated.mk \
|
||||||
|
|
||||||
|
# Files under srcdir, instead of build time
|
||||||
|
VL_INST_INC_SRCDIR_FILES = \
|
||||||
|
include/*.[chv]* \
|
||||||
|
include/vltstd/*.[chv]* \
|
||||||
|
|
||||||
|
VL_INST_DATA_SRCDIR_FILES = \
|
||||||
|
test_v/*.[chv]* \
|
||||||
|
test_c/*.[chv]* test_c/Makefile test_c/Makefile_obj \
|
||||||
|
test_sc/*.[chv]* test_sc/Makefile test_sc/Makefile_obj \
|
||||||
|
test_sp/*.[chv]* test_sp/Makefile test_sp/Makefile_obj \
|
||||||
|
|
||||||
installbin:
|
installbin:
|
||||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(bindir)
|
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(bindir)
|
||||||
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator $(DESTDIR)$(bindir)/verilator )
|
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator $(DESTDIR)$(bindir)/verilator )
|
||||||
@@ -255,26 +270,52 @@ installbin:
|
|||||||
installman: $(VL_INST_MAN_FILES)
|
installman: $(VL_INST_MAN_FILES)
|
||||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(mandir)/man1
|
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(mandir)/man1
|
||||||
for p in $(VL_INST_MAN_FILES) ; do \
|
for p in $(VL_INST_MAN_FILES) ; do \
|
||||||
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(mandir)/man1/$$p; \
|
$(INSTALL_DATA) $$p $(DESTDIR)$(mandir)/man1/$$p; \
|
||||||
done
|
done
|
||||||
|
|
||||||
installdata:
|
installdata:
|
||||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/include/vltstd $(DESTDIR)$(pkgdatadir)/examples
|
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/include/vltstd
|
||||||
cp -r include/*.* $(DESTDIR)$(pkgdatadir)/include
|
for p in $(VL_INST_INC_BLDDIR_FILES) ; do \
|
||||||
cp -r ${srcdir}/include/*.* $(DESTDIR)$(pkgdatadir)/include
|
$(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/$$p; \
|
||||||
cp -r ${srcdir}/include/vltstd/*.* $(DESTDIR)$(pkgdatadir)/include/vltstd
|
done
|
||||||
cp -r ${srcdir}/test_c $(DESTDIR)$(pkgdatadir)/examples
|
cd $(srcdir) \
|
||||||
cp -r ${srcdir}/test_sc $(DESTDIR)$(pkgdatadir)/examples
|
; for p in $(VL_INST_INC_SRCDIR_FILES) ; do \
|
||||||
cp -r ${srcdir}/test_sp $(DESTDIR)$(pkgdatadir)/examples
|
$(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/$$p; \
|
||||||
cp -r ${srcdir}/test_v $(DESTDIR)$(pkgdatadir)/examples
|
done
|
||||||
|
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_c
|
||||||
|
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_sc
|
||||||
|
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_sp
|
||||||
|
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_v
|
||||||
|
cd $(srcdir) \
|
||||||
|
; for p in $(VL_INST_DATA_SRCDIR_FILES) ; do \
|
||||||
|
$(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/examples/$$p; \
|
||||||
|
done
|
||||||
|
|
||||||
|
# We don't trust rm -rf, so rmdir instead as it will fail if user put in other files
|
||||||
|
uninstall:
|
||||||
|
-cd $(DESTDIR)$(bindir) && rm -f $(VL_INST_BIN_FILES)
|
||||||
|
-cd $(DESTDIR)$(pkgdatadir)/bin && rm -f $(VL_INST_BIN_FILES)
|
||||||
|
-cd $(DESTDIR)$(mandir)/man1 && rm -f $(VL_INST_MAN_FILES)
|
||||||
|
-cd $(DESTDIR)$(pkgdatadir) && rm -f $(VL_INST_INC_BLDDIR_FILES)
|
||||||
|
-cd $(DESTDIR)$(pkgdatadir) && rm -f $(VL_INST_INC_SRCDIR_FILES)
|
||||||
|
-cd $(DESTDIR)$(pkgdatadir)/examples && rm -f $(VL_INST_DATA_SRCDIR_FILES)
|
||||||
|
-rmdir $(DESTDIR)$(pkgdatadir)/bin
|
||||||
|
-rmdir $(DESTDIR)$(pkgdatadir)/include/vltstd
|
||||||
|
-rmdir $(DESTDIR)$(pkgdatadir)/include
|
||||||
|
-rmdir $(DESTDIR)$(pkgdatadir)/examples/test_c
|
||||||
|
-rmdir $(DESTDIR)$(pkgdatadir)/examples/test_sc
|
||||||
|
-rmdir $(DESTDIR)$(pkgdatadir)/examples/test_sp
|
||||||
|
-rmdir $(DESTDIR)$(pkgdatadir)/examples/test_v
|
||||||
|
-rmdir $(DESTDIR)$(pkgdatadir)/examples
|
||||||
|
-rmdir $(DESTDIR)$(pkgdatadir)
|
||||||
|
|
||||||
VL_INST_DATA_FILES = verilator.1
|
|
||||||
install: all_nomsg installbin installman installdata install-msg
|
install: all_nomsg installbin installman installdata install-msg
|
||||||
|
|
||||||
install-here: installman ftp
|
install-here: installman ftp
|
||||||
|
|
||||||
ifeq ($(VERILATOR_AUTHOR_SITE),1) # Local... Else don't burden users
|
ifeq ($(VERILATOR_AUTHOR_SITE),1) # Local... Else don't burden users
|
||||||
DIRPROJECT := $(shell project_dir --project)
|
DIRPROJECT := $(shell project_dir --project)
|
||||||
|
VERILATOR_CAD_DIR = $(CAD_DIR)/verilator/$(DISTNAMEREV)/$(DIRPROJECT_ARCH)
|
||||||
INST_PROJ_CVS = cp_if_cvs_diff
|
INST_PROJ_CVS = cp_if_cvs_diff
|
||||||
|
|
||||||
install-project: dist
|
install-project: dist
|
||||||
@@ -282,7 +323,7 @@ install-project: dist
|
|||||||
strip verilator_bin*
|
strip verilator_bin*
|
||||||
$(MAKE) install-project-quick
|
$(MAKE) install-project-quick
|
||||||
for p in verilator.1 ; do \
|
for p in verilator.1 ; do \
|
||||||
$(INSTALL_PROGRAM) -m 0666 $$p $(DIRPROJECT_PREFIX)/man/man1/$$p; \
|
$(INSTALL_DATA) $$p $(DIRPROJECT_PREFIX)/man/man1/$$p; \
|
||||||
done
|
done
|
||||||
$(INST_PROJ_CVS) $(DISTNAME).tgz $(DIRPROJECT)/hw/utils/verilator/verilator.tgz
|
$(INST_PROJ_CVS) $(DISTNAME).tgz $(DIRPROJECT)/hw/utils/verilator/verilator.tgz
|
||||||
rm $(DISTNAME).tgz
|
rm $(DISTNAME).tgz
|
||||||
@@ -299,6 +340,34 @@ endif
|
|||||||
for p in $(INST_PROJ_BIN_FILES) ; do \
|
for p in $(INST_PROJ_BIN_FILES) ; do \
|
||||||
$(INST_PROJ_CVS) $$p $(DIRPROJECT)/hw/utils/verilator/$$p-$(DIRPROJECT_ARCH); \
|
$(INST_PROJ_CVS) $$p $(DIRPROJECT)/hw/utils/verilator/$$p-$(DIRPROJECT_ARCH); \
|
||||||
done
|
done
|
||||||
|
|
||||||
|
install-cadtools: dist
|
||||||
|
@echo "Install-project to $(CAD_DIR)"
|
||||||
|
strip verilator_bin*
|
||||||
|
$(MAKE) install-cadtools-quick
|
||||||
|
$(SHELL) ${srcdir}/mkinstalldirs $(VERILATOR_CAD_DIR)/man/man1
|
||||||
|
for p in verilator.1 ; do \
|
||||||
|
$(INSTALL_DATA) $$p $(VERILATOR_CAD_DIR)/man/man1/$$p; \
|
||||||
|
done
|
||||||
|
$(INST_PROJ_CVS) $(DISTNAME).tgz $(VERILATOR_CAD_DIR)/verilator.tgz
|
||||||
|
rm $(DISTNAME).tgz
|
||||||
|
|
||||||
|
install-cadtools-quick:
|
||||||
|
ifeq ($(CFG_WITH_DEFENV),yes)
|
||||||
|
@echo "%Error: Reconfigure with './configure --disable-defenv' to avoid hardcoded paths."
|
||||||
|
false
|
||||||
|
endif
|
||||||
|
@echo "Install-cadtools-quick (no strip) to $(VERILATOR_CAD_DIR)"
|
||||||
|
$(SHELL) ${srcdir}/mkinstalldirs $(VERILATOR_CAD_DIR)/include/vltstd
|
||||||
|
$(SHELL) ${srcdir}/mkinstalldirs $(VERILATOR_CAD_DIR)/bin
|
||||||
|
for p in $(INST_PROJ_FILES) ; do \
|
||||||
|
$(INST_PROJ_CVS) $$p $(VERILATOR_CAD_DIR)/$$p; \
|
||||||
|
done
|
||||||
|
for p in $(INST_PROJ_BIN_FILES) ; do \
|
||||||
|
$(INST_PROJ_CVS) $$p $(VERILATOR_CAD_DIR)/$$p; \
|
||||||
|
done
|
||||||
|
|
||||||
|
# VERILATOR_AUTHOR_SITE
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ftp: info
|
ftp: info
|
||||||
@@ -306,33 +375,19 @@ ftp: info
|
|||||||
install-msg:
|
install-msg:
|
||||||
@echo "Installed!"
|
@echo "Installed!"
|
||||||
@echo
|
@echo
|
||||||
@echo "Add to your startup file (for bash or csh, as appropriate):"
|
@echo "Fod documentation see 'man verilator' or 'verilator --help'"
|
||||||
@echo " export VERILATOR_ROOT="`pwd`
|
@echo "For forums and to report bugs see http://www.veripool.org/verilator"
|
||||||
@echo " setenv VERILATOR_ROOT "`pwd` " ; export VERILATOR_ROOT "
|
|
||||||
@echo
|
|
||||||
@echo "See 'verilator.txt' for documentation."
|
|
||||||
@echo
|
@echo
|
||||||
|
|
||||||
uninstall:
|
IN_WILD := ${srcdir}/*.in ${srcdir}/*/*.in
|
||||||
-cd $(DESTDIR)$(mandir)/man1 && rm -f $(VL_INST_MAN_FILES)
|
|
||||||
-cd $(DESTDIR)$(bindir) && rm -f $(VL_INST_BIN_FILES)
|
|
||||||
-rm -f $(DESTDIR)$(pkgdatadir)
|
|
||||||
|
|
||||||
# autoheader might not change config_build.h.in, so touch a stamp file.
|
# autoheader might not change config_build.h.in, so touch it
|
||||||
IN_WILD := ${srcdir}/*.in ${srcdir}/*/*.in ${srcdir}/*/*/*.in \
|
${srcdir}/config_build.h: ${srcdir}/config_build.h.in configure
|
||||||
*.in */*.in */*.in
|
|
||||||
|
|
||||||
${srcdir}/config_build.h.in: stamp-h.in
|
|
||||||
${srcdir}/stamp-h.in: configure.ac $(wildcard $(IN_WILD))
|
|
||||||
cd ${srcdir} && autoheader
|
cd ${srcdir} && autoheader
|
||||||
echo timestamp > ${srcdir}/stamp-h.in
|
touch $@
|
||||||
config_build.h: stamp-h
|
Makefile: Makefile.in config.status $(IN_WILD)
|
||||||
stamp-h: config_build.h.in config.status
|
|
||||||
./config.status
|
|
||||||
Makefile: Makefile.in config.status
|
|
||||||
./config.status
|
|
||||||
src/Makefile: src/Makefile.in config.status
|
|
||||||
./config.status
|
./config.status
|
||||||
|
src/Makefile: src/Makefile.in Makefile
|
||||||
config.status: configure
|
config.status: configure
|
||||||
./config.status --recheck
|
./config.status --recheck
|
||||||
configure: configure.ac
|
configure: configure.ac
|
||||||
@@ -382,6 +437,7 @@ DISTCONFIG = ${srcdir}/src/config_build.h.in
|
|||||||
DISTTITLE := $(shell sed -e '/DTVERSION/!d' -e 's/[^0-9]*\([0-9.a-z]*\).*/verilator-\1/' -e 's/v/V/' -e q $(DISTCONFIG))
|
DISTTITLE := $(shell sed -e '/DTVERSION/!d' -e 's/[^0-9]*\([0-9.a-z]*\).*/verilator-\1/' -e 's/v/V/' -e q $(DISTCONFIG))
|
||||||
DISTNAME := $(shell sed -e '/DTVERSION/!d' -e 's/[^0-9]*\([0-9.a-z]*\).*/verilator-\1/' -e q $(DISTCONFIG))
|
DISTNAME := $(shell sed -e '/DTVERSION/!d' -e 's/[^0-9]*\([0-9.a-z]*\).*/verilator-\1/' -e q $(DISTCONFIG))
|
||||||
DISTDATEPRE := $(shell sed -e '/DTVERSION/!d' -e 's/.*\([1-2][0-9][0-9][0-9].[0-9]*[0-9].[0-9]*[0-9]\).*/\1/' -e q $(DISTCONFIG))
|
DISTDATEPRE := $(shell sed -e '/DTVERSION/!d' -e 's/.*\([1-2][0-9][0-9][0-9].[0-9]*[0-9].[0-9]*[0-9]\).*/\1/' -e q $(DISTCONFIG))
|
||||||
|
DISTNAMEREV := $(shell sed -e '/DTVERSION/!d' -e 's/.*verilator_\([^"]*\).*/\1/' -e q src/config_rev.h)
|
||||||
|
|
||||||
DISTTAGNAME := $(subst .,_,$(subst -,_,$(DISTNAME)))
|
DISTTAGNAME := $(subst .,_,$(subst -,_,$(DISTNAME)))
|
||||||
DISTDATE := $(subst /,-,$(DISTDATEPRE))
|
DISTDATE := $(subst /,-,$(DISTDATEPRE))
|
||||||
|
|||||||
@@ -6,129 +6,134 @@
|
|||||||
// Version 2.0.
|
// Version 2.0.
|
||||||
|
|
||||||
|
|
||||||
Features:
|
Language support:
|
||||||
Latch optimizations {Need here}
|
* Fix ordering of each bit separately in a signal (mips)
|
||||||
Task I/Os connecting to non-simple variables.
|
|
||||||
Fix ordering of each bit separately in a signal (mips)
|
|
||||||
assign b[3:0] = b[7:4]; assign b[7:4] = in;
|
assign b[3:0] = b[7:4]; assign b[7:4] = in;
|
||||||
Support gate primitives/ cell libraries from xilinx, etc
|
* Support UDP gate primitives/ cell libraries
|
||||||
Assign dont_care value to an 1'bzzz assignment
|
(have code for combos - problem is sequential udps)
|
||||||
Function to eval combo logic after /*verilator public*/ functions [gwaters]
|
* Function to eval combo logic after /*verilator public*/ functions [gwaters]
|
||||||
Support generated clocks (correctness)
|
* Support generated clocks (correctness)
|
||||||
?gcov coverage
|
* Real numbers
|
||||||
Selectable SystemC types based on widths (see notes below)
|
* Recursive functions
|
||||||
Coverage
|
* Verilog configuration files
|
||||||
Points should be per-scope like everything else rather then per-module
|
* Structs/unions (have starting point)
|
||||||
Expression coverage (see notes)
|
* DPI to define C/C++ calls from Verilog
|
||||||
Constant functions for widths, etc, IE "input [log2(PARAM):0] xx;"
|
* Expression coverage (see notes)
|
||||||
More Verilog 2001 Support
|
* Better tristate support
|
||||||
(* *) Attributes (just ignore -- preprocessor?)
|
|
||||||
Real numbers (NEVER)
|
|
||||||
Recursive functions (NEVER)
|
|
||||||
Verilog configuration files (NEVER)
|
|
||||||
DPI to define C/C++ calls from Verilog
|
|
||||||
|
|
||||||
Long-term Features
|
Long-term Features
|
||||||
Assertions
|
* Assertions
|
||||||
VHDL parser [Philips]
|
* Tristate support
|
||||||
Tristate support
|
* Multithreaded execution
|
||||||
SystemPerl integration
|
|
||||||
Multithreaded execution
|
Configure/Make/Install
|
||||||
|
* Full MSVC++ compilation (does scons support this?) (4.000?)
|
||||||
|
* Distribute with flex/bison already expanded?
|
||||||
|
Flex library not needed. Probably too difficult to be worth it.
|
||||||
|
* Integrate SystemPerl coverage
|
||||||
|
(Note in /usr/include there are no upper cased include files.)
|
||||||
|
Coverage.pm -- Need all functionality, but in C?
|
||||||
|
Coverage/Item.pm -- Need all functionality, but in C?
|
||||||
|
Coverage/ItemKey.pm -- Need all functionality, but in C?
|
||||||
|
sp_preproc -- Some steps in here need to be moved to generated C
|
||||||
|
src/Sp.cpp -- n/a
|
||||||
|
src/SpCommon.h -- mostly overlaps verilatedos.h
|
||||||
|
src/SpCoverage.cpp/h -- All needed
|
||||||
|
src/SpFunctor.cpp/h -- No longer used
|
||||||
|
src/SpTraceVcd.cpp/h -- MOVED
|
||||||
|
src/SpTraceVcdC.cpp/h -- MOVED
|
||||||
|
src/sp_log.cpp/h -- Not needed
|
||||||
|
src/systemperl.h -- some stuff may be cut
|
||||||
|
vcoverage -- Need all functionality, but in C?
|
||||||
|
|
||||||
Testing:
|
Testing:
|
||||||
Capture all inputs into global "rerun it" file
|
* Move test_c/sp/v/verilated into test_regress format (4.000?)
|
||||||
Code to make wrapper that sets signals, so can do comparison checks
|
* Capture all inputs into global "rerun it" file
|
||||||
New random program generator
|
* Code to make wrapper that sets signals, so can do comparison checks
|
||||||
Better graph viewer with search and zoom
|
* New random program generator
|
||||||
Port and test against opencores.org code
|
* Better graph viewer with search and zoom
|
||||||
|
* Port and test against opencores.org code
|
||||||
|
|
||||||
Usability:
|
Usability:
|
||||||
Better reporting of unopt problems, including what lines of code
|
* Detect and pre-remove most UNOPTFLATs (4.000)
|
||||||
Report more errors (all of them?) before exiting [Eugene Weber]
|
* Better reporting of unopt problems, including what lines of code
|
||||||
|
* Report more errors (all of them?) before exiting [Eugene Weber]
|
||||||
|
* Auto-create scons config files
|
||||||
|
* Print version/etc message at runtime. (4.000?)
|
||||||
|
Include number of lines of code, percent comments, code complexity measurement
|
||||||
|
<-80chars------------------------------------------------------------------->
|
||||||
|
Verilator 3.600 - fast, free, open-sourced. Copyright 2001-2010.
|
||||||
|
Verilated #### modules, #### instances, ##### sigs,
|
||||||
|
#### non-comment lines, ##### ops, ### KB model size
|
||||||
|
* Default the --l2name to remove extra "v" level of hierarchy (flag to make "top")
|
||||||
|
|
||||||
Internal Code:
|
Internal Code:
|
||||||
Eliminate the AstNUser* passed to all visitors; its only needed in V3Width,
|
* Eliminate the AstNUser* passed to all visitors; its only needed in V3Width,
|
||||||
and removing it will speed up and simplify all the other code.
|
and removing it will speed up and simplify all the other code.
|
||||||
V3Graph should be templated container type, taking in Vertex + Edge types
|
* V3Graph should be templated container type, taking in Vertex + Edge types
|
||||||
|
* Rename V3PreLex etc to match VerilogPerl filenames
|
||||||
|
* Instead of string, have an VEncodedString/VIdString which contains __DOT__ish
|
||||||
|
things, to reduce bugs. Also add _20 trailing space to \ encoded names. (4.000)
|
||||||
|
|
||||||
|
Runtime:
|
||||||
|
* New evalulation loop ~/src/verilator/notes/event_loop.txt (4.000?)
|
||||||
|
* Remove all private internal functions from top level wrapper header, move
|
||||||
|
to new level (4.000?)
|
||||||
|
* Completely standalone simulation (4.000)
|
||||||
|
main() records arguments for $test$plusvars
|
||||||
|
instantiates top,
|
||||||
|
does tracing (support $dump?)
|
||||||
|
calls top->simulateForever()
|
||||||
|
exits
|
||||||
|
|
||||||
Performance:
|
Performance:
|
||||||
Constant propagation
|
* Latch optimizations
|
||||||
|
* Constant propagation
|
||||||
Extra cleaning AND: 1 & ((VARREF >> 1) | ((&VARREF >> 1) & VARREF))
|
Extra cleaning AND: 1 & ((VARREF >> 1) | ((&VARREF >> 1) & VARREF))
|
||||||
Extra shift (perhaps due to clean): if (1 & CAST (VARREF >> #))
|
Extra shift (perhaps due to clean): if (1 & CAST (VARREF >> #))
|
||||||
Gated clock and latch conversion to flops. [JeanPaul Vanitegem]
|
* Gated clock and latch conversion to flops. [JeanPaul Vanitegem]
|
||||||
Could propagate the AND into pos/negedges and let domaining optimize.
|
Could propagate the AND into pos/negedges and let domaining optimize.
|
||||||
Negedge reset
|
* Negedge reset
|
||||||
Switch to remove negedges that don't matter
|
Switch to remove negedges that don't matter
|
||||||
Can't remove async resets from control flops (like in syncronizers)
|
Can't remove async resets from control flops (like in syncronizers)
|
||||||
If all references to array have a constant index, blow up into separate signals-per-index
|
* If all references to array have a constant index, blow up into separate signals-per-index
|
||||||
Multithreaded execution
|
* Bit-multiply for faster bit swapping and a=b[1,3,2] random bit reorderings.
|
||||||
Bit-multiply for faster bit swapping and a=b[1,3,2] random bit reorderings.
|
* Move _last sets and all other combo logic inside master
|
||||||
Move _last sets and all other combo logic inside master
|
|
||||||
if() that triggers on all possible sense items
|
if() that triggers on all possible sense items
|
||||||
Rewrite and combine V3Life, V3Subst
|
* Rewrite and combine V3Life, V3Subst
|
||||||
If block temp only ever set in one place to constant, propagate it
|
If block temp only ever set in one place to constant, propagate it
|
||||||
Used in t_mem for array delayed assignments
|
Used in t_mem for array delayed assignments
|
||||||
Replace variables if set later in same cfunc branch
|
Replace variables if set later in same cfunc branch
|
||||||
See for example duplicate sets of _narrow in cycle 90/91 of t_select_plusloop
|
See for example duplicate sets of _narrow in cycle 90/91 of t_select_plusloop
|
||||||
Same assignment on both if branches
|
* Same assignment on both if branches
|
||||||
"if (a) { ... b=2; } else { ... b=2;}" -> "b=2; if ..."
|
"if (a) { ... b=2; } else { ... b=2;}" -> "b=2; if ..."
|
||||||
Careful though, as b could appear in the statement or multiple times in statement
|
Careful though, as b could appear in the statement or multiple times in statement
|
||||||
(Could just require exatly two 'b's in statement)
|
(Could just require exatly two 'b's in statement)
|
||||||
Simplify XOR/XNOR/AND/OR bit selection trees
|
* Simplify XOR/XNOR/AND/OR bit selection trees
|
||||||
Foo = A[1] ^ A[2] ^ A[3] etc are better as ^ ( A & 32'b...1110 )
|
Foo = A[1] ^ A[2] ^ A[3] etc are better as ^ ( A & 32'b...1110 )
|
||||||
Combine variables into wider elements
|
* Combine variables into wider elements
|
||||||
Parallel statements on different bits should become single signal
|
Parallel statements on different bits should become single signal
|
||||||
Variables that are always consumed in "parallel" can be joined
|
Variables that are always consumed in "parallel" can be joined
|
||||||
Duplicate assignments in gate optimization
|
* Duplicate assignments in gate optimization
|
||||||
Common to have many separate posedge blocks, each with identical
|
Common to have many separate posedge blocks, each with identical
|
||||||
reset_r <= rst_in
|
reset_r <= rst_in
|
||||||
*If signal is used only once (not counting trace), always gate substitute
|
* If signal is used only once (not counting trace), always gate substitute
|
||||||
Don't merge if any combining would form circ logic (out goes back to in)
|
Don't merge if any combining would form circ logic (out goes back to in)
|
||||||
Multiple assignments each bit can become single assign with concat
|
* Multiple assignments each bit can become single assign with concat
|
||||||
Make sure a SEL of a CONCAT can get the single bit back.
|
Make sure a SEL of a CONCAT can get the single bit back.
|
||||||
Usually blocks/values
|
* Usually blocks/values
|
||||||
Enable only after certain time, so VL_TIME_I(32) > 0x1e gets eliminated out
|
Enable only after certain time, so VL_TIME_I(32) > 0x1e gets eliminated out
|
||||||
Better ordering of a<=b, b<=c, put all refs to 'b' next to each other to optimize caching
|
* Better ordering of a<=b, b<=c, put all refs to 'b' next to each other to optimize caching
|
||||||
Allow Split of case statements without a $display/$stop
|
* Allow Split of case statements without a $display/$stop
|
||||||
I-cache packing improvements (what/how?)
|
* I-cache packing improvements (what/how?)
|
||||||
Data cache organization (order of vars in class)
|
* Data cache organization (order of vars in class)
|
||||||
First have clocks,
|
First have clocks,
|
||||||
then bools instead of uint32_t's
|
then bools instead of uint32_t's
|
||||||
then based on what sense list they come from, all outputs, then all inputs
|
then based on what sense list they come from, all outputs, then all inputs
|
||||||
finally have any signals part of a "usually" block, or constant.
|
finally have any signals part of a "usually" block, or constant.
|
||||||
Rather then tracking widths, have a MSB...LSB of this expression
|
* Rather then tracking widths, have a MSB...LSB of this expression
|
||||||
(or better, a bitmask of bits relevant in this expression)
|
(or better, a bitmask of bits relevant in this expression)
|
||||||
Track recirculation and convert into clock-enables
|
* Track recirculation and convert into clock-enables
|
||||||
Clock enables should become new clocking domains for speed
|
* Clock enables should become new clocking domains for speed
|
||||||
If floped(a) & flopped(b) and no other a&b, then instead flop(a&b).
|
* If floped(a) & flopped(b) and no other a&b, then instead flop(a&b).
|
||||||
Sort by output bitselects so can combine more assignments (see DDP example dx_dm signal)
|
* Sort by output bitselects so can combine more assignments (see DDP example dx_dm signal)
|
||||||
|
|
||||||
All of the temp vars that get set, exp pre_ vars and never feedback
|
|
||||||
(not flops) don't need to be stored in the structs, but instead can
|
|
||||||
be per-invocation, and even better register-colored-like to reuse
|
|
||||||
the space. This will greatly reduce the data footprint.
|
|
||||||
|
|
||||||
|
|
||||||
//**********************************************************************
|
|
||||||
//* Eventual tristate bus Stuff allowed (old verilator)
|
|
||||||
|
|
||||||
1) Tristate assignments must be continuous assignments
|
|
||||||
The RHS of a tristate assignment can be the following
|
|
||||||
a) a node (tristate or non-tristate)
|
|
||||||
b) a constant (must be all or no z's)
|
|
||||||
x'b0, x'bz, x{x'bz}, x{x'b0} -> are allowed
|
|
||||||
c) a conditional whose possible values are (a) or (b)
|
|
||||||
|
|
||||||
2) One can lose that fact that a node is a tristate node. This happens
|
|
||||||
if a tristate node is assigned to a 'standard' node, or is used on
|
|
||||||
RHS of a conditional. The following infer tristate signals:
|
|
||||||
a) inout <SIGNAL>
|
|
||||||
b) tri <SIGNAL>
|
|
||||||
c) assigning to 'Z' (maybe through a conditional)
|
|
||||||
Note: tristate-ness of an output port determined only by
|
|
||||||
statements in the module (not the instances it calls)
|
|
||||||
|
|
||||||
4) Tristate variables can't be multidimensional arrays
|
|
||||||
5) Only check tristate contention between modules (not within!)
|
|
||||||
6) Only simple compares with 'Z' are allowed (===)
|
|
||||||
|
|
||||||
|
|||||||
+44
-23
@@ -878,7 +878,7 @@ section below for descriptions of some of the files that were created.
|
|||||||
We then can compile it
|
We then can compile it
|
||||||
|
|
||||||
cd obj_dir
|
cd obj_dir
|
||||||
make -f Vour.mk Vour
|
make -j -f Vour.mk Vour
|
||||||
|
|
||||||
(Verilator included a default compile rule and link rule, since we used
|
(Verilator included a default compile rule and link rule, since we used
|
||||||
--exe and passed a .cpp file on the Verilator command line. You can also
|
--exe and passed a .cpp file on the Verilator command line. You can also
|
||||||
@@ -944,9 +944,8 @@ Verilator by replacing the verilator --sp flag in the previous step with
|
|||||||
|
|
||||||
We then can compile it
|
We then can compile it
|
||||||
|
|
||||||
make -f Vour.mk Vour__ALL.a
|
make -j -f Vour.mk Vour__ALL.a
|
||||||
make -f Vour.mk ../sc_main.o
|
make -j -f Vour.mk ../sc_main.o verilated.o
|
||||||
make -f Vour.mk verilated.o
|
|
||||||
|
|
||||||
And link with SystemC. Note your path to the libraries may vary,
|
And link with SystemC. Note your path to the libraries may vary,
|
||||||
depending on the operating system.
|
depending on the operating system.
|
||||||
@@ -1390,20 +1389,20 @@ Verilator configuration commands.
|
|||||||
|
|
||||||
=item coverage_off [-file "<filename>" [-lines <line> [ - <line> ]]]
|
=item coverage_off [-file "<filename>" [-lines <line> [ - <line> ]]]
|
||||||
|
|
||||||
Disable coverage for the specified filename (or all files if ommitted) and
|
Disable coverage for the specified filename (or all files if omitted) and
|
||||||
range of line numbers (or all lines if ommitted). Often used to ignore an
|
range of line numbers (or all lines if omitted). Often used to ignore an
|
||||||
entire module for coverage analysis purposes.
|
entire module for coverage analysis purposes.
|
||||||
|
|
||||||
=item lint_off -msg <message> [-file "<filename>" [-lines <line> [ - <line>]]]
|
=item lint_off -msg <message> [-file "<filename>" [-lines <line> [ - <line>]]]
|
||||||
|
|
||||||
Disables the specified lint warning in the specified filename (or all files
|
Disables the specified lint warning in the specified filename (or all files
|
||||||
if ommitted) and range of line numbers (or all lines if ommitted).
|
if omitted) and range of line numbers (or all lines if omitted).
|
||||||
|
|
||||||
=item tracing_off [-file "<filename>" [-lines <line> [ - <line> ]]]
|
=item tracing_off [-file "<filename>" [-lines <line> [ - <line> ]]]
|
||||||
|
|
||||||
Disable waveform tracing for all future signals declared in the specified
|
Disable waveform tracing for all future signals declared in the specified
|
||||||
filename (or all files if ommitted) and range of line numbers (or all lines
|
filename (or all files if omitted) and range of line numbers (or all lines
|
||||||
if ommitted).
|
if omitted).
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
@@ -1630,7 +1629,8 @@ Used after a signal declaration to indicate the signal is used to gate a
|
|||||||
clock, and the user takes responsibility for insuring there are no races
|
clock, and the user takes responsibility for insuring there are no races
|
||||||
related to it. (Typically by adding a latch, and running static timing
|
related to it. (Typically by adding a latch, and running static timing
|
||||||
analysis.) This will cause the clock gate to be ignored in the scheduling
|
analysis.) This will cause the clock gate to be ignored in the scheduling
|
||||||
algorithm, improving performance.
|
algorithm, improving performance. It's also a good idea to enable the
|
||||||
|
IMPERFECTSCH warning, to insure all clock enables are properly recognized.
|
||||||
|
|
||||||
=item /*verilator coverage_block_off*/
|
=item /*verilator coverage_block_off*/
|
||||||
|
|
||||||
@@ -1644,7 +1644,7 @@ Often used to ignore an entire module for coverage analysis purposes.
|
|||||||
|
|
||||||
=item /*verilator coverage_on*/
|
=item /*verilator coverage_on*/
|
||||||
|
|
||||||
Specifies that following lines of code should have coverage reenabled (if
|
Specifies that following lines of code should have coverage re-enabled (if
|
||||||
appropriate --coverage flags are passed) after being disabled earlier with
|
appropriate --coverage flags are passed) after being disabled earlier with
|
||||||
/*verilator coverage_off*/.
|
/*verilator coverage_off*/.
|
||||||
|
|
||||||
@@ -1770,6 +1770,18 @@ signal. This will not declare this module public, which means the name of
|
|||||||
the signal or path to it may change based upon the module inlining which
|
the signal or path to it may change based upon the module inlining which
|
||||||
takes place.
|
takes place.
|
||||||
|
|
||||||
|
=item /*verilator public_flat_rd*/ (variable)
|
||||||
|
|
||||||
|
Used after a input, output, register, or wire declaration to indicate the
|
||||||
|
signal should be declared public_flat (see above), but read-only.
|
||||||
|
|
||||||
|
=item /*verilator public_flat_rw @(<edge_list>) */ (variable)
|
||||||
|
|
||||||
|
Used after a input, output, register, or wire declaration to indicate the
|
||||||
|
signal should be declared public_flat_rd (see above), and also writable,
|
||||||
|
where writes should be considered to have the timing specified by the given
|
||||||
|
sensitivity edge list.
|
||||||
|
|
||||||
=item /*verilator public_module*/
|
=item /*verilator public_module*/
|
||||||
|
|
||||||
Used after a module statement to indicate the module should not be inlined
|
Used after a module statement to indicate the module should not be inlined
|
||||||
@@ -1819,14 +1831,17 @@ program will find for you.
|
|||||||
Verilator supports only the Synthesis subset with a few minor additions
|
Verilator supports only the Synthesis subset with a few minor additions
|
||||||
such as $stop, $finish and $display. That is, you cannot use hierarchical
|
such as $stop, $finish and $display. That is, you cannot use hierarchical
|
||||||
references, events or similar features of the Verilog language. It also
|
references, events or similar features of the Verilog language. It also
|
||||||
simulates as Synopsys's Design Compiler would; namely a block of the form
|
simulates as Synopsys's Design Compiler would; namely a block of the form:
|
||||||
|
|
||||||
always @ (x) y = x & z;
|
always @ (x) y = x & z;
|
||||||
|
|
||||||
will recompute y when there is a change in x or a change in z, which is
|
This will recompute y when there is even a potential for change in x or a
|
||||||
what Design Compiler will synthesize. A compliant simulator would only
|
change in z, that is when the flops computing x or z evaluate (which is
|
||||||
calculate y if x changes. (Use verilog-mode's /*AS*/ or Verilog 2001's
|
what Design Compiler will synthesize.) A compliant simulator would only
|
||||||
always @* to prevent these issues.)
|
calculate y if x changes. Use verilog-mode's /*AS*/ or Verilog 2001's
|
||||||
|
always @* to reduce missing activity items. Avoid putting $displays in
|
||||||
|
combo blocks, as they may print multiple times when not desired, even on
|
||||||
|
compliant simulators as event ordering is not specified.
|
||||||
|
|
||||||
=head2 Dotted cross-hierarchy references
|
=head2 Dotted cross-hierarchy references
|
||||||
|
|
||||||
@@ -2597,8 +2612,8 @@ allows you to modify Verilator for internal use without distributing the
|
|||||||
modified version. But please contribute back to the community!
|
modified version. But please contribute back to the community!
|
||||||
|
|
||||||
One limit is that you cannot under either license release a commercial
|
One limit is that you cannot under either license release a commercial
|
||||||
simulation product incorporating Verilator without making the source code
|
Verilog simulation product incorporating Verilator without making the
|
||||||
available.
|
source code available.
|
||||||
|
|
||||||
=item Why is Verilation so slow?
|
=item Why is Verilation so slow?
|
||||||
|
|
||||||
@@ -2620,8 +2635,10 @@ in your main loop call "trace_object->dump(time)" every time step, and
|
|||||||
finally call "trace_object->close()". For an example, see below and the
|
finally call "trace_object->close()". For an example, see below and the
|
||||||
test_c/sim_main.cpp file of the distribution.
|
test_c/sim_main.cpp file of the distribution.
|
||||||
|
|
||||||
You also need to compile verilated_vcd_c.cpp and add it to your link. This
|
You also need to compile verilated_vcd_c.cpp and add it to your link,
|
||||||
is done for you if using the Verilator --exe flag.
|
preferably by adding the dependencies in $(VK_GLOBAL_OBJS) to your
|
||||||
|
Makefile's link rule. This is done for you if using the Verilator --exe
|
||||||
|
flag.
|
||||||
|
|
||||||
Note you can also call ->trace on multiple Verilated objects with the same
|
Note you can also call ->trace on multiple Verilated objects with the same
|
||||||
trace file if you want all data to land in the same output file.
|
trace file if you want all data to land in the same output file.
|
||||||
@@ -2658,8 +2675,10 @@ Alternatively you may use the C++ trace mechanism described in the previous
|
|||||||
question, however the timescale and timeprecision will not inherited from
|
question, however the timescale and timeprecision will not inherited from
|
||||||
your SystemC settings.
|
your SystemC settings.
|
||||||
|
|
||||||
You also need to compile verilated_vcd_sc.cpp and add it to your link.
|
You also need to compile verilated_vcd_sc.cpp and verilated_vcd_c.cpp and
|
||||||
This is done for you if using the Verilator --exe flag.
|
add them to your link, preferably by adding the dependencies in
|
||||||
|
$(VK_GLOBAL_OBJS) to your Makefile's link rule. This is done for you if
|
||||||
|
using the Verilator --exe flag.
|
||||||
|
|
||||||
Note you can also call ->trace on multiple Verilated objects with the same
|
Note you can also call ->trace on multiple Verilated objects with the same
|
||||||
trace file if you want all data to land in the same output file.
|
trace file if you want all data to land in the same output file.
|
||||||
@@ -2765,7 +2784,9 @@ simulator knows the current time. See the "CONNECTING TO C++" examples.
|
|||||||
=item Why do I get "undefined reference to `VL_RAND_RESET_I' or `Verilated::...'"?
|
=item Why do I get "undefined reference to `VL_RAND_RESET_I' or `Verilated::...'"?
|
||||||
|
|
||||||
You need to link your compiled Verilated code against the verilated.cpp
|
You need to link your compiled Verilated code against the verilated.cpp
|
||||||
file found in the include directory of the Verilator kit.
|
file found in the include directory of the Verilator kit. This is one
|
||||||
|
target in the $(VK_GLOBAL_OBJS) make variable, which should be part of your
|
||||||
|
Makefile's link rule.
|
||||||
|
|
||||||
=item Is the PLI supported?
|
=item Is the PLI supported?
|
||||||
|
|
||||||
|
|||||||
+101
-10
@@ -33,8 +33,12 @@
|
|||||||
//===========================================================================
|
//===========================================================================
|
||||||
// Global variables
|
// Global variables
|
||||||
|
|
||||||
|
// Slow path variables
|
||||||
int Verilated::s_randReset = 0;
|
int Verilated::s_randReset = 0;
|
||||||
int Verilated::s_debug = 1;
|
VerilatedVoidCb Verilated::s_flushCb = NULL;
|
||||||
|
|
||||||
|
// Keep below together in one cache line
|
||||||
|
int Verilated::s_debug = 0;
|
||||||
bool Verilated::s_calcUnusedSigs = false;
|
bool Verilated::s_calcUnusedSigs = false;
|
||||||
bool Verilated::s_gotFinish = false;
|
bool Verilated::s_gotFinish = false;
|
||||||
bool Verilated::s_assertOn = true;
|
bool Verilated::s_assertOn = true;
|
||||||
@@ -53,6 +57,7 @@ void vl_finish (const char* filename, int linenum, const char* hier) {
|
|||||||
VL_PRINTF("- %s:%d: Verilog $finish\n", filename, linenum);
|
VL_PRINTF("- %s:%d: Verilog $finish\n", filename, linenum);
|
||||||
if (Verilated::gotFinish()) {
|
if (Verilated::gotFinish()) {
|
||||||
VL_PRINTF("- %s:%d: Second verilog $finish, exiting\n", filename, linenum);
|
VL_PRINTF("- %s:%d: Second verilog $finish, exiting\n", filename, linenum);
|
||||||
|
Verilated::flushCall();
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
Verilated::gotFinish(true);
|
Verilated::gotFinish(true);
|
||||||
@@ -62,6 +67,7 @@ void vl_finish (const char* filename, int linenum, const char* hier) {
|
|||||||
#ifndef VL_USER_STOP // Define this to override this function
|
#ifndef VL_USER_STOP // Define this to override this function
|
||||||
void vl_stop (const char* filename, int linenum, const char* hier) {
|
void vl_stop (const char* filename, int linenum, const char* hier) {
|
||||||
Verilated::gotFinish(true);
|
Verilated::gotFinish(true);
|
||||||
|
Verilated::flushCall();
|
||||||
vl_fatal (filename,linenum,hier,"Verilog $stop");
|
vl_fatal (filename,linenum,hier,"Verilog $stop");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -71,6 +77,7 @@ void vl_fatal (const char* filename, int linenum, const char* hier, const char*
|
|||||||
if (0 && hier) {}
|
if (0 && hier) {}
|
||||||
Verilated::gotFinish(true);
|
Verilated::gotFinish(true);
|
||||||
VL_PRINTF("%%Error: %s:%d: %s\n", filename, linenum, msg);
|
VL_PRINTF("%%Error: %s:%d: %s\n", filename, linenum, msg);
|
||||||
|
Verilated::flushCall();
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -826,7 +833,7 @@ void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
|||||||
} else {
|
} else {
|
||||||
needinc = true;
|
needinc = true;
|
||||||
//printf(" Value width=%d @%x = %c\n", width, addr, c);
|
//printf(" Value width=%d @%x = %c\n", width, addr, c);
|
||||||
if (addr >= (IData)(depth+array_lsb) || addr < (IData)(array_lsb)) {
|
if (VL_UNLIKELY(addr >= (IData)(depth+array_lsb) || addr < (IData)(array_lsb))) {
|
||||||
vl_fatal (ofilenamez, linenum, "", "$readmem file address beyond bounds of array");
|
vl_fatal (ofilenamez, linenum, "", "$readmem file address beyond bounds of array");
|
||||||
} else {
|
} else {
|
||||||
int entry = addr - array_lsb;
|
int entry = addr - array_lsb;
|
||||||
@@ -854,7 +861,7 @@ void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
|||||||
_VL_SHIFTL_INPLACE_W(width, datap, (IData)shift);
|
_VL_SHIFTL_INPLACE_W(width, datap, (IData)shift);
|
||||||
datap[0] |= value;
|
datap[0] |= value;
|
||||||
}
|
}
|
||||||
if (value>=(1<<shift)) {
|
if (VL_UNLIKELY(value>=(1<<shift))) {
|
||||||
vl_fatal (ofilenamez, linenum, "", "$readmemb (binary) file contains hex characters");
|
vl_fatal (ofilenamez, linenum, "", "$readmemb (binary) file contains hex characters");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -871,7 +878,7 @@ void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
|||||||
|
|
||||||
// Final checks
|
// Final checks
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
if (end != VL_UL(0xffffffff) && addr != (end+1)) {
|
if (VL_UNLIKELY(end != VL_UL(0xffffffff) && addr != (end+1))) {
|
||||||
vl_fatal (ofilenamez, linenum, "", "$readmem file ended before specified ending-address");
|
vl_fatal (ofilenamez, linenum, "", "$readmem file ended before specified ending-address");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -920,8 +927,12 @@ IData VL_VALUEPLUSARGS_IW(int rbits, const char* prefixp, char fmt, WDataOutP rw
|
|||||||
|
|
||||||
const char* vl_mc_scan_plusargs(const char* prefixp) {
|
const char* vl_mc_scan_plusargs(const char* prefixp) {
|
||||||
string match = VerilatedImp::argPlusMatch(prefixp);
|
string match = VerilatedImp::argPlusMatch(prefixp);
|
||||||
if (match == "") return 0;
|
static VL_THREAD char outstr[VL_VALUE_STRING_MAX_WIDTH];
|
||||||
else return match.c_str()+strlen(prefixp)+1; // +1 to skip the "+"
|
if (match == "") return NULL;
|
||||||
|
strncpy(outstr, match.c_str()+strlen(prefixp)+1, // +1 to skip the "+"
|
||||||
|
VL_VALUE_STRING_MAX_WIDTH);
|
||||||
|
outstr[VL_VALUE_STRING_MAX_WIDTH-1] = '\0';
|
||||||
|
return outstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
@@ -967,6 +978,15 @@ const char* Verilated::catName(const char* n1, const char* n2) {
|
|||||||
return strp;
|
return strp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Verilated::flushCb(VerilatedVoidCb cb) {
|
||||||
|
if (s_flushCb == cb) {} // Ok - don't duplicate
|
||||||
|
else if (!s_flushCb) { s_flushCb=cb; }
|
||||||
|
else {
|
||||||
|
// Someday we may allow multiple callbacks ala atexit(), but until then
|
||||||
|
vl_fatal("unknown",0,"", "Verilated::flushCb called twice with different callbacks");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Verilated::commandArgs(int argc, const char** argv) {
|
void Verilated::commandArgs(int argc, const char** argv) {
|
||||||
VerilatedImp::commandArgs(argc,argv);
|
VerilatedImp::commandArgs(argc,argv);
|
||||||
}
|
}
|
||||||
@@ -975,6 +995,10 @@ void Verilated::scopesDump() {
|
|||||||
VerilatedImp::scopesDump();
|
VerilatedImp::scopesDump();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const VerilatedScope* Verilated::scopeFind(const char* namep) {
|
||||||
|
return VerilatedImp::scopeFind(namep);
|
||||||
|
}
|
||||||
|
|
||||||
int Verilated::exportFuncNum(const char* namep) {
|
int Verilated::exportFuncNum(const char* namep) {
|
||||||
return VerilatedImp::exportFind(namep);
|
return VerilatedImp::exportFind(namep);
|
||||||
}
|
}
|
||||||
@@ -990,6 +1014,23 @@ VerilatedModule::~VerilatedModule() {
|
|||||||
if (m_namep) free((void*)m_namep); m_namep=NULL;
|
if (m_namep) free((void*)m_namep); m_namep=NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//======================================================================
|
||||||
|
// VerilatedVar:: Methods
|
||||||
|
|
||||||
|
vluint32_t VerilatedVar::entSize() const {
|
||||||
|
vluint32_t size = 1;
|
||||||
|
switch (vltype()) {
|
||||||
|
case VLVT_PTR: size=sizeof(void*); break;
|
||||||
|
case VLVT_UINT8: size=sizeof(CData); break;
|
||||||
|
case VLVT_UINT16: size=sizeof(SData); break;
|
||||||
|
case VLVT_UINT32: size=sizeof(IData); break;
|
||||||
|
case VLVT_UINT64: size=sizeof(QData); break;
|
||||||
|
case VLVT_WDATA: size=VL_WORDS_I(range().bits())*sizeof(IData); break;
|
||||||
|
default: size=0; break;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// VerilatedScope:: Methods
|
// VerilatedScope:: Methods
|
||||||
|
|
||||||
@@ -997,12 +1038,14 @@ VerilatedScope::VerilatedScope() {
|
|||||||
m_callbacksp = NULL;
|
m_callbacksp = NULL;
|
||||||
m_namep = NULL;
|
m_namep = NULL;
|
||||||
m_funcnumMax = 0;
|
m_funcnumMax = 0;
|
||||||
|
m_varsp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
VerilatedScope::~VerilatedScope() {
|
VerilatedScope::~VerilatedScope() {
|
||||||
VerilatedImp::scopeErase(this);
|
VerilatedImp::scopeErase(this);
|
||||||
if (m_namep) { delete [] m_namep; m_namep = NULL; }
|
if (m_namep) { delete [] m_namep; m_namep = NULL; }
|
||||||
if (m_callbacksp) { delete [] m_callbacksp; m_callbacksp = NULL; }
|
if (m_callbacksp) { delete [] m_callbacksp; m_callbacksp = NULL; }
|
||||||
|
if (m_varsp) { delete m_varsp; m_varsp = NULL; }
|
||||||
m_funcnumMax = 0; // Force callback table to empty
|
m_funcnumMax = 0; // Force callback table to empty
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1027,10 +1070,10 @@ void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) {
|
|||||||
// Alternative is to dynamically stretch the array, which is more code, and slower.
|
// Alternative is to dynamically stretch the array, which is more code, and slower.
|
||||||
if (funcnum >= m_funcnumMax) { m_funcnumMax = funcnum+1; }
|
if (funcnum >= m_funcnumMax) { m_funcnumMax = funcnum+1; }
|
||||||
} else {
|
} else {
|
||||||
if (funcnum >= m_funcnumMax) {
|
if (VL_UNLIKELY(funcnum >= m_funcnumMax)) {
|
||||||
vl_fatal(__FILE__,__LINE__,"","Internal: Bad funcnum vs. pre-finalize maximum");
|
vl_fatal(__FILE__,__LINE__,"","Internal: Bad funcnum vs. pre-finalize maximum");
|
||||||
}
|
}
|
||||||
if (!m_callbacksp) { // First allocation
|
if (VL_UNLIKELY(!m_callbacksp)) { // First allocation
|
||||||
m_callbacksp = new void* [m_funcnumMax];
|
m_callbacksp = new void* [m_funcnumMax];
|
||||||
memset(m_callbacksp, 0, m_funcnumMax*sizeof(void*));
|
memset(m_callbacksp, 0, m_funcnumMax*sizeof(void*));
|
||||||
}
|
}
|
||||||
@@ -1038,6 +1081,47 @@ void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VerilatedScope::varInsert(int finalize, const char* namep, void* datap,
|
||||||
|
VerilatedVarType vltype, int vlflags, int dims, ...) {
|
||||||
|
// Grab dimensions
|
||||||
|
// In the future we may just create a large table at emit time and statically construct from that.
|
||||||
|
if (!finalize) return;
|
||||||
|
|
||||||
|
if (!m_varsp) m_varsp = new VerilatedVarNameMap();
|
||||||
|
VerilatedVar var (namep, datap, vltype, (VerilatedVarFlags)vlflags, dims);
|
||||||
|
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap,dims);
|
||||||
|
for (int i=0; i<dims; ++i) {
|
||||||
|
int msb = va_arg(ap,int);
|
||||||
|
int lsb = va_arg(ap,int);
|
||||||
|
if (i==0) {
|
||||||
|
var.m_range.m_lhs = msb;
|
||||||
|
var.m_range.m_rhs = lsb;
|
||||||
|
} else if (i==1) {
|
||||||
|
var.m_array.m_lhs = msb;
|
||||||
|
var.m_array.m_rhs = lsb;
|
||||||
|
} else {
|
||||||
|
// We could have a linked list of ranges, but really this whole thing needs
|
||||||
|
// to be generalized to support structs and unions, etc.
|
||||||
|
vl_fatal(__FILE__,__LINE__,"",(string("Unsupported multi-dimensional public varInsert: ")+namep).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
m_varsp->insert(make_pair(namep,var));
|
||||||
|
}
|
||||||
|
|
||||||
|
VerilatedVar* VerilatedScope::varFind(const char* namep) const {
|
||||||
|
if (VL_LIKELY(m_varsp)) {
|
||||||
|
VerilatedVarNameMap::iterator it = m_varsp->find(namep);
|
||||||
|
if (VL_LIKELY(it != m_varsp->end())) {
|
||||||
|
return &(it->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void* VerilatedScope::exportFindNullError(int funcnum) const {
|
void* VerilatedScope::exportFindNullError(int funcnum) const {
|
||||||
// Slowpath - Called only when find has failed
|
// Slowpath - Called only when find has failed
|
||||||
string msg = (string("Testbench C called '")
|
string msg = (string("Testbench C called '")
|
||||||
@@ -1058,10 +1142,17 @@ void* VerilatedScope::exportFindError(int funcnum) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VerilatedScope::scopeDump() const {
|
void VerilatedScope::scopeDump() const {
|
||||||
VL_PRINTF(" SCOPE: %s\n", name());
|
VL_PRINTF(" SCOPE %p: %s\n", this, name());
|
||||||
for (int i=0; i<m_funcnumMax; i++) {
|
for (int i=0; i<m_funcnumMax; i++) {
|
||||||
if (m_callbacksp && m_callbacksp[i]) {
|
if (m_callbacksp && m_callbacksp[i]) {
|
||||||
VL_PRINTF(" DPI-EXPORT: %s\n", VerilatedImp::exportName(i));
|
VL_PRINTF(" DPI-EXPORT %p: %s\n",
|
||||||
|
m_callbacksp[i], VerilatedImp::exportName(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (varsp()) {
|
||||||
|
for (VerilatedVarNameMap::const_iterator it = varsp()->begin();
|
||||||
|
it != varsp()->end(); ++it) {
|
||||||
|
VL_PRINTF(" VAR %p: %s\n", &(it->second), it->first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+48
-4
@@ -62,11 +62,37 @@ typedef vluint32_t WData; ///< Verilated pack data, >64 bits, as an array
|
|||||||
typedef const WData* WDataInP; ///< Array input to a function
|
typedef const WData* WDataInP; ///< Array input to a function
|
||||||
typedef WData* WDataOutP; ///< Array output from a function
|
typedef WData* WDataOutP; ///< Array output from a function
|
||||||
|
|
||||||
|
typedef void (*VerilatedVoidCb)(void);
|
||||||
|
|
||||||
class SpTraceVcd;
|
class SpTraceVcd;
|
||||||
class SpTraceVcdCFile;
|
class SpTraceVcdCFile;
|
||||||
|
class VerilatedVar;
|
||||||
|
class VerilatedVarNameMap;
|
||||||
class VerilatedVcd;
|
class VerilatedVcd;
|
||||||
class VerilatedVcdC;
|
class VerilatedVcdC;
|
||||||
|
|
||||||
|
enum VerilatedVarType {
|
||||||
|
VLVT_UNKNOWN=0,
|
||||||
|
VLVT_PTR, // Pointer to something
|
||||||
|
VLVT_UINT8, // AKA CData
|
||||||
|
VLVT_UINT16, // AKA SData
|
||||||
|
VLVT_UINT32, // AKA IData
|
||||||
|
VLVT_UINT64, // AKA QData
|
||||||
|
VLVT_WDATA, // AKA WData
|
||||||
|
VLVT_STRING // C++ string
|
||||||
|
};
|
||||||
|
|
||||||
|
enum VerilatedVarFlags {
|
||||||
|
VLVD_IN=1, // == vpiInput
|
||||||
|
VLVD_OUT=2, // == vpiOutput
|
||||||
|
VLVD_INOUT=3, // == vpiInOut
|
||||||
|
VLVD_NODIR=5, // == vpiNoDirection
|
||||||
|
VLVF_MASK_DIR=7, // Bit mask for above directions
|
||||||
|
// Flags
|
||||||
|
VLVF_PUB_RD=(1<<8), // Public readable
|
||||||
|
VLVF_PUB_RW=(1<<9) // Public writable
|
||||||
|
};
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
/// Base class for all Verilated module classes
|
/// Base class for all Verilated module classes
|
||||||
|
|
||||||
@@ -136,6 +162,9 @@ public:
|
|||||||
#ifndef VL_PRINTF
|
#ifndef VL_PRINTF
|
||||||
# define VL_PRINTF printf ///< Print ala printf; may redefine if desired
|
# define VL_PRINTF printf ///< Print ala printf; may redefine if desired
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef VL_VPRINTF
|
||||||
|
# define VL_VPRINTF vprintf ///< Print ala vprintf; may redefine if desired
|
||||||
|
#endif
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
/// Verilator symbol table base class
|
/// Verilator symbol table base class
|
||||||
@@ -149,19 +178,25 @@ class VerilatedSyms {
|
|||||||
|
|
||||||
class VerilatedScope {
|
class VerilatedScope {
|
||||||
// Fastpath:
|
// Fastpath:
|
||||||
VerilatedSyms* m_symsp; ///< Symbol table
|
VerilatedSyms* m_symsp; ///< Symbol table
|
||||||
void** m_callbacksp; ///< Callback table pointer (Fastpath)
|
void** m_callbacksp; ///< Callback table pointer (Fastpath)
|
||||||
int m_funcnumMax; ///< Maxium function number stored (Fastpath)
|
int m_funcnumMax; ///< Maxium function number stored (Fastpath)
|
||||||
// 4 bytes padding (on -m64), for rent.
|
// 4 bytes padding (on -m64), for rent.
|
||||||
const char* m_namep; ///< Scope name (Slowpath)
|
VerilatedVarNameMap* m_varsp; ///< Variable map
|
||||||
|
const char* m_namep; ///< Scope name (Slowpath)
|
||||||
|
|
||||||
public: // But internals only - called from VerilatedModule's
|
public: // But internals only - called from VerilatedModule's
|
||||||
VerilatedScope();
|
VerilatedScope();
|
||||||
~VerilatedScope();
|
~VerilatedScope();
|
||||||
void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp);
|
void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp);
|
||||||
void exportInsert(int finalize, const char* namep, void* cb);
|
void exportInsert(int finalize, const char* namep, void* cb);
|
||||||
|
void varInsert(int finalize, const char* namep, void* datap,
|
||||||
|
VerilatedVarType vltype, int vlflags, int dims, ...);
|
||||||
// ACCESSORS
|
// ACCESSORS
|
||||||
const char* name() const { return m_namep; }
|
const char* name() const { return m_namep; }
|
||||||
inline VerilatedSyms* symsp() const { return m_symsp; }
|
inline VerilatedSyms* symsp() const { return m_symsp; }
|
||||||
|
VerilatedVar* varFind(const char* namep) const;
|
||||||
|
VerilatedVarNameMap* varsp() const { return m_varsp; }
|
||||||
void* exportFindError(int funcnum) const;
|
void* exportFindError(int funcnum) const;
|
||||||
void* exportFindNullError(int funcnum) const;
|
void* exportFindNullError(int funcnum) const;
|
||||||
void scopeDump() const;
|
void scopeDump() const;
|
||||||
@@ -182,7 +217,11 @@ public: // But internals only - called from VerilatedModule's
|
|||||||
struct Verilated {
|
struct Verilated {
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
private:
|
private:
|
||||||
|
// Slow path variables
|
||||||
static int s_randReset; ///< Random reset: 0=all 0s, 1=all 1s, 2=random
|
static int s_randReset; ///< Random reset: 0=all 0s, 1=all 1s, 2=random
|
||||||
|
static VerilatedVoidCb s_flushCb; ///< Flush callback function
|
||||||
|
|
||||||
|
// Fast path
|
||||||
static int s_debug; ///< See accessors... only when VL_DEBUG set
|
static int s_debug; ///< See accessors... only when VL_DEBUG set
|
||||||
static bool s_calcUnusedSigs; ///< Waves file on, need all signals calculated
|
static bool s_calcUnusedSigs; ///< Waves file on, need all signals calculated
|
||||||
static bool s_gotFinish; ///< A $finish statement executed
|
static bool s_gotFinish; ///< A $finish statement executed
|
||||||
@@ -224,6 +263,9 @@ public:
|
|||||||
/// Enable/disable assertions
|
/// Enable/disable assertions
|
||||||
static void assertOn(bool flag) { s_assertOn=flag; }
|
static void assertOn(bool flag) { s_assertOn=flag; }
|
||||||
static bool assertOn() { return s_assertOn; }
|
static bool assertOn() { return s_assertOn; }
|
||||||
|
/// Flush callback for VCD waves
|
||||||
|
static void flushCb(VerilatedVoidCb cb);
|
||||||
|
static void flushCall() { if (s_flushCb) (*s_flushCb)(); }
|
||||||
|
|
||||||
/// Record command line arguments, for retrieval by $test$plusargs/$value$plusargs
|
/// Record command line arguments, for retrieval by $test$plusargs/$value$plusargs
|
||||||
static void commandArgs(int argc, const char** argv);
|
static void commandArgs(int argc, const char** argv);
|
||||||
@@ -237,6 +279,8 @@ public:
|
|||||||
// METHODS - INTERNAL USE ONLY
|
// METHODS - INTERNAL USE ONLY
|
||||||
// Internal: Create a new module name by concatenating two strings
|
// Internal: Create a new module name by concatenating two strings
|
||||||
static const char* catName(const char* n1, const char* n2); // Returns new'ed data
|
static const char* catName(const char* n1, const char* n2); // Returns new'ed data
|
||||||
|
// Internal: Find scope
|
||||||
|
static const VerilatedScope* scopeFind(const char* namep);
|
||||||
// Internal: Get and set DPI context
|
// Internal: Get and set DPI context
|
||||||
static const VerilatedScope* dpiScope() { return t_dpiScopep; }
|
static const VerilatedScope* dpiScope() { return t_dpiScopep; }
|
||||||
static void dpiScope(const VerilatedScope* scopep) { t_dpiScopep=scopep; }
|
static void dpiScope(const VerilatedScope* scopep) { t_dpiScopep=scopep; }
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include "verilatedos.h"
|
#include "verilatedos.h"
|
||||||
#include "verilated.h"
|
#include "verilated.h"
|
||||||
#include "verilated_heavy.h"
|
#include "verilated_heavy.h"
|
||||||
|
#include "verilated_syms.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -41,13 +42,6 @@ class VerilatedScope;
|
|||||||
//======================================================================
|
//======================================================================
|
||||||
// Types
|
// Types
|
||||||
|
|
||||||
struct VerilatedCStrCmp {
|
|
||||||
// For ordering maps keyed by const char*'s
|
|
||||||
bool operator() (const char *a, const char *b) const {
|
|
||||||
return std::strcmp(a, b) < 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class VerilatedImp {
|
class VerilatedImp {
|
||||||
// Whole class is internal use only - Global information shared between verilated*.cpp files.
|
// Whole class is internal use only - Global information shared between verilated*.cpp files.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
// -*- C++ -*-
|
||||||
|
//*************************************************************************
|
||||||
|
//
|
||||||
|
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||||
|
// redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||||
|
// Version 2.0.
|
||||||
|
//
|
||||||
|
// Verilator is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
///
|
||||||
|
/// \file
|
||||||
|
/// \brief Verilator: Include to allow symbol inspection
|
||||||
|
///
|
||||||
|
/// This file is for inclusion by files that need to inspect
|
||||||
|
/// the symbol table. It is not included in verilated.h
|
||||||
|
/// as it requires some heavyweight C++ classes.
|
||||||
|
///
|
||||||
|
/// Code available from: http://www.veripool.org/verilator
|
||||||
|
///
|
||||||
|
//*************************************************************************
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _VERILATED_SYMS_H_
|
||||||
|
#define _VERILATED_SYMS_H_ 1 ///< Header Guard
|
||||||
|
|
||||||
|
#include "verilated_heavy.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
//======================================================================
|
||||||
|
// Types
|
||||||
|
|
||||||
|
struct VerilatedCStrCmp {
|
||||||
|
/// Ordering maps keyed by const char*'s
|
||||||
|
bool operator() (const char *a, const char *b) const {
|
||||||
|
return std::strcmp(a, b) < 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
/// Verilator range
|
||||||
|
|
||||||
|
class VerilatedRange {
|
||||||
|
int m_lhs;
|
||||||
|
int m_rhs;
|
||||||
|
protected:
|
||||||
|
friend class VerilatedVar;
|
||||||
|
friend class VerilatedScope;
|
||||||
|
VerilatedRange() : m_lhs(0), m_rhs(0) {}
|
||||||
|
void sets(int lhs, int rhs) { m_lhs=lhs; m_rhs=rhs; }
|
||||||
|
public:
|
||||||
|
~VerilatedRange() {}
|
||||||
|
int lhs() const { return m_lhs; }
|
||||||
|
int rhs() const { return m_rhs; }
|
||||||
|
int bits() const { return (VL_LIKELY(m_lhs>=m_rhs)?(m_lhs-m_rhs+1):(m_rhs-m_lhs+1)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
/// Verilator variable
|
||||||
|
|
||||||
|
class VerilatedVar {
|
||||||
|
void* m_datap; // Location of data
|
||||||
|
VerilatedVarType m_vltype; // Data type
|
||||||
|
VerilatedVarFlags m_vlflags; // Direction
|
||||||
|
VerilatedRange m_range; // First range
|
||||||
|
VerilatedRange m_array; // Array
|
||||||
|
int m_dims; // Dimensions
|
||||||
|
const char* m_namep; // Name - slowpath
|
||||||
|
protected:
|
||||||
|
friend class VerilatedScope;
|
||||||
|
VerilatedVar(const char* namep, void* datap,
|
||||||
|
VerilatedVarType vltype, VerilatedVarFlags vlflags, int dims)
|
||||||
|
: m_datap(datap), m_vltype(vltype), m_vlflags(vlflags), m_dims(dims), m_namep(namep) {}
|
||||||
|
public:
|
||||||
|
~VerilatedVar() {}
|
||||||
|
void* datap() const { return m_datap; }
|
||||||
|
VerilatedVarType vltype() const { return m_vltype; }
|
||||||
|
VerilatedVarFlags vldir() const { return (VerilatedVarFlags)((int)m_vlflags & VLVF_MASK_DIR); }
|
||||||
|
vluint32_t entSize() const;
|
||||||
|
bool isPublicRW() const { return ((m_vlflags & VLVF_PUB_RW) != 0); }
|
||||||
|
const VerilatedRange& range() const { return m_range; }
|
||||||
|
const VerilatedRange& array() const { return m_array; }
|
||||||
|
const char* name() const { return m_namep; }
|
||||||
|
int dims() const { return m_dims; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//======================================================================
|
||||||
|
/// Types
|
||||||
|
|
||||||
|
struct VerilatedVarNameMap : public map<const char*, VerilatedVar, VerilatedCStrCmp> {
|
||||||
|
VerilatedVarNameMap() {}
|
||||||
|
~VerilatedVarNameMap() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // Guard
|
||||||
+44
-12
@@ -88,6 +88,11 @@ void VerilatedVcd::open (const char* filename) {
|
|||||||
m_filename = filename;
|
m_filename = filename;
|
||||||
s_vcdVecp.push_back(this);
|
s_vcdVecp.push_back(this);
|
||||||
|
|
||||||
|
// SPDIFF_OFF
|
||||||
|
// Set callback so an early exit will flush us
|
||||||
|
Verilated::flushCb(&flush_all);
|
||||||
|
|
||||||
|
// SPDIFF_ON
|
||||||
openNext (m_rolloverMB!=0);
|
openNext (m_rolloverMB!=0);
|
||||||
if (!isOpen()) return;
|
if (!isOpen()) return;
|
||||||
|
|
||||||
@@ -149,6 +154,39 @@ void VerilatedVcd::openNext (bool incFilename) {
|
|||||||
m_wroteBytes = 0;
|
m_wroteBytes = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VerilatedVcd::makeNameMap() {
|
||||||
|
// Take signal information from each module and build m_namemapp
|
||||||
|
m_namemapp = new NameMap;
|
||||||
|
for (vluint32_t ent = 0; ent< m_callbacks.size(); ent++) {
|
||||||
|
VerilatedVcdCallInfo *cip = m_callbacks[ent];
|
||||||
|
cip->m_code = nextCode();
|
||||||
|
(cip->m_initcb) (this, cip->m_userthis, cip->m_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Though not speced, it's illegal to generate a vcd with signals
|
||||||
|
// not under any module - it crashes at least two viewers.
|
||||||
|
// If no scope was specified, prefix everything with a "top"
|
||||||
|
// This comes from user instantiations with no name - IE Vtop("").
|
||||||
|
bool nullScope = false;
|
||||||
|
for (NameMap::iterator it=m_namemapp->begin(); it!=m_namemapp->end(); ++it) {
|
||||||
|
const char* hiername = (*it).first.c_str();
|
||||||
|
if (hiername[0] == '\t') nullScope=true;
|
||||||
|
}
|
||||||
|
if (nullScope) {
|
||||||
|
NameMap* newmapp = new NameMap;
|
||||||
|
for (NameMap::iterator it=m_namemapp->begin(); it!=m_namemapp->end(); ++it) {
|
||||||
|
const string& hiername = it->first;
|
||||||
|
const string& decl = it->second;
|
||||||
|
string newname = string("top");
|
||||||
|
if (hiername[0] != '\t') newname += ' ';
|
||||||
|
newname += hiername;
|
||||||
|
newmapp->insert(make_pair(newname,decl));
|
||||||
|
}
|
||||||
|
delete m_namemapp; m_namemapp=NULL;
|
||||||
|
m_namemapp = newmapp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VerilatedVcd::~VerilatedVcd() {
|
VerilatedVcd::~VerilatedVcd() {
|
||||||
close();
|
close();
|
||||||
if (m_wrBufp) { delete[] m_wrBufp; m_wrBufp=NULL; }
|
if (m_wrBufp) { delete[] m_wrBufp; m_wrBufp=NULL; }
|
||||||
@@ -196,7 +234,7 @@ void VerilatedVcd::printStr (const char* str) {
|
|||||||
|
|
||||||
void VerilatedVcd::printQuad (vluint64_t n) {
|
void VerilatedVcd::printQuad (vluint64_t n) {
|
||||||
char buf [100];
|
char buf [100];
|
||||||
sprintf(buf,"%" VL_PRI64 "u",(long long unsigned)n);
|
sprintf(buf,"%" VL_PRI64 "u", n);
|
||||||
printStr(buf);
|
printStr(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,10 +260,10 @@ void VerilatedVcd::bufferFlush () {
|
|||||||
if (VL_UNLIKELY(!isOpen())) return;
|
if (VL_UNLIKELY(!isOpen())) return;
|
||||||
char* wp = m_wrBufp;
|
char* wp = m_wrBufp;
|
||||||
while (1) {
|
while (1) {
|
||||||
size_t remaining = (m_writep - wp);
|
ssize_t remaining = (m_writep - wp);
|
||||||
if (remaining==0) break;
|
if (remaining==0) break;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
int got = write (m_fd, wp, remaining);
|
ssize_t got = write (m_fd, wp, remaining);
|
||||||
if (got>0) {
|
if (got>0) {
|
||||||
wp += got;
|
wp += got;
|
||||||
m_wroteBytes += got;
|
m_wroteBytes += got;
|
||||||
@@ -309,13 +347,7 @@ void VerilatedVcd::dumpHeader () {
|
|||||||
printStr(doubleToTimescale(m_timeRes).c_str());
|
printStr(doubleToTimescale(m_timeRes).c_str());
|
||||||
printStr(" $end\n");
|
printStr(" $end\n");
|
||||||
|
|
||||||
// Take signal information from each module and build m_namemapp
|
makeNameMap();
|
||||||
m_namemapp = new NameMap;
|
|
||||||
for (vluint32_t ent = 0; ent< m_callbacks.size(); ent++) {
|
|
||||||
VerilatedVcdCallInfo *cip = m_callbacks[ent];
|
|
||||||
cip->m_code = nextCode();
|
|
||||||
(cip->m_initcb) (this, cip->m_userthis, cip->m_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signal header
|
// Signal header
|
||||||
assert (m_modDepth==0);
|
assert (m_modDepth==0);
|
||||||
@@ -341,7 +373,7 @@ void VerilatedVcd::dumpHeader () {
|
|||||||
// Skip common prefix, it must break at a space or tab
|
// Skip common prefix, it must break at a space or tab
|
||||||
for (; *np && (*np == *lp); np++, lp++) {}
|
for (; *np && (*np == *lp); np++, lp++) {}
|
||||||
while (np!=hiername && *np && *np!=' ' && *np!='\t') { np--; lp--; }
|
while (np!=hiername && *np && *np!=' ' && *np!='\t') { np--; lp--; }
|
||||||
//cout <<"hier "<<hiername<<endl<<" lp "<<lp<<endl<<" np "<<np<<endl;
|
//printf("hier %s\n lp=%s\n np=%s\n",hiername,lp,np);
|
||||||
|
|
||||||
// Any extra spaces in last name are scope ups we need to do
|
// Any extra spaces in last name are scope ups we need to do
|
||||||
bool first = true;
|
bool first = true;
|
||||||
@@ -389,7 +421,7 @@ void VerilatedVcd::module (string name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VerilatedVcd::declare (vluint32_t code, const char* name, const char* wirep,
|
void VerilatedVcd::declare (vluint32_t code, const char* name, const char* wirep,
|
||||||
int arraynum, bool tri, bool bussed, int msb, int lsb) {
|
int arraynum, bool tri, bool bussed, int msb, int lsb) {
|
||||||
if (!code) { vl_fatal(__FILE__,__LINE__,"","Internal: internal trace problem, code 0 is illegal"); }
|
if (!code) { vl_fatal(__FILE__,__LINE__,"","Internal: internal trace problem, code 0 is illegal"); }
|
||||||
|
|
||||||
int bits = ((msb>lsb)?(msb-lsb):(lsb-msb))+1;
|
int bits = ((msb>lsb)?(msb-lsb):(lsb-msb))+1;
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ private:
|
|||||||
void closePrev();
|
void closePrev();
|
||||||
void closeErr();
|
void closeErr();
|
||||||
void openNext();
|
void openNext();
|
||||||
|
void makeNameMap();
|
||||||
void printIndent (int levelchange);
|
void printIndent (int levelchange);
|
||||||
void printStr (const char* str);
|
void printStr (const char* str);
|
||||||
void printQuad (vluint64_t n);
|
void printQuad (vluint64_t n);
|
||||||
|
|||||||
+24
-2
@@ -126,8 +126,13 @@ typedef unsigned long uint32_t; ///< 32-bit unsigned type (backward compatibili
|
|||||||
typedef long vlsint32_t; ///< 32-bit signed type
|
typedef long vlsint32_t; ///< 32-bit signed type
|
||||||
typedef unsigned long vluint32_t; ///< 32-bit unsigned type
|
typedef unsigned long vluint32_t; ///< 32-bit unsigned type
|
||||||
# endif
|
# endif
|
||||||
|
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
||||||
|
typedef long vlsint64_t; ///< 64-bit signed type
|
||||||
|
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
|
||||||
|
# else
|
||||||
typedef long long vlsint64_t; ///< 64-bit signed type
|
typedef long long vlsint64_t; ///< 64-bit signed type
|
||||||
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||||
|
# endif
|
||||||
|
|
||||||
#elif defined(_WIN32) && defined(_MSC_VER)
|
#elif defined(_WIN32) && defined(_MSC_VER)
|
||||||
|
|
||||||
@@ -141,6 +146,14 @@ typedef unsigned __int32 vluint32_t; ///< 32-bit unsigned type
|
|||||||
typedef signed __int64 vlsint64_t; ///< 64-bit signed type
|
typedef signed __int64 vlsint64_t; ///< 64-bit signed type
|
||||||
typedef unsigned __int64 vluint64_t; ///< 64-bit unsigned type
|
typedef unsigned __int64 vluint64_t; ///< 64-bit unsigned type
|
||||||
|
|
||||||
|
# ifndef _SSIZE_T_DEFINED
|
||||||
|
# ifdef _WIN64
|
||||||
|
typedef signed __int64 ssize_t; ///< signed size_t; returned from read()
|
||||||
|
# else
|
||||||
|
typedef signed __int32 ssize_t; ///< signed size_t; returned from read()
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
#else // Linux or compliant Unix flavors, -m64
|
#else // Linux or compliant Unix flavors, -m64
|
||||||
|
|
||||||
# include <stdint.h> // Linux and most flavors
|
# include <stdint.h> // Linux and most flavors
|
||||||
@@ -149,8 +162,13 @@ typedef uint8_t vluint8_t; ///< 32-bit unsigned type
|
|||||||
typedef uint16_t vluint16_t; ///< 32-bit unsigned type
|
typedef uint16_t vluint16_t; ///< 32-bit unsigned type
|
||||||
typedef int vlsint32_t; ///< 32-bit signed type
|
typedef int vlsint32_t; ///< 32-bit signed type
|
||||||
typedef uint32_t vluint32_t; ///< 32-bit signed type
|
typedef uint32_t vluint32_t; ///< 32-bit signed type
|
||||||
|
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
||||||
|
typedef long vlsint64_t; ///< 64-bit signed type
|
||||||
|
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
|
||||||
|
# else
|
||||||
typedef long long vlsint64_t; ///< 64-bit signed type
|
typedef long long vlsint64_t; ///< 64-bit signed type
|
||||||
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
@@ -160,7 +178,11 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# define VL_PRI64 "I64"
|
# define VL_PRI64 "I64"
|
||||||
#else // Linux or compliant Unix flavors
|
#else // Linux or compliant Unix flavors
|
||||||
# define VL_PRI64 "ll"
|
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
||||||
|
# define VL_PRI64 "l"
|
||||||
|
# else
|
||||||
|
# define VL_PRI64 "ll"
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
+143
-54
@@ -40,7 +40,148 @@ Modify the later visitor functions to process the new feature as needed.
|
|||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head1 DEBUG OUTPUT/ TREE FILES
|
=head1 CODE FLOWS
|
||||||
|
|
||||||
|
=head2 Verilator Flow
|
||||||
|
|
||||||
|
The main flow of Verilator can be followed by reading the Verilator.cpp
|
||||||
|
process() function:
|
||||||
|
|
||||||
|
First, the files specified on the command line are read. Reading involves
|
||||||
|
preprocessing, then lexical analysis with Flex and parsing with Bison.
|
||||||
|
This produces an abstract syntax tree (AST) representation of the design,
|
||||||
|
which is what is visible in the .tree files described below.
|
||||||
|
|
||||||
|
Cells are then linked, which will read and parse additional files as above.
|
||||||
|
|
||||||
|
Functions, variable and other references are linked to their definitions.
|
||||||
|
|
||||||
|
Parameters are resolved and the design is elaborated.
|
||||||
|
|
||||||
|
Verilator then performs many additional edits and optimizations on the
|
||||||
|
hierarchical design. This includes coverage, assertions, X elimination,
|
||||||
|
inlining, constant propagation, and dead code elimination.
|
||||||
|
|
||||||
|
References in the design are then psudo-flattened. Each module's variables
|
||||||
|
and functions get "Scope" references. A scope reference is an occurrence of
|
||||||
|
that un-flattened variable in the flattened hierarchy. A module that occurs
|
||||||
|
only once in the hierarchy will have a single scope and single VarScope for
|
||||||
|
each variable. A module that occurs twice will have a scope for each
|
||||||
|
occurrence, and two VarScopes for each variable. This allows optimizations
|
||||||
|
to proceed across the flattened design, while still preserving the
|
||||||
|
hierarchy.
|
||||||
|
|
||||||
|
Additional edits and optimizations proceed on the psudo-flat design. These
|
||||||
|
include module references, function inlining, loop unrolling, variable
|
||||||
|
lifetime analysis, lookup table creation, always splitting, and logic gate
|
||||||
|
simplifications (pushing inverters, etc).
|
||||||
|
|
||||||
|
Verilator orders the code. Best case, this results in a single "eval"
|
||||||
|
function which has all always statements flowing from top to bottom with no
|
||||||
|
loops.
|
||||||
|
|
||||||
|
Verilator mostly removes the flattening, so that code may be shared between
|
||||||
|
multiple invocations of the same module. It localizes variables, combines
|
||||||
|
identical functions, expands macros to C primitives, adds branch prediction
|
||||||
|
hints, and performs additional constant propagation.
|
||||||
|
|
||||||
|
Verilator finally writes the C++ modules.
|
||||||
|
|
||||||
|
=head2 Verilated Flow
|
||||||
|
|
||||||
|
The evaluation loop outputted by Verilator is designed to allow a single
|
||||||
|
function to perform evaluation under most situations.
|
||||||
|
|
||||||
|
On the first evaluation, the Verilated code calls initial blocks, and then
|
||||||
|
"settles" the modules, by evaluating functions (from always statements)
|
||||||
|
until all signals are stable.
|
||||||
|
|
||||||
|
On other evaluations, the Verilated code detects what input signals have
|
||||||
|
changes. If any are clocks, it calls the appropriate sequential functions
|
||||||
|
(from always @ posedge statements). Interspersed with sequential functions
|
||||||
|
it calls combo functions (from always @*). After this is complete, it
|
||||||
|
detects any changes due to combo loops or internally generated clocks, and
|
||||||
|
if one is found must reevaluate the model again.
|
||||||
|
|
||||||
|
For SystemC code, the eval() function is wrapped in a SystemC SC_METHOD,
|
||||||
|
sensitive to all inputs. (Ideally it would only be sensitive to clocks and
|
||||||
|
combo inputs, but tracing requires all signals to cause evaluation, and the
|
||||||
|
performance difference is small.)
|
||||||
|
|
||||||
|
If tracing is enabled, a callback examines all variables in the design for
|
||||||
|
changes, and writes the trace for each change. To accelerate this process
|
||||||
|
the evaluation process records a bitmask of variables that might have
|
||||||
|
changed; if clear, checking those signals for changes may be skipped.
|
||||||
|
|
||||||
|
=head1 CODING CONVENTIONS
|
||||||
|
|
||||||
|
=head2 Indentation style
|
||||||
|
|
||||||
|
To match the indentation of Verilator C++ sources, use 4 spaces per level,
|
||||||
|
and leave tabs at 8 columns, so every other indent level is a tab stop.
|
||||||
|
|
||||||
|
In Emacs, use in your ~/.emacs
|
||||||
|
|
||||||
|
(add-hook 'c-mode-common-hook '(lambda ()
|
||||||
|
(c-set-style "cc-mode"))))
|
||||||
|
|
||||||
|
This sets indentation to the cc-mode defaults. (Verilator predates a
|
||||||
|
CC-mode change of several years ago which overrides the defaults with GNU
|
||||||
|
style indentation; the c-set-style undoes that.)
|
||||||
|
|
||||||
|
=head2 Visitor Functions
|
||||||
|
|
||||||
|
There's three ways data is passed between visitor functions.
|
||||||
|
|
||||||
|
1. A visitor-class member variable. This is generally for passing "parent"
|
||||||
|
information down to children. m_modp is a common example. It's set to
|
||||||
|
NULL in the constructor, where that node (AstModule visitor) sets it, then
|
||||||
|
the children are iterated, then it's cleared. Children under an AstModule
|
||||||
|
will see it set, while nodes elsewhere will see it clear. If there can be
|
||||||
|
nested items (for example an AstFor under an AstFor) the variable needs to
|
||||||
|
be save-set-restored in the AstFor visitor, otherwise exiting the lower for
|
||||||
|
will loose the upper for's setting.
|
||||||
|
|
||||||
|
2. User() attributes. Each node has 5 ->user() number or ->userp() pointer
|
||||||
|
utility values (a common technique lifted from graph traversal packages).
|
||||||
|
A visitor first clears the one it wants to use by calling
|
||||||
|
AstNode::user#ClearTree(), then it can mark any node's user() with whatever
|
||||||
|
data it wants. Readers just call nodep->user(), but may need to cast
|
||||||
|
appropriately, so you'll often see nodep->userp()->castSOMETYPE(). At the
|
||||||
|
top of each visitor are comments describing how the user() stuff applies to
|
||||||
|
that visitor class. For example:
|
||||||
|
|
||||||
|
// NODE STATE
|
||||||
|
// Cleared entire netlist
|
||||||
|
// AstModule::user1p() // bool. True to inline this module
|
||||||
|
|
||||||
|
This says that at the AstNetlist user1ClearTree() is called. Each
|
||||||
|
AstModule's is user1() is used to indicate if we're going to inline it.
|
||||||
|
|
||||||
|
These comments are important to make sure a user#() on a given AstNode type
|
||||||
|
is never being used for two different purposes.
|
||||||
|
|
||||||
|
Note that calling user#ClearTree is fast, it doesn't walk the tree, so it's
|
||||||
|
ok to call fairly often. For example, it's commonly called on every
|
||||||
|
module.
|
||||||
|
|
||||||
|
3. Parameters can be passed between the visitors in close to the "normal"
|
||||||
|
function caller to callee way. This is the second "vup" parameter that is
|
||||||
|
ignored on most of the visitor functions. V3Width does this, but it proved
|
||||||
|
more messy than the above and is deprecated. (V3Width was nearly the first
|
||||||
|
module written. Someday this scheme may be removed, as it slows the
|
||||||
|
program down to have to pass vup everywhere.)
|
||||||
|
|
||||||
|
=head1 TESTING
|
||||||
|
|
||||||
|
To write a test see notes in the forum and in the verilator.txt manual.
|
||||||
|
|
||||||
|
Note you can run the regression tests in parallel; see the
|
||||||
|
test_regress/driver.pl script -j flag.
|
||||||
|
|
||||||
|
=head1 DEBUGGING
|
||||||
|
|
||||||
|
=head2 --debug
|
||||||
|
|
||||||
When you run with --debug there are two primary output file types placed into
|
When you run with --debug there are two primary output file types placed into
|
||||||
the obj_dir, .tree and .dot files.
|
the obj_dir, .tree and .dot files.
|
||||||
@@ -94,59 +235,7 @@ variable is an output.
|
|||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head1 TESTING
|
=head2 Debugging with GDB
|
||||||
|
|
||||||
To write a test see notes in the forum and in the verilator.txt manual.
|
|
||||||
|
|
||||||
Note you can run the regression tests in parallel; see the
|
|
||||||
test_regress/driver.pl script -j flag.
|
|
||||||
|
|
||||||
=head1 VISITOR FUNCTIONS
|
|
||||||
|
|
||||||
=head2 Passing Variables
|
|
||||||
|
|
||||||
There's three ways data is passed between visitor functions.
|
|
||||||
|
|
||||||
1. A visitor-class member variable. This is generally for passing "parent"
|
|
||||||
information down to children. m_modp is a common example. It's set to
|
|
||||||
NULL in the constructor, where that node (AstModule visitor) sets it, then
|
|
||||||
the children are iterated, then it's cleared. Children under an AstModule
|
|
||||||
will see it set, while nodes elsewhere will see it clear. If there can be
|
|
||||||
nested items (for example an AstFor under an AstFor) the variable needs to
|
|
||||||
be save-set-restored in the AstFor visitor, otherwise exiting the lower for
|
|
||||||
will loose the upper for's setting.
|
|
||||||
|
|
||||||
2. User() attributes. Each node has 5 ->user() number or ->userp() pointer
|
|
||||||
utility values (a common technique lifted from graph traversal packages).
|
|
||||||
A visitor first clears the one it wants to use by calling
|
|
||||||
AstNode::user#ClearTree(), then it can mark any node's user() with whatever
|
|
||||||
data it wants. Readers just call nodep->user(), but may need to cast
|
|
||||||
appropriately, so you'll often see nodep->userp()->castSOMETYPE(). At the
|
|
||||||
top of each visitor are comments describing how the user() stuff applies to
|
|
||||||
that visitor class. For example:
|
|
||||||
|
|
||||||
// NODE STATE
|
|
||||||
// Cleared entire netlist
|
|
||||||
// AstModule::user1p() // bool. True to inline this module
|
|
||||||
|
|
||||||
This says that at the AstNetlist user1ClearTree() is called. Each
|
|
||||||
AstModule's is user1() is used to indicate if we're going to inline it.
|
|
||||||
|
|
||||||
These comments are important to make sure a user#() on a given AstNode type
|
|
||||||
is never being used for two different purposes.
|
|
||||||
|
|
||||||
Note that calling user#ClearTree is fast, it doesn't walk the tree, so it's
|
|
||||||
ok to call fairly often. For example, it's commonly called on every
|
|
||||||
module.
|
|
||||||
|
|
||||||
3. Parameters can be passed between the visitors in close to the "normal"
|
|
||||||
function caller to callee way. This is the second "vup" parameter that is
|
|
||||||
ignored on most of the visitor functions. V3Width does this, but it proved
|
|
||||||
more messy than the above and is deprecated. (V3Width was nearly the first
|
|
||||||
module written. Someday this scheme may be removed, as it slows the
|
|
||||||
program down to have to pass vup everywhere.)
|
|
||||||
|
|
||||||
=head1 DEBUGGING WITH GDB
|
|
||||||
|
|
||||||
The test_regress/driver.pl script accepts --debug --gdb to start Verilator
|
The test_regress/driver.pl script accepts --debug --gdb to start Verilator
|
||||||
under gdb. You can also use --debug --gdbbt to just backtrace and then
|
under gdb. You can also use --debug --gdbbt to just backtrace and then
|
||||||
|
|||||||
+2
-2
@@ -59,9 +59,9 @@ sub test {
|
|||||||
my $bin1 = $prefix."/bin";
|
my $bin1 = $prefix."/bin";
|
||||||
my $bin2 = $prefix."/share/bin";
|
my $bin2 = $prefix."/share/bin";
|
||||||
IO::File->new(">$testdir/foo.v")->print('module t; initial begin $display("HELLO WORLD"); end endmodule'."\n");
|
IO::File->new(">$testdir/foo.v")->print('module t; initial begin $display("HELLO WORLD"); end endmodule'."\n");
|
||||||
run("cd $testdir && PATH=$bin1:$bin2:\$PATH verilator --cc --exe foo.v");
|
run("cd $testdir && PATH=$bin1:$bin2:\$PATH verilator --cc foo.v");
|
||||||
run("cd $testdir/obj_dir && PATH=$bin1:$bin2:\$PATH make -f Vfoo.mk");
|
run("cd $testdir/obj_dir && PATH=$bin1:$bin2:\$PATH make -f Vfoo.mk");
|
||||||
#Need .c file for this to work
|
#Need .c file, and --exe for this to work
|
||||||
#run("cd $testdir && PATH=$bin1:$bin2:\$PATH obj_dir/Vfoo");
|
#run("cd $testdir && PATH=$bin1:$bin2:\$PATH obj_dir/Vfoo");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Executable
+59
@@ -0,0 +1,59 @@
|
|||||||
|
#!/usr/bin/perl -w
|
||||||
|
# See copyright, etc in below POD section.
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
require 5.006_001;
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
#======================================================================
|
||||||
|
# main
|
||||||
|
|
||||||
|
delete $ENV{MODULE_VERSION};
|
||||||
|
_setup_modules();
|
||||||
|
module('add','axiom-athdl');
|
||||||
|
exec('atsim',@ARGV);
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
# Modules package
|
||||||
|
|
||||||
|
sub _setup_modules {
|
||||||
|
# Load the 'module' command into the environment
|
||||||
|
my $init = "$ENV{MODULESHOME}/init/perl";
|
||||||
|
(-f $init) or die "%Error: Script not found: $init,";
|
||||||
|
require $init;
|
||||||
|
}
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
__END__
|
||||||
|
|
||||||
|
=pod
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
invoke_atsim - Invoke tool under "modules" command
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
invoke_atsim {ncv arguments}
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
=head1 DISTRIBUTION
|
||||||
|
|
||||||
|
Copyright 2005-2010 by Wilson Snyder. This package is free software; you
|
||||||
|
can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
Version 2.0.
|
||||||
|
|
||||||
|
=head1 AUTHORS
|
||||||
|
|
||||||
|
Wilson Snyder <[email protected]>
|
||||||
|
|
||||||
|
=head1 SEE ALSO
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
### Local Variables:
|
||||||
|
### compile-command: "./invoke_atsim -help"
|
||||||
|
### End:
|
||||||
@@ -126,6 +126,7 @@ sub prep {
|
|||||||
#
|
#
|
||||||
$wholefile =~ s/\b(uint[0-9]+_t)/vl$1/g;
|
$wholefile =~ s/\b(uint[0-9]+_t)/vl$1/g;
|
||||||
$wholefile =~ s/%ll/%" VL_PRI64 "/g;
|
$wholefile =~ s/%ll/%" VL_PRI64 "/g;
|
||||||
|
$wholefile =~ s/\(long long unsigned\)n/ n/g; # printQuad
|
||||||
#
|
#
|
||||||
$wholefile =~ s/\bSP_SC_BV/VL_SC_BV/g;
|
$wholefile =~ s/\bSP_SC_BV/VL_SC_BV/g;
|
||||||
$wholefile =~ s/\bSP_UNLIKELY/VL_UNLIKELY/g;
|
$wholefile =~ s/\bSP_UNLIKELY/VL_UNLIKELY/g;
|
||||||
|
|||||||
+7
-5
@@ -121,6 +121,7 @@ HEADERS = $(wildcard V*.h v*.h)
|
|||||||
|
|
||||||
ASTGEN = $(srcdir)/astgen
|
ASTGEN = $(srcdir)/astgen
|
||||||
BISONPRE = $(srcdir)/bisonpre
|
BISONPRE = $(srcdir)/bisonpre
|
||||||
|
FLEXFIX = $(srcdir)/flexfix
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
#### Top level
|
#### Top level
|
||||||
@@ -194,8 +195,9 @@ RAW_OBJS = \
|
|||||||
V3Link.o \
|
V3Link.o \
|
||||||
V3LinkCells.o \
|
V3LinkCells.o \
|
||||||
V3LinkDot.o \
|
V3LinkDot.o \
|
||||||
V3LinkLevel.o \
|
V3LinkJump.o \
|
||||||
V3LinkLValue.o \
|
V3LinkLValue.o \
|
||||||
|
V3LinkLevel.o \
|
||||||
V3LinkParse.o \
|
V3LinkParse.o \
|
||||||
V3LinkResolve.o \
|
V3LinkResolve.o \
|
||||||
V3Localize.o \
|
V3Localize.o \
|
||||||
@@ -295,15 +297,15 @@ V3Lexer_pregen.yy.cpp: verilog.l V3ParseBison.h $(HEADERS)
|
|||||||
${LEX} --version
|
${LEX} --version
|
||||||
${LEX} ${LFLAGS} -o$@ $<
|
${LEX} ${LFLAGS} -o$@ $<
|
||||||
|
|
||||||
V3Lexer.yy.cpp: V3Lexer_pregen.yy.cpp
|
V3Lexer.yy.cpp: V3Lexer_pregen.yy.cpp $(FLEXFIX)
|
||||||
$(PERL) $(srcdir)/flexfix <$< >$@
|
$(PERL) $(FLEXFIX) V3Lexer <$< >$@
|
||||||
|
|
||||||
V3PreLex_pregen.yy.cpp: V3PreLex.l $(HEADERS)
|
V3PreLex_pregen.yy.cpp: V3PreLex.l $(HEADERS)
|
||||||
${LEX} --version
|
${LEX} --version
|
||||||
${LEX} ${LFLAGS} -o$@ $<
|
${LEX} ${LFLAGS} -o$@ $<
|
||||||
|
|
||||||
V3PreLex.yy.cpp: V3PreLex_pregen.yy.cpp
|
V3PreLex.yy.cpp: V3PreLex_pregen.yy.cpp $(FLEXFIX)
|
||||||
$(PERL) $(srcdir)/flexfix <$< >$@
|
$(PERL) $(FLEXFIX) V3PreLex <$< >$@
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|||||||
+29
-23
@@ -197,7 +197,6 @@ private:
|
|||||||
// STATE
|
// STATE
|
||||||
ActiveNamer m_namer; // Tracking of active names
|
ActiveNamer m_namer; // Tracking of active names
|
||||||
AstCFunc* m_scopeFinalp; // Final function for this scope
|
AstCFunc* m_scopeFinalp; // Final function for this scope
|
||||||
AstAlways* m_alwaysp; // Under always
|
|
||||||
bool m_itemCombo; // Found a SenItem combo
|
bool m_itemCombo; // Found a SenItem combo
|
||||||
bool m_itemSequent; // Found a SenItem sequential
|
bool m_itemSequent; // Found a SenItem sequential
|
||||||
|
|
||||||
@@ -264,32 +263,22 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
virtual void visit(AstAlways* nodep, AstNUser*) {
|
void visitAlways(AstNode* nodep, AstSenTree* oldsensesp) {
|
||||||
// Move always to appropriate ACTIVE based on its sense list
|
// Move always to appropriate ACTIVE based on its sense list
|
||||||
UINFO(4," ALW "<<nodep<<endl);
|
if (oldsensesp
|
||||||
//if (debug()>=9) nodep->dumpTree(cout," Alw: ");
|
&& oldsensesp->sensesp()
|
||||||
|
&& oldsensesp->sensesp()->castSenItem()
|
||||||
if (!nodep->bodysp()) {
|
&& oldsensesp->sensesp()->castSenItem()->isNever()) {
|
||||||
// Empty always. Kill it.
|
|
||||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (nodep->sensesp()
|
|
||||||
&& nodep->sensesp()->sensesp()
|
|
||||||
&& nodep->sensesp()->sensesp()->castSenItem()
|
|
||||||
&& nodep->sensesp()->sensesp()->castSenItem()->isNever()) {
|
|
||||||
// Never executing. Kill it.
|
// Never executing. Kill it.
|
||||||
if (nodep->sensesp()->sensesp()->nextp()) nodep->v3fatalSrc("Never senitem should be alone, else the never should be eliminated.");
|
if (oldsensesp->sensesp()->nextp()) nodep->v3fatalSrc("Never senitem should be alone, else the never should be eliminated.");
|
||||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read sensitivitues
|
// Read sensitivitues
|
||||||
m_alwaysp = nodep;
|
|
||||||
m_itemCombo = false;
|
m_itemCombo = false;
|
||||||
m_itemSequent = false;
|
m_itemSequent = false;
|
||||||
nodep->sensesp()->iterateAndNext(*this);
|
oldsensesp->iterateAndNext(*this);
|
||||||
m_alwaysp = NULL;
|
|
||||||
bool combo = m_itemCombo;
|
bool combo = m_itemCombo;
|
||||||
bool sequent = m_itemSequent;
|
bool sequent = m_itemSequent;
|
||||||
|
|
||||||
@@ -311,15 +300,15 @@ private:
|
|||||||
// always (posedge RESET) { if (RESET).... } we know RESET is true.
|
// always (posedge RESET) { if (RESET).... } we know RESET is true.
|
||||||
// Summarize a long list of combo inputs as just "combo"
|
// Summarize a long list of combo inputs as just "combo"
|
||||||
#ifndef __COVERITY__ // Else dead code on next line.
|
#ifndef __COVERITY__ // Else dead code on next line.
|
||||||
if (combo) nodep->sensesp()->addSensesp
|
if (combo) oldsensesp->addSensesp
|
||||||
(new AstSenItem(nodep->fileline(),AstSenItem::Combo()));
|
(new AstSenItem(nodep->fileline(),AstSenItem::Combo()));
|
||||||
#endif
|
#endif
|
||||||
wantactivep = m_namer.getActive(nodep->fileline(), nodep->sensesp());
|
wantactivep = m_namer.getActive(nodep->fileline(), oldsensesp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete sensitivity list
|
// Delete sensitivity list
|
||||||
if (AstNode* oldsense = nodep->sensesp()) {
|
if (oldsensesp) {
|
||||||
oldsense->unlinkFrBackWithNext()->deleteTree(); oldsense=NULL;
|
oldsensesp->unlinkFrBackWithNext()->deleteTree(); oldsensesp=NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move node to new active
|
// Move node to new active
|
||||||
@@ -331,6 +320,24 @@ private:
|
|||||||
ActiveDlyVisitor dlyvisitor (nodep);
|
ActiveDlyVisitor dlyvisitor (nodep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstAlways* nodep, AstNUser*) {
|
||||||
|
// Move always to appropriate ACTIVE based on its sense list
|
||||||
|
UINFO(4," ALW "<<nodep<<endl);
|
||||||
|
//if (debug()>=9) nodep->dumpTree(cout," Alw: ");
|
||||||
|
|
||||||
|
if (!nodep->bodysp()) {
|
||||||
|
// Empty always. Kill it.
|
||||||
|
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
visitAlways(nodep, nodep->sensesp());
|
||||||
|
}
|
||||||
|
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
|
||||||
|
// Move always to appropriate ACTIVE based on its sense list
|
||||||
|
UINFO(4," ALWPub "<<nodep<<endl);
|
||||||
|
//if (debug()>=9) nodep->dumpTree(cout," Alw: ");
|
||||||
|
visitAlways(nodep, nodep->sensesp());
|
||||||
|
}
|
||||||
virtual void visit(AstSenGate* nodep, AstNUser*) {
|
virtual void visit(AstSenGate* nodep, AstNUser*) {
|
||||||
AstSenItem* subitemp = nodep->sensesp();
|
AstSenItem* subitemp = nodep->sensesp();
|
||||||
if (subitemp->edgeType() != AstEdgeType::ET_ANYEDGE
|
if (subitemp->edgeType() != AstEdgeType::ET_ANYEDGE
|
||||||
@@ -366,7 +373,6 @@ public:
|
|||||||
// CONSTUCTORS
|
// CONSTUCTORS
|
||||||
ActiveVisitor(AstNetlist* nodep) {
|
ActiveVisitor(AstNetlist* nodep) {
|
||||||
m_scopeFinalp = NULL;
|
m_scopeFinalp = NULL;
|
||||||
m_alwaysp = NULL;
|
|
||||||
m_itemCombo = false;
|
m_itemCombo = false;
|
||||||
m_itemSequent = false;
|
m_itemSequent = false;
|
||||||
nodep->accept(*this);
|
nodep->accept(*this);
|
||||||
|
|||||||
@@ -133,6 +133,9 @@ private:
|
|||||||
virtual void visit(AstAlways* nodep, AstNUser*) {
|
virtual void visit(AstAlways* nodep, AstNUser*) {
|
||||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
|
||||||
|
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||||
|
}
|
||||||
virtual void visit(AstFinal* nodep, AstNUser*) {
|
virtual void visit(AstFinal* nodep, AstNUser*) {
|
||||||
nodep->v3fatalSrc("Node should have been deleted");
|
nodep->v3fatalSrc("Node should have been deleted");
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -177,8 +177,7 @@ private:
|
|||||||
// VISITORS //========== Case assertions
|
// VISITORS //========== Case assertions
|
||||||
virtual void visit(AstCase* nodep, AstNUser*) {
|
virtual void visit(AstCase* nodep, AstNUser*) {
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (!nodep->user1()) {
|
if (!nodep->user1Inc()) {
|
||||||
nodep->user1(true);
|
|
||||||
bool has_default=false;
|
bool has_default=false;
|
||||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
|
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
|
||||||
if (itemp->isDefault()) has_default=true;
|
if (itemp->isDefault()) has_default=true;
|
||||||
|
|||||||
+11
-1
@@ -179,6 +179,8 @@ public:
|
|||||||
VAR_CLOCK_ENABLE, // V3LinkParse moves to AstVar::attrClockEn
|
VAR_CLOCK_ENABLE, // V3LinkParse moves to AstVar::attrClockEn
|
||||||
VAR_PUBLIC, // V3LinkParse moves to AstVar::sigPublic
|
VAR_PUBLIC, // V3LinkParse moves to AstVar::sigPublic
|
||||||
VAR_PUBLIC_FLAT, // V3LinkParse moves to AstVar::sigPublic
|
VAR_PUBLIC_FLAT, // V3LinkParse moves to AstVar::sigPublic
|
||||||
|
VAR_PUBLIC_FLAT_RD, // V3LinkParse moves to AstVar::sigPublic
|
||||||
|
VAR_PUBLIC_FLAT_RW, // V3LinkParse moves to AstVar::sigPublic
|
||||||
VAR_ISOLATE_ASSIGNMENTS, // V3LinkParse moves to AstVar::attrIsolateAssign
|
VAR_ISOLATE_ASSIGNMENTS, // V3LinkParse moves to AstVar::attrIsolateAssign
|
||||||
VAR_SFORMAT // V3LinkParse moves to AstVar::attrSFormat
|
VAR_SFORMAT // V3LinkParse moves to AstVar::attrSFormat
|
||||||
};
|
};
|
||||||
@@ -186,7 +188,8 @@ public:
|
|||||||
const char* ascii() const {
|
const char* ascii() const {
|
||||||
static const char* names[] = {
|
static const char* names[] = {
|
||||||
"EXPR_BITS", "VAR_BASE",
|
"EXPR_BITS", "VAR_BASE",
|
||||||
"VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC", "VAR_PUBLIC_FLAT",
|
"VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC",
|
||||||
|
"VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD","VAR_PUBLIC_FLAT_RW",
|
||||||
"VAR_ISOLATE_ASSIGNMENTS", "VAR_SFORMAT"
|
"VAR_ISOLATE_ASSIGNMENTS", "VAR_SFORMAT"
|
||||||
};
|
};
|
||||||
return names[m_e];
|
return names[m_e];
|
||||||
@@ -761,6 +764,7 @@ public:
|
|||||||
AstNode* clonep() const { return ((m_cloneCnt==s_cloneCntGbl)?m_clonep:NULL); }
|
AstNode* clonep() const { return ((m_cloneCnt==s_cloneCntGbl)?m_clonep:NULL); }
|
||||||
AstNode* firstAbovep() const { return ((backp() && backp()->nextp()!=this) ? backp() : NULL); } // Returns NULL when second or later in list
|
AstNode* firstAbovep() const { return ((backp() && backp()->nextp()!=this) ? backp() : NULL); } // Returns NULL when second or later in list
|
||||||
bool brokeExists() const;
|
bool brokeExists() const;
|
||||||
|
bool brokeExistsAbove() const;
|
||||||
|
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
virtual ~AstNode();
|
virtual ~AstNode();
|
||||||
@@ -818,6 +822,7 @@ public:
|
|||||||
void user1p(void* userp) { m_user1p=(AstNUser*)(userp); m_user1Cnt=AstUser1InUse::s_userCntGbl; }
|
void user1p(void* userp) { m_user1p=(AstNUser*)(userp); m_user1Cnt=AstUser1InUse::s_userCntGbl; }
|
||||||
int user1() const { return user1p()->castInt(); }
|
int user1() const { return user1p()->castInt(); }
|
||||||
void user1(int val) { user1p(AstNUser::fromInt(val)); }
|
void user1(int val) { user1p(AstNUser::fromInt(val)); }
|
||||||
|
int user1Inc() { int v=user1(); user1(v+1); return v; }
|
||||||
static void user1ClearTree() { AstUser1InUse::clear(); } // Clear userp()'s across the entire tree
|
static void user1ClearTree() { AstUser1InUse::clear(); } // Clear userp()'s across the entire tree
|
||||||
|
|
||||||
AstNUser* user2p() const {
|
AstNUser* user2p() const {
|
||||||
@@ -826,6 +831,7 @@ public:
|
|||||||
void user2p(void* userp) { m_user2p=(AstNUser*)(userp); m_user2Cnt=AstUser2InUse::s_userCntGbl; }
|
void user2p(void* userp) { m_user2p=(AstNUser*)(userp); m_user2Cnt=AstUser2InUse::s_userCntGbl; }
|
||||||
int user2() const { return user2p()->castInt(); }
|
int user2() const { return user2p()->castInt(); }
|
||||||
void user2(int val) { user2p(AstNUser::fromInt(val)); }
|
void user2(int val) { user2p(AstNUser::fromInt(val)); }
|
||||||
|
int user2Inc() { int v=user2(); user2(v+1); return v; }
|
||||||
static void user2ClearTree() { AstUser2InUse::clear(); }
|
static void user2ClearTree() { AstUser2InUse::clear(); }
|
||||||
|
|
||||||
AstNUser* user3p() const {
|
AstNUser* user3p() const {
|
||||||
@@ -834,6 +840,7 @@ public:
|
|||||||
void user3p(void* userp) { m_user3p=(AstNUser*)(userp); m_user3Cnt=AstUser3InUse::s_userCntGbl; }
|
void user3p(void* userp) { m_user3p=(AstNUser*)(userp); m_user3Cnt=AstUser3InUse::s_userCntGbl; }
|
||||||
int user3() const { return user3p()->castInt(); }
|
int user3() const { return user3p()->castInt(); }
|
||||||
void user3(int val) { user3p(AstNUser::fromInt(val)); }
|
void user3(int val) { user3p(AstNUser::fromInt(val)); }
|
||||||
|
int user3Inc() { int v=user3(); user3(v+1); return v; }
|
||||||
static void user3ClearTree() { AstUser3InUse::clear(); }
|
static void user3ClearTree() { AstUser3InUse::clear(); }
|
||||||
|
|
||||||
AstNUser* user4p() const {
|
AstNUser* user4p() const {
|
||||||
@@ -842,6 +849,7 @@ public:
|
|||||||
void user4p(void* userp) { m_user4p=(AstNUser*)(userp); m_user4Cnt=AstUser4InUse::s_userCntGbl; }
|
void user4p(void* userp) { m_user4p=(AstNUser*)(userp); m_user4Cnt=AstUser4InUse::s_userCntGbl; }
|
||||||
int user4() const { return user4p()->castInt(); }
|
int user4() const { return user4p()->castInt(); }
|
||||||
void user4(int val) { user4p(AstNUser::fromInt(val)); }
|
void user4(int val) { user4p(AstNUser::fromInt(val)); }
|
||||||
|
int user4Inc() { int v=user4(); user4(v+1); return v; }
|
||||||
static void user4ClearTree() { AstUser4InUse::clear(); }
|
static void user4ClearTree() { AstUser4InUse::clear(); }
|
||||||
|
|
||||||
AstNUser* user5p() const {
|
AstNUser* user5p() const {
|
||||||
@@ -850,6 +858,7 @@ public:
|
|||||||
void user5p(void* userp) { m_user5p=(AstNUser*)(userp); m_user5Cnt=AstUser5InUse::s_userCntGbl; }
|
void user5p(void* userp) { m_user5p=(AstNUser*)(userp); m_user5Cnt=AstUser5InUse::s_userCntGbl; }
|
||||||
int user5() const { return user5p()->castInt(); }
|
int user5() const { return user5p()->castInt(); }
|
||||||
void user5(int val) { user5p(AstNUser::fromInt(val)); }
|
void user5(int val) { user5p(AstNUser::fromInt(val)); }
|
||||||
|
int user5Inc() { int v=user5(); user5(v+1); return v; }
|
||||||
static void user5ClearTree() { AstUser5InUse::clear(); }
|
static void user5ClearTree() { AstUser5InUse::clear(); }
|
||||||
|
|
||||||
vluint64_t editCount() const { return m_editCount; }
|
vluint64_t editCount() const { return m_editCount; }
|
||||||
@@ -870,6 +879,7 @@ public:
|
|||||||
AstNode* addNext(AstNode* newp); // Returns this, adds to end of list
|
AstNode* addNext(AstNode* newp); // Returns this, adds to end of list
|
||||||
AstNode* addNextNull(AstNode* newp); // Returns this, adds to end of list, NULL is OK
|
AstNode* addNextNull(AstNode* newp); // Returns this, adds to end of list, NULL is OK
|
||||||
void addNextHere(AstNode* newp); // Adds after speced node
|
void addNextHere(AstNode* newp); // Adds after speced node
|
||||||
|
void addPrev(AstNode* newp) { replaceWith(newp); newp->addNext(this); }
|
||||||
void addHereThisAsNext(AstNode* newp); // Adds at old place of this, this becomes next
|
void addHereThisAsNext(AstNode* newp); // Adds at old place of this, this becomes next
|
||||||
void replaceWith(AstNode* newp); // Replace current node in tree with new node
|
void replaceWith(AstNode* newp); // Replace current node in tree with new node
|
||||||
void v3errorEnd(ostringstream& str) const;
|
void v3errorEnd(ostringstream& str) const;
|
||||||
|
|||||||
+56
-5
@@ -137,6 +137,43 @@ string AstVar::vlArgType(bool named, bool forReturn) const {
|
|||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string AstVar::vlEnumType() const {
|
||||||
|
string arg;
|
||||||
|
AstBasicDType* bdtypep = basicp();
|
||||||
|
bool strtype = bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::STRING;
|
||||||
|
if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::CHARPTR) {
|
||||||
|
return "VLVT_PTR";
|
||||||
|
} else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::SCOPEPTR) {
|
||||||
|
return "VLVT_PTR";
|
||||||
|
} else if (strtype) {
|
||||||
|
arg += "VLVT_STRING";
|
||||||
|
} else if (widthMin() <= 8) {
|
||||||
|
arg += "VLVT_UINT8";
|
||||||
|
} else if (widthMin() <= 16) {
|
||||||
|
arg += "VLVT_UINT16";
|
||||||
|
} else if (widthMin() <= VL_WORDSIZE) {
|
||||||
|
arg += "VLVT_UINT32";
|
||||||
|
} else if (isQuad()) {
|
||||||
|
arg += "VLVT_UINT64";
|
||||||
|
} else if (isWide()) {
|
||||||
|
arg += "VLVT_WDATA";
|
||||||
|
}
|
||||||
|
// else return "VLVT_UNKNOWN"
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
string AstVar::vlEnumDir() const {
|
||||||
|
if (isInout()) {
|
||||||
|
return "VLVD_INOUT";
|
||||||
|
} else if (isInOnly()) {
|
||||||
|
return "VLVD_IN";
|
||||||
|
} else if (isOutOnly()) {
|
||||||
|
return "VLVD_OUT";
|
||||||
|
} else {
|
||||||
|
return "VLVD_NODIR";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
string AstVar::cPubArgType(bool named, bool forReturn) const {
|
string AstVar::cPubArgType(bool named, bool forReturn) const {
|
||||||
if (forReturn) named=false;
|
if (forReturn) named=false;
|
||||||
string arg;
|
string arg;
|
||||||
@@ -258,13 +295,15 @@ uint32_t AstVar::arrayElements() const {
|
|||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t AstVar::dimensions() const {
|
pair<uint32_t,uint32_t> AstVar::dimensions() const {
|
||||||
// How many array dimensions does this Var have?
|
// How many array dimensions (packed,unpacked) does this Var have?
|
||||||
uint32_t dim = 0;
|
uint32_t packed = 0;
|
||||||
|
uint32_t unpacked = 0;
|
||||||
for (AstNodeDType* dtypep=this->dtypep(); dtypep; ) {
|
for (AstNodeDType* dtypep=this->dtypep(); dtypep; ) {
|
||||||
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
||||||
if (AstArrayDType* adtypep = dtypep->castArrayDType()) {
|
if (AstArrayDType* adtypep = dtypep->castArrayDType()) {
|
||||||
dim += 1;
|
if (adtypep->isPacked()) packed += 1;
|
||||||
|
else unpacked += 1;
|
||||||
dtypep = adtypep->dtypep();
|
dtypep = adtypep->dtypep();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -272,7 +311,7 @@ uint32_t AstVar::dimensions() const {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dim;
|
return make_pair(packed, unpacked);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special operators
|
// Special operators
|
||||||
@@ -348,6 +387,8 @@ string AstScopeName::scopeSymName() const {
|
|||||||
out += textp->text();
|
out += textp->text();
|
||||||
}
|
}
|
||||||
if (out.substr(0,10) == "__DOT__TOP") out.replace(0,10,"");
|
if (out.substr(0,10) == "__DOT__TOP") out.replace(0,10,"");
|
||||||
|
if (out.substr(0,7) == "__DOT__") out.replace(0,7,"");
|
||||||
|
if (out.substr(0,1) == ".") out.replace(0,1,"");
|
||||||
string::size_type pos;
|
string::size_type pos;
|
||||||
while ((pos=out.find(".")) != string::npos) {
|
while ((pos=out.find(".")) != string::npos) {
|
||||||
out.replace(pos, 1, "__");
|
out.replace(pos, 1, "__");
|
||||||
@@ -464,6 +505,10 @@ void AstNode::dump(ostream& os) {
|
|||||||
if (name()!="") os<<" "<<AstNode::quoteName(name());
|
if (name()!="") os<<" "<<AstNode::quoteName(name());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AstArrayDType::dump(ostream& str) {
|
||||||
|
this->AstNode::dump(str);
|
||||||
|
if (isPacked()) str<<" [PACKED]";
|
||||||
|
}
|
||||||
void AstArraySel::dump(ostream& str) {
|
void AstArraySel::dump(ostream& str) {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
str<<" [start:"<<start()<<"] [length:"<<length()<<"]";
|
str<<" [start:"<<start()<<"] [length:"<<length()<<"]";
|
||||||
@@ -494,6 +539,12 @@ void AstDisplay::dump(ostream& str) {
|
|||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
//str<<" "<<displayType().ascii();
|
//str<<" "<<displayType().ascii();
|
||||||
}
|
}
|
||||||
|
void AstJumpGo::dump(ostream& str) {
|
||||||
|
this->AstNode::dump(str);
|
||||||
|
str<<" -> ";
|
||||||
|
if (labelp()) { labelp()->dump(str); }
|
||||||
|
else { str<<"%Error:UNLINKED"; }
|
||||||
|
}
|
||||||
void AstEnumItemRef::dump(ostream& str) {
|
void AstEnumItemRef::dump(ostream& str) {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
str<<" -> ";
|
str<<" -> ";
|
||||||
|
|||||||
+119
-15
@@ -204,13 +204,17 @@ public:
|
|||||||
|
|
||||||
struct AstArrayDType : public AstNodeDType {
|
struct AstArrayDType : public AstNodeDType {
|
||||||
// Array data type, ie "some_dtype var_name [2:0]"
|
// Array data type, ie "some_dtype var_name [2:0]"
|
||||||
AstArrayDType(FileLine* fl, AstNodeDType* dtypep, AstRange* rangep)
|
private:
|
||||||
: AstNodeDType(fl) {
|
bool m_packed;
|
||||||
|
public:
|
||||||
|
AstArrayDType(FileLine* fl, AstNodeDType* dtypep, AstRange* rangep, bool isPacked=false)
|
||||||
|
: AstNodeDType(fl), m_packed(isPacked) {
|
||||||
setOp1p(dtypep);
|
setOp1p(dtypep);
|
||||||
setOp2p(rangep);
|
setOp2p(rangep);
|
||||||
widthSignedFrom(dtypep);
|
widthSignedFrom(dtypep);
|
||||||
}
|
}
|
||||||
ASTNODE_NODE_FUNCS(ArrayDType, ARRAYDTYPE)
|
ASTNODE_NODE_FUNCS(ArrayDType, ARRAYDTYPE)
|
||||||
|
virtual void dump(ostream& str);
|
||||||
AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
|
AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
|
||||||
AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable
|
AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable
|
||||||
void dtypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
void dtypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
||||||
@@ -225,6 +229,7 @@ struct AstArrayDType : public AstNodeDType {
|
|||||||
int lsb() const { return arrayp()->lsbConst(); }
|
int lsb() const { return arrayp()->lsbConst(); }
|
||||||
int elementsConst() const { return arrayp()->elementsConst(); }
|
int elementsConst() const { return arrayp()->elementsConst(); }
|
||||||
int msbMaxSelect() const { return (lsb()<0 ? msb()-lsb() : msb()); } // Maximum value a [] select may index
|
int msbMaxSelect() const { return (lsb()<0 ? msb()-lsb() : msb()); } // Maximum value a [] select may index
|
||||||
|
bool isPacked() const { return m_packed; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstBasicDType : public AstNodeDType {
|
struct AstBasicDType : public AstNodeDType {
|
||||||
@@ -542,8 +547,10 @@ private:
|
|||||||
bool m_sc:1; // SystemC variable
|
bool m_sc:1; // SystemC variable
|
||||||
bool m_scClocked:1; // SystemC sc_clk<> needed
|
bool m_scClocked:1; // SystemC sc_clk<> needed
|
||||||
bool m_scSensitive:1;// SystemC sensitive() needed
|
bool m_scSensitive:1;// SystemC sensitive() needed
|
||||||
bool m_sigPublic:1; // User C code accesses this signal
|
bool m_sigPublic:1; // User C code accesses this signal or is top signal
|
||||||
bool m_sigModPublic:1;// User C code accesses this signal and module
|
bool m_sigModPublic:1;// User C code accesses this signal and module
|
||||||
|
bool m_sigUserRdPublic:1; // User C code accesses this signal, read only
|
||||||
|
bool m_sigUserRWPublic:1; // User C code accesses this signal, read-write
|
||||||
bool m_usedClock:1; // Signal used as a clock
|
bool m_usedClock:1; // Signal used as a clock
|
||||||
bool m_usedParam:1; // Parameter is referenced (on link; later signals not setup)
|
bool m_usedParam:1; // Parameter is referenced (on link; later signals not setup)
|
||||||
bool m_funcLocal:1; // Local variable for a function
|
bool m_funcLocal:1; // Local variable for a function
|
||||||
@@ -561,7 +568,7 @@ private:
|
|||||||
m_primaryIO=false;
|
m_primaryIO=false;
|
||||||
m_sc=false; m_scClocked=false; m_scSensitive=false;
|
m_sc=false; m_scClocked=false; m_scSensitive=false;
|
||||||
m_usedClock=false; m_usedParam=false;
|
m_usedClock=false; m_usedParam=false;
|
||||||
m_sigPublic=false; m_sigModPublic=false;
|
m_sigPublic=false; m_sigModPublic=false; m_sigUserRdPublic=false; m_sigUserRWPublic=false;
|
||||||
m_funcLocal=false; m_funcReturn=false;
|
m_funcLocal=false; m_funcReturn=false;
|
||||||
m_attrClockEn=false; m_attrIsolateAssign=false; m_attrSFormat=false;
|
m_attrClockEn=false; m_attrIsolateAssign=false; m_attrSFormat=false;
|
||||||
m_fileDescr=false; m_isConst=false; m_isStatic=false;
|
m_fileDescr=false; m_isConst=false; m_isStatic=false;
|
||||||
@@ -607,12 +614,14 @@ public:
|
|||||||
string cPubArgType(bool named, bool forReturn) const; // Return C /*public*/ type for argument: bool, uint32_t, uint64_t, etc.
|
string cPubArgType(bool named, bool forReturn) const; // Return C /*public*/ type for argument: bool, uint32_t, uint64_t, etc.
|
||||||
string dpiArgType(bool named, bool forReturn) const; // Return DPI-C type for argument
|
string dpiArgType(bool named, bool forReturn) const; // Return DPI-C type for argument
|
||||||
string vlArgType(bool named, bool forReturn) const; // Return Verilator internal type for argument: CData, SData, IData, WData
|
string vlArgType(bool named, bool forReturn) const; // Return Verilator internal type for argument: CData, SData, IData, WData
|
||||||
|
string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc
|
||||||
|
string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc
|
||||||
void combineType(AstVarType type);
|
void combineType(AstVarType type);
|
||||||
AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
|
AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
|
||||||
AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType)
|
AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType)
|
||||||
AstBasicDType* basicp() const { return dtypep()->basicp(); } // (Slow) recurse down to find basic data type (Note don't need virtual - AstVar isn't a NodeDType)
|
AstBasicDType* basicp() const { return dtypep()->basicp(); } // (Slow) recurse down to find basic data type (Note don't need virtual - AstVar isn't a NodeDType)
|
||||||
AstNodeDType* dtypeDimensionp(int depth) const;
|
AstNodeDType* dtypeDimensionp(int depth) const;
|
||||||
uint32_t dimensions() const;
|
pair<uint32_t,uint32_t> dimensions() const;
|
||||||
AstNode* valuep() const { return op3p()->castNode(); } // op3 = Initial value that never changes (static const)
|
AstNode* valuep() const { return op3p()->castNode(); } // op3 = Initial value that never changes (static const)
|
||||||
void valuep(AstNode* nodep) { setOp3p(nodep); } // It's valuep, not constp, as may be more complicated than a AstConst
|
void valuep(AstNode* nodep) { setOp3p(nodep); } // It's valuep, not constp, as may be more complicated than a AstConst
|
||||||
void addAttrsp(AstNode* nodep) { addNOp4p(nodep); }
|
void addAttrsp(AstNode* nodep) { addNOp4p(nodep); }
|
||||||
@@ -628,6 +637,8 @@ public:
|
|||||||
void usedParam(bool flag) { m_usedParam = flag; }
|
void usedParam(bool flag) { m_usedParam = flag; }
|
||||||
void sigPublic(bool flag) { m_sigPublic = flag; }
|
void sigPublic(bool flag) { m_sigPublic = flag; }
|
||||||
void sigModPublic(bool flag) { m_sigModPublic = flag; }
|
void sigModPublic(bool flag) { m_sigModPublic = flag; }
|
||||||
|
void sigUserRdPublic(bool flag) { m_sigUserRdPublic = flag; if (flag) sigPublic(true); }
|
||||||
|
void sigUserRWPublic(bool flag) { m_sigUserRWPublic = flag; if (flag) sigUserRdPublic(true); }
|
||||||
void sc(bool flag) { m_sc = flag; }
|
void sc(bool flag) { m_sc = flag; }
|
||||||
void scSensitive(bool flag) { m_scSensitive = flag; }
|
void scSensitive(bool flag) { m_scSensitive = flag; }
|
||||||
void primaryIO(bool flag) { m_primaryIO = flag; }
|
void primaryIO(bool flag) { m_primaryIO = flag; }
|
||||||
@@ -670,6 +681,8 @@ public:
|
|||||||
bool isScSensitive() const { return m_scSensitive; }
|
bool isScSensitive() const { return m_scSensitive; }
|
||||||
bool isSigPublic() const;
|
bool isSigPublic() const;
|
||||||
bool isSigModPublic() const { return m_sigModPublic; }
|
bool isSigModPublic() const { return m_sigModPublic; }
|
||||||
|
bool isSigUserRdPublic() const { return m_sigUserRdPublic; }
|
||||||
|
bool isSigUserRWPublic() const { return m_sigUserRWPublic; }
|
||||||
bool isTrace() const { return m_trace; }
|
bool isTrace() const { return m_trace; }
|
||||||
bool isConst() const { return m_isConst; }
|
bool isConst() const { return m_isConst; }
|
||||||
bool isStatic() const { return m_isStatic; }
|
bool isStatic() const { return m_isStatic; }
|
||||||
@@ -699,6 +712,8 @@ public:
|
|||||||
combineType(typevarp->varType());
|
combineType(typevarp->varType());
|
||||||
if (typevarp->isSigPublic()) sigPublic(true);
|
if (typevarp->isSigPublic()) sigPublic(true);
|
||||||
if (typevarp->isSigModPublic()) sigModPublic(true);
|
if (typevarp->isSigModPublic()) sigModPublic(true);
|
||||||
|
if (typevarp->isSigUserRdPublic()) sigUserRdPublic(true);
|
||||||
|
if (typevarp->isSigUserRWPublic()) sigUserRWPublic(true);
|
||||||
if (typevarp->attrScClocked()) attrScClocked(true);
|
if (typevarp->attrScClocked()) attrScClocked(true);
|
||||||
}
|
}
|
||||||
void inlineAttrReset(const string& name) {
|
void inlineAttrReset(const string& name) {
|
||||||
@@ -1265,6 +1280,24 @@ struct AstAlways : public AstNode {
|
|||||||
bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); }
|
bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AstAlwaysPublic : public AstNodeStmt {
|
||||||
|
// "Fake" sensitivity created by /*verilator public_flat_rw @(edgelist)*/
|
||||||
|
// Body statements are just AstVarRefs to the public signals
|
||||||
|
AstAlwaysPublic(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp)
|
||||||
|
: AstNodeStmt(fl) {
|
||||||
|
addNOp1p(sensesp); addNOp2p(bodysp);
|
||||||
|
}
|
||||||
|
ASTNODE_NODE_FUNCS(AlwaysPublic, ALWAYSPUBLIC)
|
||||||
|
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||||
|
virtual bool same(AstNode* samep) const { return true; }
|
||||||
|
//
|
||||||
|
AstSenTree* sensesp() const { return op1p()->castSenTree(); } // op1 = Sensitivity list
|
||||||
|
AstNode* bodysp() const { return op2p()->castNode(); } // op2 = Statements to evaluate
|
||||||
|
void addStmtp(AstNode* nodep) { addOp2p(nodep); }
|
||||||
|
// Special accessors
|
||||||
|
bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); }
|
||||||
|
};
|
||||||
|
|
||||||
struct AstAlwaysPost : public AstNode {
|
struct AstAlwaysPost : public AstNode {
|
||||||
// Like always but post assignments for memory assignment IFs
|
// Like always but post assignments for memory assignment IFs
|
||||||
AstAlwaysPost(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp)
|
AstAlwaysPost(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp)
|
||||||
@@ -1846,14 +1879,6 @@ struct AstGenFor : public AstNodeFor {
|
|||||||
ASTNODE_NODE_FUNCS(GenFor, GENFOR)
|
ASTNODE_NODE_FUNCS(GenFor, GENFOR)
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstFor : public AstNodeFor {
|
|
||||||
AstFor(FileLine* fileline, AstNode* initsp, AstNode* condp,
|
|
||||||
AstNode* incsp, AstNode* bodysp)
|
|
||||||
: AstNodeFor(fileline, initsp, condp, incsp, bodysp) {
|
|
||||||
}
|
|
||||||
ASTNODE_NODE_FUNCS(For, FOR)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AstRepeat : public AstNodeStmt {
|
struct AstRepeat : public AstNodeStmt {
|
||||||
AstRepeat(FileLine* fileline, AstNode* countp, AstNode* bodysp)
|
AstRepeat(FileLine* fileline, AstNode* countp, AstNode* bodysp)
|
||||||
: AstNodeStmt(fileline) {
|
: AstNodeStmt(fileline) {
|
||||||
@@ -1869,16 +1894,18 @@ struct AstRepeat : public AstNodeStmt {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct AstWhile : public AstNodeStmt {
|
struct AstWhile : public AstNodeStmt {
|
||||||
AstWhile(FileLine* fileline, AstNode* condp, AstNode* bodysp)
|
AstWhile(FileLine* fileline, AstNode* condp, AstNode* bodysp, AstNode* incsp=NULL)
|
||||||
: AstNodeStmt(fileline) {
|
: AstNodeStmt(fileline) {
|
||||||
setOp2p(condp); addNOp3p(bodysp);
|
setOp2p(condp); addNOp3p(bodysp); addNOp4p(incsp);
|
||||||
}
|
}
|
||||||
ASTNODE_NODE_FUNCS(While, WHILE)
|
ASTNODE_NODE_FUNCS(While, WHILE)
|
||||||
AstNode* precondsp() const { return op1p()->castNode(); } // op1= prepare statements for condition (exec every loop)
|
AstNode* precondsp() const { return op1p()->castNode(); } // op1= prepare statements for condition (exec every loop)
|
||||||
AstNode* condp() const { return op2p()->castNode(); } // op2= condition to continue
|
AstNode* condp() const { return op2p()->castNode(); } // op2= condition to continue
|
||||||
AstNode* bodysp() const { return op3p()->castNode(); } // op3= body of loop
|
AstNode* bodysp() const { return op3p()->castNode(); } // op3= body of loop
|
||||||
|
AstNode* incsp() const { return op4p()->castNode(); } // op4= increment (if from a FOR loop)
|
||||||
void addPrecondsp(AstNode* newp) { addOp1p(newp); }
|
void addPrecondsp(AstNode* newp) { addOp1p(newp); }
|
||||||
void addBodysp(AstNode* newp) { addOp3p(newp); }
|
void addBodysp(AstNode* newp) { addOp3p(newp); }
|
||||||
|
void addIncsp(AstNode* newp) { addOp4p(newp); }
|
||||||
virtual bool isGateOptimizable() const { return false; }
|
virtual bool isGateOptimizable() const { return false; }
|
||||||
virtual int instrCount() const { return instrCountBranch(); }
|
virtual int instrCount() const { return instrCountBranch(); }
|
||||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||||
@@ -1887,6 +1914,36 @@ struct AstWhile : public AstNodeStmt {
|
|||||||
virtual void addNextStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here
|
virtual void addNextStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AstBreak : public AstNodeStmt {
|
||||||
|
AstBreak(FileLine* fileline)
|
||||||
|
: AstNodeStmt (fileline) {}
|
||||||
|
ASTNODE_NODE_FUNCS(Break, BREAK)
|
||||||
|
virtual string verilogKwd() const { return "break"; };
|
||||||
|
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||||
|
virtual bool isSplittable() const { return false; } // SPECIAL: We don't process code after breaks
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AstContinue : public AstNodeStmt {
|
||||||
|
AstContinue(FileLine* fileline)
|
||||||
|
: AstNodeStmt (fileline) {}
|
||||||
|
ASTNODE_NODE_FUNCS(Continue, CONTINUE)
|
||||||
|
virtual string verilogKwd() const { return "continue"; };
|
||||||
|
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||||
|
virtual bool isSplittable() const { return false; } // SPECIAL: We don't process code after breaks
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AstReturn : public AstNodeStmt {
|
||||||
|
AstReturn(FileLine* fileline, AstNode* lhsp=NULL)
|
||||||
|
: AstNodeStmt (fileline) {
|
||||||
|
setNOp1p(lhsp);
|
||||||
|
}
|
||||||
|
ASTNODE_NODE_FUNCS(Return, RETURN)
|
||||||
|
virtual string verilogKwd() const { return "return"; };
|
||||||
|
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||||
|
AstNode* lhsp() const { return op1p(); }
|
||||||
|
virtual bool isSplittable() const { return false; } // SPECIAL: We don't process code after breaks
|
||||||
|
};
|
||||||
|
|
||||||
struct AstGenIf : public AstNodeIf {
|
struct AstGenIf : public AstNodeIf {
|
||||||
AstGenIf(FileLine* fileline, AstNode* condp, AstNode* ifsp, AstNode* elsesp)
|
AstGenIf(FileLine* fileline, AstNode* condp, AstNode* ifsp, AstNode* elsesp)
|
||||||
: AstNodeIf(fileline, condp, ifsp, elsesp) {
|
: AstNodeIf(fileline, condp, ifsp, elsesp) {
|
||||||
@@ -1901,6 +1958,53 @@ struct AstIf : public AstNodeIf {
|
|||||||
ASTNODE_NODE_FUNCS(If, IF)
|
ASTNODE_NODE_FUNCS(If, IF)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AstJumpLabel : public AstNodeStmt {
|
||||||
|
// Jump point declaration
|
||||||
|
// Separate from AstJumpGo; as a declaration can't be deleted
|
||||||
|
// Parents: {statement list}
|
||||||
|
// Children: {statement list, with JumpGo below}
|
||||||
|
private:
|
||||||
|
int m_labelNum; // Set by V3EmitCSyms to tell final V3Emit what to increment
|
||||||
|
public:
|
||||||
|
AstJumpLabel(FileLine* fl, AstNode* stmtsp)
|
||||||
|
: AstNodeStmt(fl) ,m_labelNum(0) {
|
||||||
|
addNOp1p(stmtsp);
|
||||||
|
}
|
||||||
|
virtual int instrCount() const { return 0; }
|
||||||
|
ASTNODE_NODE_FUNCS(JumpLabel, JUMPLABEL)
|
||||||
|
virtual bool maybePointedTo() const { return true; }
|
||||||
|
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||||
|
virtual bool same(AstNode* samep) const { return true; }
|
||||||
|
// op1 = Statements
|
||||||
|
AstNode* stmtsp() const { return op1p()->castNode(); } // op1 = List of statements
|
||||||
|
void addStmtsp(AstNode* nodep) { addNOp1p(nodep); }
|
||||||
|
int labelNum() const { return m_labelNum; }
|
||||||
|
void labelNum(int flag) { m_labelNum=flag; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AstJumpGo : public AstNodeStmt {
|
||||||
|
// Jump point; branch up to the JumpLabel
|
||||||
|
// Parents: {statement list}
|
||||||
|
private:
|
||||||
|
AstJumpLabel* m_labelp; // [After V3Jump] Pointer to declaration
|
||||||
|
public:
|
||||||
|
AstJumpGo(FileLine* fl, AstJumpLabel* labelp)
|
||||||
|
: AstNodeStmt(fl) {
|
||||||
|
m_labelp = labelp;
|
||||||
|
}
|
||||||
|
ASTNODE_NODE_FUNCS(JumpGo, JUMPGO)
|
||||||
|
virtual bool broken() const { return !labelp()->brokeExistsAbove(); }
|
||||||
|
virtual void cloneRelink() { if (m_labelp->clonep()) m_labelp = m_labelp->clonep()->castJumpLabel(); }
|
||||||
|
virtual void dump(ostream& str);
|
||||||
|
virtual int instrCount() const { return instrCountBranch(); }
|
||||||
|
virtual V3Hash sameHash() const { return V3Hash(labelp()); }
|
||||||
|
virtual bool same(AstNode* samep) const { // Also same if identical tree structure all the way down, but hard to detect
|
||||||
|
return labelp()==samep->castJumpGo()->labelp(); }
|
||||||
|
virtual bool isGateOptimizable() const { return false; }
|
||||||
|
virtual bool isSplittable() const { return false; } // SPECIAL: We don't process code after breaks
|
||||||
|
AstJumpLabel* labelp() const { return m_labelp; }
|
||||||
|
};
|
||||||
|
|
||||||
struct AstUntilStable : public AstNodeStmt {
|
struct AstUntilStable : public AstNodeStmt {
|
||||||
// Quasi-while loop until given signals are stable
|
// Quasi-while loop until given signals are stable
|
||||||
// Parents: CFUNC (generally)
|
// Parents: CFUNC (generally)
|
||||||
|
|||||||
@@ -135,53 +135,6 @@ private:
|
|||||||
m_modp->addStmtp(nodep);
|
m_modp->addStmtp(nodep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstFor* nodep, AstNUser*) {
|
|
||||||
// So later optimizations don't need to deal with them,
|
|
||||||
// FOR(init,cond,assign,body) -> init,WHILE(cond) { body, assign }
|
|
||||||
AstNode* initsp = nodep->initsp(); if (initsp) initsp->unlinkFrBackWithNext();
|
|
||||||
AstNode* condp = nodep->condp(); if (condp) condp->unlinkFrBackWithNext();
|
|
||||||
AstNode* incsp = nodep->incsp(); if (incsp) incsp->unlinkFrBackWithNext();
|
|
||||||
AstNode* bodysp = nodep->bodysp(); if (bodysp) bodysp->unlinkFrBackWithNext();
|
|
||||||
bodysp = bodysp->addNext(incsp);
|
|
||||||
AstNode* newp = new AstWhile(nodep->fileline(),
|
|
||||||
condp,
|
|
||||||
bodysp);
|
|
||||||
initsp = initsp->addNext(newp);
|
|
||||||
newp = initsp;
|
|
||||||
nodep->replaceWith(newp);
|
|
||||||
nodep->deleteTree(); nodep=NULL;
|
|
||||||
}
|
|
||||||
virtual void visit(AstRepeat* nodep, AstNUser*) {
|
|
||||||
// So later optimizations don't need to deal with them,
|
|
||||||
// REPEAT(count,body) -> loop=count,WHILE(loop>0) { body, loop-- }
|
|
||||||
// Note var can be signed or unsigned based on original number.
|
|
||||||
AstNode* countp = nodep->countp()->unlinkFrBackWithNext();
|
|
||||||
string name = string("__Vrepeat")+cvtToStr(m_repeatNum++);
|
|
||||||
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP, name, AstLogicPacked(), countp->width());
|
|
||||||
m_modp->addStmtp(varp);
|
|
||||||
AstNode* initsp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
|
|
||||||
countp);
|
|
||||||
AstNode* decp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
|
|
||||||
new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
|
|
||||||
new AstConst(nodep->fileline(), 1)));
|
|
||||||
AstNode* condp;
|
|
||||||
if (countp->isSigned()) {
|
|
||||||
condp = new AstGtS(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
|
|
||||||
new AstConst(nodep->fileline(), 0));
|
|
||||||
} else {
|
|
||||||
condp = new AstGt (nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
|
|
||||||
new AstConst(nodep->fileline(), 0));
|
|
||||||
}
|
|
||||||
AstNode* bodysp = nodep->bodysp(); if (bodysp) bodysp->unlinkFrBackWithNext();
|
|
||||||
bodysp = bodysp->addNext(decp);
|
|
||||||
AstNode* newp = new AstWhile(nodep->fileline(),
|
|
||||||
condp,
|
|
||||||
bodysp);
|
|
||||||
initsp = initsp->addNext(newp);
|
|
||||||
newp = initsp;
|
|
||||||
nodep->replaceWith(newp);
|
|
||||||
nodep->deleteTree(); nodep=NULL;
|
|
||||||
}
|
|
||||||
virtual void visit(AstScopeName* nodep, AstNUser*) {
|
virtual void visit(AstScopeName* nodep, AstNUser*) {
|
||||||
// If there's a %m in the display text, we add a special node that will contain the name()
|
// If there's a %m in the display text, we add a special node that will contain the name()
|
||||||
// Similar code in V3Inline
|
// Similar code in V3Inline
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ private:
|
|||||||
static const int FLAG_IN_TREE = 0x02; // Is in netlist tree
|
static const int FLAG_IN_TREE = 0x02; // Is in netlist tree
|
||||||
static const int FLAG_LINKABLE = 0x04; // Is in netlist tree, can be linked to
|
static const int FLAG_LINKABLE = 0x04; // Is in netlist tree, can be linked to
|
||||||
static const int FLAG_LEAKED = 0x08; // Known to have been leaked
|
static const int FLAG_LEAKED = 0x08; // Known to have been leaked
|
||||||
|
static const int FLAG_UNDER_NOW = 0x10; // Is in tree as parent of current node
|
||||||
public:
|
public:
|
||||||
// METHODS
|
// METHODS
|
||||||
static void deleted(const AstNode* nodep) {
|
static void deleted(const AstNode* nodep) {
|
||||||
@@ -74,6 +75,15 @@ public:
|
|||||||
s_nodes.insert(make_pair(nodep,FLAG_ALLOCATED));
|
s_nodes.insert(make_pair(nodep,FLAG_ALLOCATED));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static void setUnder(const AstNode* nodep, bool flag) {
|
||||||
|
// Called by BrokenCheckVisitor when each node entered/exited
|
||||||
|
if (!okIfLinkedTo(nodep)) return;
|
||||||
|
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||||
|
if (iter!=s_nodes.end()) {
|
||||||
|
iter->second &= ~FLAG_UNDER_NOW;
|
||||||
|
if (flag) iter->second |= FLAG_UNDER_NOW;
|
||||||
|
}
|
||||||
|
}
|
||||||
static void addInTree(AstNode* nodep, bool linkable) {
|
static void addInTree(AstNode* nodep, bool linkable) {
|
||||||
#ifndef VL_LEAK_CHECKS
|
#ifndef VL_LEAK_CHECKS
|
||||||
if (!linkable) return; // save some time, else the map will get huge!
|
if (!linkable) return; // save some time, else the map will get huge!
|
||||||
@@ -111,6 +121,14 @@ public:
|
|||||||
if (!(iter->second & FLAG_LINKABLE)) return false;
|
if (!(iter->second & FLAG_LINKABLE)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
static bool okIfBelow(const AstNode* nodep) {
|
||||||
|
// Must be linked to and below current node
|
||||||
|
if (!okIfLinkedTo(nodep)) return false;
|
||||||
|
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||||
|
if (iter == s_nodes.end()) return false;
|
||||||
|
if (!(iter->second & FLAG_UNDER_NOW)) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
static void prepForTree() {
|
static void prepForTree() {
|
||||||
#ifndef VL_LEAK_CHECKS
|
#ifndef VL_LEAK_CHECKS
|
||||||
s_nodes.clear();
|
s_nodes.clear();
|
||||||
@@ -152,6 +170,10 @@ bool AstNode::brokeExists() const {
|
|||||||
// Called by node->broken() routines to do table lookup
|
// Called by node->broken() routines to do table lookup
|
||||||
return BrokenTable::okIfLinkedTo(this);
|
return BrokenTable::okIfLinkedTo(this);
|
||||||
}
|
}
|
||||||
|
bool AstNode::brokeExistsAbove() const {
|
||||||
|
// Called by node->broken() routines to do table lookup
|
||||||
|
return BrokenTable::okIfBelow(this);
|
||||||
|
}
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|
||||||
@@ -180,6 +202,7 @@ public:
|
|||||||
class BrokenCheckVisitor : public AstNVisitor {
|
class BrokenCheckVisitor : public AstNVisitor {
|
||||||
private:
|
private:
|
||||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||||
|
BrokenTable::setUnder(nodep,true);
|
||||||
if (nodep->broken()) {
|
if (nodep->broken()) {
|
||||||
nodep->v3fatalSrc("Broken link in node (or something without maybePointedTo)\n");
|
nodep->v3fatalSrc("Broken link in node (or something without maybePointedTo)\n");
|
||||||
}
|
}
|
||||||
@@ -192,6 +215,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
|
BrokenTable::setUnder(nodep,false);
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
// CONSTUCTORS
|
// CONSTUCTORS
|
||||||
|
|||||||
@@ -642,6 +642,9 @@ private:
|
|||||||
virtual void visit(AstAlways* nodep, AstNUser*) {
|
virtual void visit(AstAlways* nodep, AstNUser*) {
|
||||||
iterateNewStmt(nodep);
|
iterateNewStmt(nodep);
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
|
||||||
|
// CDC doesn't care about public variables
|
||||||
|
}
|
||||||
virtual void visit(AstCFunc* nodep, AstNUser*) {
|
virtual void visit(AstCFunc* nodep, AstNUser*) {
|
||||||
iterateNewStmt(nodep);
|
iterateNewStmt(nodep);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -128,8 +128,7 @@ private:
|
|||||||
virtual void visit(AstVarScope* nodep, AstNUser*) {
|
virtual void visit(AstVarScope* nodep, AstNUser*) {
|
||||||
if (nodep->isCircular()) {
|
if (nodep->isCircular()) {
|
||||||
UINFO(8," CIRC "<<nodep<<endl);
|
UINFO(8," CIRC "<<nodep<<endl);
|
||||||
if (!nodep->user1()) {
|
if (!nodep->user1Inc()) {
|
||||||
nodep->user1(true);
|
|
||||||
genChangeDet(nodep);
|
genChangeDet(nodep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -704,8 +704,7 @@ class GaterVisitor : public GaterBaseVisitor {
|
|||||||
virtual void visit(AstAlways* nodep, AstNUser*) {
|
virtual void visit(AstAlways* nodep, AstNUser*) {
|
||||||
if (debug()>=9) cout<<endl<<endl<<endl;
|
if (debug()>=9) cout<<endl<<endl<<endl;
|
||||||
UINFO(5, "Gater: ALWAYS: "<<nodep<<endl);
|
UINFO(5, "Gater: ALWAYS: "<<nodep<<endl);
|
||||||
if (nodep->user4()) return;
|
if (nodep->user4Inc()) return;
|
||||||
nodep->user4(1);
|
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
|
|||||||
+27
-1
@@ -96,6 +96,7 @@ private:
|
|||||||
// ** only when m_warn/m_expensive is set. If state is needed other times,
|
// ** only when m_warn/m_expensive is set. If state is needed other times,
|
||||||
// ** must track down everywhere V3Const is called and make sure no overlaps.
|
// ** must track down everywhere V3Const is called and make sure no overlaps.
|
||||||
// AstVar::user4p -> Used by ConstVarMarkVisitor/ConstVarFindVisitor
|
// AstVar::user4p -> Used by ConstVarMarkVisitor/ConstVarFindVisitor
|
||||||
|
// AstJumpLabel::user4 -> bool. Set when AstJumpGo uses this label
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
bool m_params; // If true, propogate parameterized and true numbers only
|
bool m_params; // If true, propogate parameterized and true numbers only
|
||||||
@@ -1487,7 +1488,8 @@ private:
|
|||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (nodep->condp()->isZero()) {
|
if (nodep->condp()->isZero()) {
|
||||||
UINFO(4,"WHILE(0) => nop "<<nodep<<endl);
|
UINFO(4,"WHILE(0) => nop "<<nodep<<endl);
|
||||||
nodep->unlinkFrBack();
|
if (nodep->precondsp()) nodep->replaceWith(nodep->precondsp());
|
||||||
|
else nodep->unlinkFrBack();
|
||||||
nodep->deleteTree(); nodep=NULL;
|
nodep->deleteTree(); nodep=NULL;
|
||||||
}
|
}
|
||||||
else if (operandBoolShift(nodep->condp())) {
|
else if (operandBoolShift(nodep->condp())) {
|
||||||
@@ -1499,6 +1501,30 @@ private:
|
|||||||
// If output of a presel didn't get consted, chances are V3Param didn't visit properly
|
// If output of a presel didn't get consted, chances are V3Param didn't visit properly
|
||||||
virtual void visit(AstNodePreSel* nodep, AstNUser*) {}
|
virtual void visit(AstNodePreSel* nodep, AstNUser*) {}
|
||||||
|
|
||||||
|
//-----
|
||||||
|
// Jump elimination
|
||||||
|
|
||||||
|
virtual void visit(AstJumpGo* nodep, AstNUser*) {
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
if (m_expensive) { nodep->labelp()->user4(true); }
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(AstJumpLabel* nodep, AstNUser*) {
|
||||||
|
// Because JumpLabels disable many optimizations,
|
||||||
|
// remove JumpLabels that are not pointed to by any AstJumpGos
|
||||||
|
// Note this assumes all AstJumpGos are underneath the given label; V3Broken asserts this
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
// AstJumpGo's below here that point to this node will set user4
|
||||||
|
if (m_expensive && !nodep->user4()) {
|
||||||
|
UINFO(4,"JUMPLABEL => unused "<<nodep<<endl);
|
||||||
|
AstNode* underp = NULL;
|
||||||
|
if (nodep->stmtsp()) underp = nodep->stmtsp()->unlinkFrBackWithNext();
|
||||||
|
if (underp) nodep->replaceWith(underp);
|
||||||
|
else nodep->unlinkFrBack();
|
||||||
|
nodep->deleteTree(); nodep=NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//-----
|
//-----
|
||||||
// Below lines are magic expressions processed by astgen
|
// Below lines are magic expressions processed by astgen
|
||||||
// "AstNODETYPE { # bracket not paren
|
// "AstNODETYPE { # bracket not paren
|
||||||
|
|||||||
+8
-11
@@ -95,31 +95,31 @@ private:
|
|||||||
// VISITORS
|
// VISITORS
|
||||||
virtual void visit(AstCell* nodep, AstNUser*) {
|
virtual void visit(AstCell* nodep, AstNUser*) {
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
nodep->modp()->user1(nodep->modp()->user1() + 1);
|
nodep->modp()->user1Inc();
|
||||||
}
|
}
|
||||||
virtual void visit(AstNodeVarRef* nodep, AstNUser*) {
|
virtual void visit(AstNodeVarRef* nodep, AstNUser*) {
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (nodep->varScopep()) {
|
if (nodep->varScopep()) {
|
||||||
nodep->varScopep()->user1(nodep->varScopep()->user1() + 1);
|
nodep->varScopep()->user1Inc();
|
||||||
nodep->varScopep()->varp()->user1(nodep->varScopep()->varp()->user1() + 1);
|
nodep->varScopep()->varp()->user1Inc();
|
||||||
}
|
}
|
||||||
if (nodep->varp()) {
|
if (nodep->varp()) {
|
||||||
nodep->varp()->user1(nodep->varp()->user1() + 1);
|
nodep->varp()->user1Inc();
|
||||||
}
|
}
|
||||||
if (nodep->packagep()) {
|
if (nodep->packagep()) {
|
||||||
nodep->packagep()->user1(nodep->packagep()->user1() + 1);
|
nodep->packagep()->user1Inc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
|
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (nodep->packagep()) {
|
if (nodep->packagep()) {
|
||||||
nodep->packagep()->user1(nodep->packagep()->user1() + 1);
|
nodep->packagep()->user1Inc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstRefDType* nodep, AstNUser*) {
|
virtual void visit(AstRefDType* nodep, AstNUser*) {
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (nodep->packagep()) {
|
if (nodep->packagep()) {
|
||||||
nodep->packagep()->user1(nodep->packagep()->user1() + 1);
|
nodep->packagep()->user1Inc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstVarScope* nodep, AstNUser*) {
|
virtual void visit(AstVarScope* nodep, AstNUser*) {
|
||||||
@@ -145,13 +145,10 @@ private:
|
|||||||
nodep->lhsp()->iterateAndNext(*this);
|
nodep->lhsp()->iterateAndNext(*this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstUCFunc* nodep, AstNUser*) {
|
|
||||||
m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment
|
|
||||||
nodep->iterateChildren(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----
|
//-----
|
||||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||||
|
if (nodep->isOutputter()) m_sideEffect=true;
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+18
-5
@@ -149,6 +149,8 @@ public:
|
|||||||
if (decind) ofp()->blockDec();
|
if (decind) ofp()->blockDec();
|
||||||
if (!m_suppressSemi) puts(";\n");
|
if (!m_suppressSemi) puts(";\n");
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstAlwaysPublic*, AstNUser*) {
|
||||||
|
}
|
||||||
virtual void visit(AstCCall* nodep, AstNUser*) {
|
virtual void visit(AstCCall* nodep, AstNUser*) {
|
||||||
puts(nodep->hiername());
|
puts(nodep->hiername());
|
||||||
puts(nodep->funcp()->name());
|
puts(nodep->funcp()->name());
|
||||||
@@ -360,12 +362,22 @@ public:
|
|||||||
puts(")); }\n");
|
puts(")); }\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstJumpGo* nodep, AstNUser*) {
|
||||||
|
puts("goto __Vlabel"+cvtToStr(nodep->labelp()->labelNum())+";\n");
|
||||||
|
}
|
||||||
|
virtual void visit(AstJumpLabel* nodep, AstNUser*) {
|
||||||
|
puts("{\n");
|
||||||
|
nodep->stmtsp()->iterateAndNext(*this);
|
||||||
|
puts("}\n");
|
||||||
|
puts("__Vlabel"+cvtToStr(nodep->labelNum())+": ;\n");
|
||||||
|
}
|
||||||
virtual void visit(AstWhile* nodep, AstNUser*) {
|
virtual void visit(AstWhile* nodep, AstNUser*) {
|
||||||
nodep->precondsp()->iterateAndNext(*this);
|
nodep->precondsp()->iterateAndNext(*this);
|
||||||
puts("while (");
|
puts("while (");
|
||||||
nodep->condp()->iterateAndNext(*this);
|
nodep->condp()->iterateAndNext(*this);
|
||||||
puts(") {\n");
|
puts(") {\n");
|
||||||
nodep->bodysp()->iterateAndNext(*this);
|
nodep->bodysp()->iterateAndNext(*this);
|
||||||
|
nodep->incsp()->iterateAndNext(*this);
|
||||||
nodep->precondsp()->iterateAndNext(*this); // Need to recompute before next loop
|
nodep->precondsp()->iterateAndNext(*this); // Need to recompute before next loop
|
||||||
puts("}\n");
|
puts("}\n");
|
||||||
}
|
}
|
||||||
@@ -531,17 +543,18 @@ public:
|
|||||||
}
|
}
|
||||||
for (int word=VL_WORDS_I(nodep->num().minWidth())-1; word>0; word--) {
|
for (int word=VL_WORDS_I(nodep->num().minWidth())-1; word>0; word--) {
|
||||||
// Only 32 bits - llx + long long here just to appease CPP format warning
|
// Only 32 bits - llx + long long here just to appease CPP format warning
|
||||||
ofp()->printf(",0x%08" VL_PRI64 "x", (long long)(nodep->num().dataWord(word)));
|
ofp()->printf(",0x%08" VL_PRI64 "x", (vluint64_t)(nodep->num().dataWord(word)));
|
||||||
}
|
}
|
||||||
ofp()->printf(",0x%08" VL_PRI64 "x)", (long long)(nodep->num().dataWord(0)));
|
ofp()->printf(",0x%08" VL_PRI64 "x)", (vluint64_t)(nodep->num().dataWord(0)));
|
||||||
} else if (nodep->isQuad()) {
|
} else if (nodep->isQuad()) {
|
||||||
vluint64_t num = nodep->toUQuad();
|
vluint64_t num = nodep->toUQuad();
|
||||||
if (num<10) ofp()->printf("VL_ULL(%" VL_PRI64 "d)", (long long)num);
|
if (num<10) ofp()->printf("VL_ULL(%" VL_PRI64 "d)", num);
|
||||||
else ofp()->printf("VL_ULL(0x%" VL_PRI64 "x)", (long long)num);
|
else ofp()->printf("VL_ULL(0x%" VL_PRI64 "x)", num);
|
||||||
} else {
|
} else {
|
||||||
uint32_t num = nodep->toUInt();
|
uint32_t num = nodep->toUInt();
|
||||||
|
// Only 32 bits - llx + long long here just to appease CPP format warning
|
||||||
if (num<10) puts(cvtToStr(num));
|
if (num<10) puts(cvtToStr(num));
|
||||||
else ofp()->printf("0x%" VL_PRI64 "x", (long long)num);
|
else ofp()->printf("0x%" VL_PRI64 "x", (vluint64_t)num);
|
||||||
//Unneeded-Causes %lx format warnings:
|
//Unneeded-Causes %lx format warnings:
|
||||||
// if (!nodep->num().isSigned() && (num & (1UL<<31))) puts("U");
|
// if (!nodep->num().isSigned() && (num & (1UL<<31))) puts("U");
|
||||||
}
|
}
|
||||||
|
|||||||
+141
-6
@@ -45,13 +45,24 @@ class EmitCSyms : EmitCBaseVisitor {
|
|||||||
AstUser1InUse m_inuser1;
|
AstUser1InUse m_inuser1;
|
||||||
|
|
||||||
// TYPES
|
// TYPES
|
||||||
|
struct ScopeNameData { string m_symName; string m_prettyName;
|
||||||
|
ScopeNameData(const string& symName, const string& prettyName)
|
||||||
|
: m_symName(symName), m_prettyName(prettyName) {}
|
||||||
|
};
|
||||||
struct ScopeFuncData { AstScopeName* m_scopep; AstCFunc* m_funcp; AstNodeModule* m_modp;
|
struct ScopeFuncData { AstScopeName* m_scopep; AstCFunc* m_funcp; AstNodeModule* m_modp;
|
||||||
ScopeFuncData(AstScopeName* scopep, AstCFunc* funcp, AstNodeModule* modp)
|
ScopeFuncData(AstScopeName* scopep, AstCFunc* funcp, AstNodeModule* modp)
|
||||||
: m_scopep(scopep), m_funcp(funcp), m_modp(modp) {}
|
: m_scopep(scopep), m_funcp(funcp), m_modp(modp) {}
|
||||||
};
|
};
|
||||||
|
struct ScopeVarData { string m_scopeName; string m_varBasePretty; AstVar* m_varp;
|
||||||
|
AstNodeModule* m_modp; AstScope* m_scopep;
|
||||||
|
ScopeVarData(const string& scopeName, const string& varBasePretty, AstVar* varp, AstNodeModule* modp, AstScope* scopep)
|
||||||
|
: m_scopeName(scopeName), m_varBasePretty(varBasePretty), m_varp(varp), m_modp(modp), m_scopep(scopep) {}
|
||||||
|
};
|
||||||
typedef map<string,ScopeFuncData> ScopeFuncs;
|
typedef map<string,ScopeFuncData> ScopeFuncs;
|
||||||
typedef map<string,AstScopeName*> ScopeNames;
|
typedef map<string,ScopeVarData> ScopeVars;
|
||||||
|
typedef map<string,ScopeNameData> ScopeNames;
|
||||||
typedef pair<AstScope*,AstNodeModule*> ScopeModPair;
|
typedef pair<AstScope*,AstNodeModule*> ScopeModPair;
|
||||||
|
typedef pair<AstNodeModule*,AstVar*> ModVarPair;
|
||||||
struct CmpName {
|
struct CmpName {
|
||||||
inline bool operator () (const ScopeModPair& lhsp, const ScopeModPair& rhsp) const {
|
inline bool operator () (const ScopeModPair& lhsp, const ScopeModPair& rhsp) const {
|
||||||
return lhsp.first->name() < rhsp.first->name();
|
return lhsp.first->name() < rhsp.first->name();
|
||||||
@@ -71,10 +82,13 @@ class EmitCSyms : EmitCBaseVisitor {
|
|||||||
AstNodeModule* m_modp; // Current module
|
AstNodeModule* m_modp; // Current module
|
||||||
vector<ScopeModPair> m_scopes; // Every scope by module
|
vector<ScopeModPair> m_scopes; // Every scope by module
|
||||||
vector<AstCFunc*> m_dpis; // DPI functions
|
vector<AstCFunc*> m_dpis; // DPI functions
|
||||||
|
vector<ModVarPair> m_modVars; // Each public {mod,var}
|
||||||
ScopeNames m_scopeNames; // Each unique AstScopeName
|
ScopeNames m_scopeNames; // Each unique AstScopeName
|
||||||
ScopeFuncs m_scopeFuncs; // Each {scope,dpiexportfunc}
|
ScopeFuncs m_scopeFuncs; // Each {scope,dpi-export-func}
|
||||||
|
ScopeVars m_scopeVars; // Each {scope,public-var}
|
||||||
V3LanguageWords m_words; // Reserved word detector
|
V3LanguageWords m_words; // Reserved word detector
|
||||||
int m_coverBins; // Coverage bin number
|
int m_coverBins; // Coverage bin number
|
||||||
|
int m_labelNum; // Next label number
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
void emitSymHdr();
|
void emitSymHdr();
|
||||||
@@ -94,10 +108,65 @@ class EmitCSyms : EmitCBaseVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void varsExpand() {
|
||||||
|
// We didn'e have all m_scopes loaded when we encountered variables, so expand them now
|
||||||
|
// It would be less code if each module inserted its own variables.
|
||||||
|
// Someday. For now public isn't common.
|
||||||
|
for (vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
|
||||||
|
AstScope* scopep = it->first; AstNodeModule* smodp = it->second;
|
||||||
|
for (vector<ModVarPair>::iterator it = m_modVars.begin(); it != m_modVars.end(); ++it) {
|
||||||
|
AstNodeModule* modp = it->first;
|
||||||
|
if (modp == smodp) {
|
||||||
|
AstVar* varp = it->second;
|
||||||
|
// Need to split the module + var name into the original-ish full scope and variable name under that scope.
|
||||||
|
// The module instance name is included later, when we know the scopes this module is under
|
||||||
|
string whole = scopep->name()+"__DOT__"+varp->name();
|
||||||
|
string scpName;
|
||||||
|
string varBase;
|
||||||
|
if (whole.substr(0,10) == "__DOT__TOP") whole.replace(0,10,"");
|
||||||
|
string::size_type pos = whole.rfind("__DOT__");
|
||||||
|
if (pos != string::npos) {
|
||||||
|
scpName = whole.substr(0,pos);
|
||||||
|
varBase = whole.substr(pos+strlen("__DOT__"));
|
||||||
|
} else {
|
||||||
|
varBase = whole;
|
||||||
|
}
|
||||||
|
//UINFO(9,"For "<<scopep->name()<<" - "<<varp->name()<<" Scp "<<scpName<<" Var "<<varBase<<endl);
|
||||||
|
string varBasePretty = AstNode::prettyName(varBase);
|
||||||
|
string scpPretty = AstNode::prettyName(scpName);
|
||||||
|
string scpSym;
|
||||||
|
{
|
||||||
|
string out = scpName;
|
||||||
|
string::size_type pos;
|
||||||
|
while ((pos=out.find("__PVT__")) != string::npos) {
|
||||||
|
out.replace(pos, 7, "");
|
||||||
|
}
|
||||||
|
if (out.substr(0,10) == "TOP__DOT__") out.replace(0,10,"");
|
||||||
|
if (out.substr(0,4) == "TOP.") out.replace(0,4,"");
|
||||||
|
while ((pos=out.find(".")) != string::npos) {
|
||||||
|
out.replace(pos, 1, "__");
|
||||||
|
}
|
||||||
|
while ((pos=out.find("__DOT__")) != string::npos) {
|
||||||
|
out.replace(pos, 7, "__");
|
||||||
|
}
|
||||||
|
scpSym = out;
|
||||||
|
}
|
||||||
|
//UINFO(9," scnameins sp "<<scpName<<" sp "<<scpPretty<<" ss "<<scpSym<<endl);
|
||||||
|
if (m_scopeNames.find(scpSym) == m_scopeNames.end()) {
|
||||||
|
m_scopeNames.insert(make_pair(scpSym, ScopeNameData(scpSym, scpPretty)));
|
||||||
|
}
|
||||||
|
m_scopeVars.insert(make_pair(scpSym + " " + varp->name(),
|
||||||
|
ScopeVarData(scpSym, varBasePretty, varp, modp, scopep)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
virtual void visit(AstNetlist* nodep, AstNUser*) {
|
virtual void visit(AstNetlist* nodep, AstNUser*) {
|
||||||
// Collect list of scopes
|
// Collect list of scopes
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
|
varsExpand();
|
||||||
|
|
||||||
// Sort by names, so line/process order matters less
|
// Sort by names, so line/process order matters less
|
||||||
sort(m_scopes.begin(), m_scopes.end(), CmpName());
|
sort(m_scopes.begin(), m_scopes.end(), CmpName());
|
||||||
@@ -114,6 +183,7 @@ class EmitCSyms : EmitCBaseVisitor {
|
|||||||
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
||||||
nameCheck(nodep);
|
nameCheck(nodep);
|
||||||
m_modp = nodep;
|
m_modp = nodep;
|
||||||
|
m_labelNum = 0;
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
m_modp = NULL;
|
m_modp = NULL;
|
||||||
}
|
}
|
||||||
@@ -123,8 +193,9 @@ class EmitCSyms : EmitCBaseVisitor {
|
|||||||
}
|
}
|
||||||
virtual void visit(AstScopeName* nodep, AstNUser*) {
|
virtual void visit(AstScopeName* nodep, AstNUser*) {
|
||||||
string name = nodep->scopeSymName();
|
string name = nodep->scopeSymName();
|
||||||
|
//UINFO(9,"scnameins sp "<<nodep->name()<<" sp "<<nodep->scopePrettyName()<<" ss "<<name<<endl);
|
||||||
if (m_scopeNames.find(name) == m_scopeNames.end()) {
|
if (m_scopeNames.find(name) == m_scopeNames.end()) {
|
||||||
m_scopeNames.insert(make_pair(name, nodep));
|
m_scopeNames.insert(make_pair(name, ScopeNameData(name, nodep->scopePrettyName())));
|
||||||
}
|
}
|
||||||
if (nodep->dpiExport()) {
|
if (nodep->dpiExport()) {
|
||||||
if (!m_funcp) nodep->v3fatalSrc("ScopeName not under DPI function");
|
if (!m_funcp) nodep->v3fatalSrc("ScopeName not under DPI function");
|
||||||
@@ -132,12 +203,22 @@ class EmitCSyms : EmitCBaseVisitor {
|
|||||||
ScopeFuncData(nodep, m_funcp, m_modp)));
|
ScopeFuncData(nodep, m_funcp, m_modp)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstVar* nodep, AstNUser*) {
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
if (nodep->isSigUserRdPublic()) {
|
||||||
|
m_modVars.push_back(make_pair(m_modp, nodep));
|
||||||
|
}
|
||||||
|
}
|
||||||
virtual void visit(AstCoverDecl* nodep, AstNUser*) {
|
virtual void visit(AstCoverDecl* nodep, AstNUser*) {
|
||||||
// Assign numbers to all bins, so we know how big of an array to use
|
// Assign numbers to all bins, so we know how big of an array to use
|
||||||
if (!nodep->dataDeclNullp()) { // else duplicate we don't need code for
|
if (!nodep->dataDeclNullp()) { // else duplicate we don't need code for
|
||||||
nodep->binNum(m_coverBins++);
|
nodep->binNum(m_coverBins++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstJumpLabel* nodep, AstNUser*) {
|
||||||
|
nodep->labelNum(++m_labelNum);
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
}
|
||||||
virtual void visit(AstCFunc* nodep, AstNUser*) {
|
virtual void visit(AstCFunc* nodep, AstNUser*) {
|
||||||
if (nodep->dpiImport() || nodep->dpiExportWrapper()) {
|
if (nodep->dpiImport() || nodep->dpiExportWrapper()) {
|
||||||
m_dpis.push_back(nodep);
|
m_dpis.push_back(nodep);
|
||||||
@@ -160,6 +241,7 @@ public:
|
|||||||
m_funcp = NULL;
|
m_funcp = NULL;
|
||||||
m_modp = NULL;
|
m_modp = NULL;
|
||||||
m_coverBins = 0;
|
m_coverBins = 0;
|
||||||
|
m_labelNum = 0;
|
||||||
nodep->accept(*this);
|
nodep->accept(*this);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -248,7 +330,7 @@ void EmitCSyms::emitSymHdr() {
|
|||||||
|
|
||||||
puts("\n// SCOPE NAMES\n");
|
puts("\n// SCOPE NAMES\n");
|
||||||
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
|
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
|
||||||
puts("VerilatedScope __Vscope_"+it->second->scopeSymName()+";\n");
|
puts("VerilatedScope __Vscope_"+it->second.m_symName+";\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
puts("\n// CREATORS\n");
|
puts("\n// CREATORS\n");
|
||||||
@@ -338,8 +420,8 @@ void EmitCSyms::emitSymImp() {
|
|||||||
|
|
||||||
puts("// Setup scope names\n");
|
puts("// Setup scope names\n");
|
||||||
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
|
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
|
||||||
puts("__Vscope_"+it->second->scopeSymName()+".configure(this,name(),");
|
puts("__Vscope_"+it->second.m_symName+".configure(this,name(),");
|
||||||
putsQuoted(it->second->scopePrettyName());
|
putsQuoted(it->second.m_prettyName);
|
||||||
puts(");\n");
|
puts(");\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,6 +442,59 @@ void EmitCSyms::emitSymImp() {
|
|||||||
puts("));\n");
|
puts("));\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// It would be less code if each module inserted its own variables.
|
||||||
|
// Someday. For now public isn't common.
|
||||||
|
for (ScopeVars::iterator it = m_scopeVars.begin(); it != m_scopeVars.end(); ++it) {
|
||||||
|
AstNodeModule* modp = it->second.m_modp;
|
||||||
|
AstScope* scopep = it->second.m_scopep;
|
||||||
|
AstVar* varp = it->second.m_varp;
|
||||||
|
//
|
||||||
|
int dim=0;
|
||||||
|
string bounds;
|
||||||
|
if (AstBasicDType* basicp = varp->basicp()) {
|
||||||
|
// Range is always first, it's not in "C" order
|
||||||
|
if (basicp->rangep()) {
|
||||||
|
bounds += " ,"; bounds += cvtToStr(basicp->rangep()->msbConst());
|
||||||
|
bounds += ","; bounds += cvtToStr(basicp->rangep()->lsbConst());
|
||||||
|
dim++;
|
||||||
|
}
|
||||||
|
for (AstNodeDType* dtypep=varp->dtypep(); dtypep; ) {
|
||||||
|
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
||||||
|
if (AstArrayDType* adtypep = dtypep->castArrayDType()) {
|
||||||
|
bounds += " ,"; bounds += cvtToStr(adtypep->arrayp()->msbConst());
|
||||||
|
bounds += ","; bounds += cvtToStr(adtypep->arrayp()->lsbConst());
|
||||||
|
dim++;
|
||||||
|
dtypep = adtypep->dtypep();
|
||||||
|
}
|
||||||
|
else break; // AstBasicDType - nothing below, 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
if (dim>2) {
|
||||||
|
puts("//UNSUP "); // VerilatedImp can't deal with >2d arrays
|
||||||
|
}
|
||||||
|
puts("__Vscope_"+it->second.m_scopeName+".varInsert(__Vfinal,");
|
||||||
|
putsQuoted(it->second.m_varBasePretty);
|
||||||
|
puts(", &(");
|
||||||
|
if (modp->isTop()) {
|
||||||
|
puts(scopep->nameDotless());
|
||||||
|
puts("p->");
|
||||||
|
} else {
|
||||||
|
puts(scopep->nameDotless());
|
||||||
|
puts(".");
|
||||||
|
}
|
||||||
|
puts(varp->name());
|
||||||
|
puts("), ");
|
||||||
|
puts(varp->vlEnumType()); // VLVT_UINT32 etc
|
||||||
|
puts(",");
|
||||||
|
puts(varp->vlEnumDir()); // VLVD_IN etc
|
||||||
|
if (varp->isSigUserRWPublic()) puts("|VLVF_PUB_RW");
|
||||||
|
else if (varp->isSigUserRdPublic()) puts("|VLVF_PUB_RD");
|
||||||
|
puts(",");
|
||||||
|
puts(cvtToStr(dim));
|
||||||
|
puts(bounds);
|
||||||
|
puts(");\n");
|
||||||
|
}
|
||||||
puts("}\n");
|
puts("}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -109,6 +109,14 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||||||
nodep->bodysp()->iterateAndNext(*this);
|
nodep->bodysp()->iterateAndNext(*this);
|
||||||
putqs(nodep,"end\n");
|
putqs(nodep,"end\n");
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
|
||||||
|
putfs(nodep,"/*verilator public_flat_rw ");
|
||||||
|
if (m_sensesp) m_sensesp->iterateAndNext(*this); // In active
|
||||||
|
else nodep->sensesp()->iterateAndNext(*this);
|
||||||
|
putqs(nodep," ");
|
||||||
|
nodep->bodysp()->iterateAndNext(*this);
|
||||||
|
putqs(nodep,"*/\n");
|
||||||
|
}
|
||||||
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
||||||
nodep->lhsp()->iterateAndNext(*this);
|
nodep->lhsp()->iterateAndNext(*this);
|
||||||
putfs(nodep," "+nodep->verilogKwd()+" ");
|
putfs(nodep," "+nodep->verilogKwd()+" ");
|
||||||
@@ -135,6 +143,10 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||||||
nodep->rhsp()->iterateAndNext(*this);
|
nodep->rhsp()->iterateAndNext(*this);
|
||||||
if (!m_suppressSemi) puts(";\n");
|
if (!m_suppressSemi) puts(";\n");
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstBreak* nodep, AstNUser*) {
|
||||||
|
putbs("break");
|
||||||
|
if (!m_suppressSemi) puts(";\n");
|
||||||
|
}
|
||||||
virtual void visit(AstSenTree* nodep, AstNUser*) {
|
virtual void visit(AstSenTree* nodep, AstNUser*) {
|
||||||
// AstSenItem is called for dumping in isolation by V3Order
|
// AstSenItem is called for dumping in isolation by V3Order
|
||||||
putfs(nodep,"@(");
|
putfs(nodep,"@(");
|
||||||
@@ -180,6 +192,10 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||||||
puts((string)"// "+nodep->name()+"\n");
|
puts((string)"// "+nodep->name()+"\n");
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstContinue* nodep, AstNUser*) {
|
||||||
|
putbs("continue");
|
||||||
|
if (!m_suppressSemi) puts(";\n");
|
||||||
|
}
|
||||||
virtual void visit(AstCoverDecl*, AstNUser*) {} // N/A
|
virtual void visit(AstCoverDecl*, AstNUser*) {} // N/A
|
||||||
virtual void visit(AstCoverInc*, AstNUser*) {} // N/A
|
virtual void visit(AstCoverInc*, AstNUser*) {} // N/A
|
||||||
virtual void visit(AstCoverToggle*, AstNUser*) {} // N/A
|
virtual void visit(AstCoverToggle*, AstNUser*) {} // N/A
|
||||||
@@ -236,6 +252,14 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||||||
if (nodep->filep()) nodep->filep()->iterateChildren(*this);
|
if (nodep->filep()) nodep->filep()->iterateChildren(*this);
|
||||||
puts(");\n");
|
puts(");\n");
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstJumpGo* nodep, AstNUser*) {
|
||||||
|
putbs("disable "+cvtToStr((void*)(nodep->labelp()))+";\n");
|
||||||
|
}
|
||||||
|
virtual void visit(AstJumpLabel* nodep, AstNUser*) {
|
||||||
|
putbs("begin : "+cvtToStr((void*)(nodep))+"\n");
|
||||||
|
if (nodep->stmtsp()) nodep->stmtsp()->iterateChildren(*this);
|
||||||
|
puts("end\n");
|
||||||
|
}
|
||||||
virtual void visit(AstReadMem* nodep, AstNUser*) {
|
virtual void visit(AstReadMem* nodep, AstNUser*) {
|
||||||
putfs(nodep,nodep->verilogKwd());
|
putfs(nodep,nodep->verilogKwd());
|
||||||
putbs(" (");
|
putbs(" (");
|
||||||
@@ -272,6 +296,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||||||
nodep->condp()->iterateAndNext(*this);
|
nodep->condp()->iterateAndNext(*this);
|
||||||
puts(") begin\n");
|
puts(") begin\n");
|
||||||
nodep->bodysp()->iterateAndNext(*this);
|
nodep->bodysp()->iterateAndNext(*this);
|
||||||
|
nodep->incsp()->iterateAndNext(*this);
|
||||||
nodep->precondsp()->iterateAndNext(*this); // Need to recompute before next loop
|
nodep->precondsp()->iterateAndNext(*this); // Need to recompute before next loop
|
||||||
putfs(nodep,"end\n");
|
putfs(nodep,"end\n");
|
||||||
}
|
}
|
||||||
@@ -287,6 +312,11 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||||||
}
|
}
|
||||||
putqs(nodep,"end\n");
|
putqs(nodep,"end\n");
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstReturn* nodep, AstNUser*) {
|
||||||
|
putfs(nodep,"return ");
|
||||||
|
nodep->lhsp()->iterateAndNext(*this);
|
||||||
|
puts(";\n");
|
||||||
|
}
|
||||||
virtual void visit(AstStop* nodep, AstNUser*) {
|
virtual void visit(AstStop* nodep, AstNUser*) {
|
||||||
putfs(nodep,"$stop;\n");
|
putfs(nodep,"$stop;\n");
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-1
@@ -79,7 +79,13 @@ FileLine::FileLine(FileLine::EmptySecret) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileLine::lineDirective(const char* textp) {
|
string FileLine::lineDirectiveStrg(int enterExit) const {
|
||||||
|
char numbuf[20]; sprintf(numbuf, "%d", lineno());
|
||||||
|
char levelbuf[20]; sprintf(levelbuf, "%d", enterExit);
|
||||||
|
return ((string)"`line "+numbuf+" \""+filename()+"\" "+levelbuf+"\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileLine::lineDirective(const char* textp, int& enterExitRef) {
|
||||||
// Handle `line directive
|
// Handle `line directive
|
||||||
// Skip `line
|
// Skip `line
|
||||||
while (*textp && isspace(*textp)) textp++;
|
while (*textp && isspace(*textp)) textp++;
|
||||||
@@ -102,6 +108,12 @@ void FileLine::lineDirective(const char* textp) {
|
|||||||
strfn = strfn.substr(0, textp-fn);
|
strfn = strfn.substr(0, textp-fn);
|
||||||
this->filename(strfn);
|
this->filename(strfn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Grab level
|
||||||
|
while (*textp && (isspace(*textp) || *textp=='"')) textp++;
|
||||||
|
if (isdigit(*textp)) enterExitRef = atoi(textp);
|
||||||
|
else enterExitRef = 0;
|
||||||
|
|
||||||
//printf ("PPLINE %d '%s'\n", s_lineno, s_filename.c_str());
|
//printf ("PPLINE %d '%s'\n", s_lineno, s_filename.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-3
@@ -44,6 +44,7 @@ public:
|
|||||||
// Boolean information we track per-line, but aren't errors
|
// Boolean information we track per-line, but aren't errors
|
||||||
I_COVERAGE, // Coverage is on/off from /*verilator coverage_on/off*/
|
I_COVERAGE, // Coverage is on/off from /*verilator coverage_on/off*/
|
||||||
I_TRACING, // Tracing is on/off from /*verilator tracing_on/off*/
|
I_TRACING, // Tracing is on/off from /*verilator tracing_on/off*/
|
||||||
|
I_DEF_NETTYPE_WIRE, // `default_nettype is WIRE (false=NONE)
|
||||||
// Error codes:
|
// Error codes:
|
||||||
E_MULTITOP, // Error: Multiple top level modules
|
E_MULTITOP, // Error: Multiple top level modules
|
||||||
E_TASKNSVAR, // Error: Task I/O not simple
|
E_TASKNSVAR, // Error: Task I/O not simple
|
||||||
@@ -91,7 +92,7 @@ public:
|
|||||||
// Leading spaces indicate it can't be disabled.
|
// Leading spaces indicate it can't be disabled.
|
||||||
" MIN", " SUPPRESS", " INFO", " FATAL", " FATALSRC", " ERROR",
|
" MIN", " SUPPRESS", " INFO", " FATAL", " FATALSRC", " ERROR",
|
||||||
// Boolean
|
// Boolean
|
||||||
" I_COVERAGE", " I_TRACING",
|
" I_COVERAGE", " I_TRACING", " I_DEF_NETTYPE_WIRE",
|
||||||
// Errors
|
// Errors
|
||||||
"MULTITOP", "TASKNSVAR", "BLKLOOPINIT",
|
"MULTITOP", "TASKNSVAR", "BLKLOOPINIT",
|
||||||
// Warnings
|
// Warnings
|
||||||
@@ -233,26 +234,32 @@ protected:
|
|||||||
// We are storing pointers, so we CAN'T change them after initial reading.
|
// We are storing pointers, so we CAN'T change them after initial reading.
|
||||||
friend class V3ParseImp;
|
friend class V3ParseImp;
|
||||||
friend class V3PreLex;
|
friend class V3PreLex;
|
||||||
|
friend class V3PreProcImp;
|
||||||
void lineno(int num) { m_lineno = num; }
|
void lineno(int num) { m_lineno = num; }
|
||||||
void filename(const string& name) { m_filename = name; }
|
void filename(const string& name) { m_filename = name; }
|
||||||
void lineDirective(const char* textp);
|
void lineDirective(const char* textp, int& enterExitRef);
|
||||||
void incLineno() { m_lineno++; }
|
void linenoInc() { m_lineno++; }
|
||||||
|
void linenoIncInPlace() { m_lineno++; }
|
||||||
FileLine* copyOrSameFileLine();
|
FileLine* copyOrSameFileLine();
|
||||||
public:
|
public:
|
||||||
FileLine (const string& filename, int lineno) { m_lineno=lineno; m_filename = filename; m_warnOn=s_defaultFileLine.m_warnOn; }
|
FileLine (const string& filename, int lineno) { m_lineno=lineno; m_filename = filename; m_warnOn=s_defaultFileLine.m_warnOn; }
|
||||||
FileLine (FileLine* fromp) { m_lineno=fromp->lineno(); m_filename = fromp->filename(); m_warnOn=fromp->m_warnOn; }
|
FileLine (FileLine* fromp) { m_lineno=fromp->lineno(); m_filename = fromp->filename(); m_warnOn=fromp->m_warnOn; }
|
||||||
FileLine (EmptySecret);
|
FileLine (EmptySecret);
|
||||||
~FileLine() { }
|
~FileLine() { }
|
||||||
|
FileLine* create(const string& filename, int lineno) { return new FileLine(filename,lineno); }
|
||||||
|
FileLine* create(int lineno) { return create(filename(), lineno); }
|
||||||
static void deleteAllRemaining();
|
static void deleteAllRemaining();
|
||||||
#ifdef VL_LEAK_CHECKS
|
#ifdef VL_LEAK_CHECKS
|
||||||
static void* operator new(size_t size);
|
static void* operator new(size_t size);
|
||||||
static void operator delete(void* obj, size_t size);
|
static void operator delete(void* obj, size_t size);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int lineno () const { return m_lineno; }
|
int lineno () const { return m_lineno; }
|
||||||
string ascii() const;
|
string ascii() const;
|
||||||
const string filename () const { return m_filename; }
|
const string filename () const { return m_filename; }
|
||||||
const string filebasename () const;
|
const string filebasename () const;
|
||||||
const string profileFuncname() const;
|
const string profileFuncname() const;
|
||||||
|
string lineDirectiveStrg(int enter_exit_level) const;
|
||||||
void warnOn(V3ErrorCode code, bool flag) { m_warnOn.set(code,flag); } // Turn on/off warning messages on this line.
|
void warnOn(V3ErrorCode code, bool flag) { m_warnOn.set(code,flag); } // Turn on/off warning messages on this line.
|
||||||
void warnOff(V3ErrorCode code, bool flag) { warnOn(code,!flag); }
|
void warnOff(V3ErrorCode code, bool flag) { warnOn(code,!flag); }
|
||||||
bool warnOff(const string& code, bool flag); // Returns 1 if ok
|
bool warnOff(const string& code, bool flag); // Returns 1 if ok
|
||||||
|
|||||||
@@ -47,6 +47,8 @@
|
|||||||
class ExpandVisitor : public AstNVisitor {
|
class ExpandVisitor : public AstNVisitor {
|
||||||
private:
|
private:
|
||||||
// NODE STATE
|
// NODE STATE
|
||||||
|
// AstNode::user1() -> bool. Processed
|
||||||
|
AstUser1InUse m_inuser1;
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
AstNode* m_stmtp; // Current statement
|
AstNode* m_stmtp; // Current statement
|
||||||
@@ -76,12 +78,14 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void insertBefore (AstNode* placep, AstNode* newp) {
|
void insertBefore (AstNode* placep, AstNode* newp) {
|
||||||
|
newp->user1(1); // Already processed, don't need to re-iterate
|
||||||
AstNRelinker linker;
|
AstNRelinker linker;
|
||||||
placep->unlinkFrBack(&linker);
|
placep->unlinkFrBack(&linker);
|
||||||
newp->addNext(placep);
|
newp->addNext(placep);
|
||||||
linker.relink(newp);
|
linker.relink(newp);
|
||||||
}
|
}
|
||||||
void replaceWithDelete (AstNode* nodep, AstNode* newp) {
|
void replaceWithDelete (AstNode* nodep, AstNode* newp) {
|
||||||
|
newp->user1(1); // Already processed, don't need to re-iterate
|
||||||
nodep->replaceWith(newp);
|
nodep->replaceWith(newp);
|
||||||
nodep->deleteTree(); nodep=NULL;
|
nodep->deleteTree(); nodep=NULL;
|
||||||
}
|
}
|
||||||
@@ -306,6 +310,7 @@ private:
|
|||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
virtual void visit(AstExtend* nodep, AstNUser*) {
|
virtual void visit(AstExtend* nodep, AstNUser*) {
|
||||||
|
if (nodep->user1Inc()) return; // Process once
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (nodep->isWide()) {
|
if (nodep->isWide()) {
|
||||||
// See under ASSIGN(EXTEND)
|
// See under ASSIGN(EXTEND)
|
||||||
@@ -344,6 +349,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void visit(AstSel* nodep, AstNUser*) {
|
virtual void visit(AstSel* nodep, AstNUser*) {
|
||||||
|
if (nodep->user1Inc()) return; // Process once
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
// Remember, Sel's may have non-integer rhs, so need to optimize for that!
|
// Remember, Sel's may have non-integer rhs, so need to optimize for that!
|
||||||
if (nodep->widthMin()!=(int)nodep->widthConst()) nodep->v3fatalSrc("Width mismatch");
|
if (nodep->widthMin()!=(int)nodep->widthConst()) nodep->v3fatalSrc("Width mismatch");
|
||||||
@@ -640,6 +646,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void visit(AstConcat* nodep, AstNUser*) {
|
virtual void visit(AstConcat* nodep, AstNUser*) {
|
||||||
|
if (nodep->user1Inc()) return; // Process once
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (nodep->isWide()) {
|
if (nodep->isWide()) {
|
||||||
// See under ASSIGN(WIDE)
|
// See under ASSIGN(WIDE)
|
||||||
@@ -679,6 +686,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void visit(AstReplicate* nodep, AstNUser*) {
|
virtual void visit(AstReplicate* nodep, AstNUser*) {
|
||||||
|
if (nodep->user1Inc()) return; // Process once
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (nodep->isWide()) {
|
if (nodep->isWide()) {
|
||||||
// See under ASSIGN(WIDE)
|
// See under ASSIGN(WIDE)
|
||||||
@@ -740,6 +748,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void visit(AstChangeXor* nodep, AstNUser*) {
|
virtual void visit(AstChangeXor* nodep, AstNUser*) {
|
||||||
|
if (nodep->user1Inc()) return; // Process once
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
UINFO(8," Wordize ChangeXor "<<nodep<<endl);
|
UINFO(8," Wordize ChangeXor "<<nodep<<endl);
|
||||||
// -> (0=={or{for each_word{WORDSEL(lhs,#)^WORDSEL(rhs,#)}}}
|
// -> (0=={or{for each_word{WORDSEL(lhs,#)^WORDSEL(rhs,#)}}}
|
||||||
@@ -754,6 +763,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void visitEqNeq(AstNodeBiop* nodep) {
|
void visitEqNeq(AstNodeBiop* nodep) {
|
||||||
|
if (nodep->user1Inc()) return; // Process once
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (nodep->lhsp()->isWide()) {
|
if (nodep->lhsp()->isWide()) {
|
||||||
UINFO(8," Wordize EQ/NEQ "<<nodep<<endl);
|
UINFO(8," Wordize EQ/NEQ "<<nodep<<endl);
|
||||||
@@ -779,6 +789,7 @@ private:
|
|||||||
virtual void visit(AstNeq* nodep, AstNUser*) { visitEqNeq (nodep); }
|
virtual void visit(AstNeq* nodep, AstNUser*) { visitEqNeq (nodep); }
|
||||||
|
|
||||||
virtual void visit(AstRedOr* nodep, AstNUser*) {
|
virtual void visit(AstRedOr* nodep, AstNUser*) {
|
||||||
|
if (nodep->user1Inc()) return; // Process once
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (nodep->lhsp()->isWide()) {
|
if (nodep->lhsp()->isWide()) {
|
||||||
UINFO(8," Wordize REDOR "<<nodep<<endl);
|
UINFO(8," Wordize REDOR "<<nodep<<endl);
|
||||||
@@ -802,6 +813,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstRedAnd* nodep, AstNUser*) {
|
virtual void visit(AstRedAnd* nodep, AstNUser*) {
|
||||||
|
if (nodep->user1Inc()) return; // Process once
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (nodep->lhsp()->isWide()) {
|
if (nodep->lhsp()->isWide()) {
|
||||||
UINFO(8," Wordize REDAND "<<nodep<<endl);
|
UINFO(8," Wordize REDAND "<<nodep<<endl);
|
||||||
@@ -830,6 +842,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstRedXor* nodep, AstNUser*) {
|
virtual void visit(AstRedXor* nodep, AstNUser*) {
|
||||||
|
if (nodep->user1Inc()) return; // Process once
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (nodep->lhsp()->isWide()) {
|
if (nodep->lhsp()->isWide()) {
|
||||||
UINFO(8," Wordize REDXOR "<<nodep<<endl);
|
UINFO(8," Wordize REDXOR "<<nodep<<endl);
|
||||||
@@ -840,6 +853,7 @@ private:
|
|||||||
newp = (newp==NULL) ? eqp : (new AstXor (nodep->fileline(), newp, eqp));
|
newp = (newp==NULL) ? eqp : (new AstXor (nodep->fileline(), newp, eqp));
|
||||||
}
|
}
|
||||||
newp = new AstRedXor (nodep->fileline(), newp);
|
newp = new AstRedXor (nodep->fileline(), newp);
|
||||||
|
UINFO(8," Wordize REDXORnew "<<newp<<endl);
|
||||||
replaceWithDelete(nodep, newp); nodep=NULL;
|
replaceWithDelete(nodep, newp); nodep=NULL;
|
||||||
}
|
}
|
||||||
// We don't reduce non-wide XORs, as its more efficient to use a temp register,
|
// We don't reduce non-wide XORs, as its more efficient to use a temp register,
|
||||||
@@ -847,11 +861,13 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void visit(AstNodeStmt* nodep, AstNUser*) {
|
virtual void visit(AstNodeStmt* nodep, AstNUser*) {
|
||||||
|
if (nodep->user1Inc()) return; // Process once
|
||||||
m_stmtp = nodep;
|
m_stmtp = nodep;
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
m_stmtp = NULL;
|
m_stmtp = NULL;
|
||||||
}
|
}
|
||||||
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
||||||
|
if (nodep->user1Inc()) return; // Process once
|
||||||
m_stmtp = nodep;
|
m_stmtp = nodep;
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
bool did = false;
|
bool did = false;
|
||||||
|
|||||||
+47
-24
@@ -44,6 +44,8 @@
|
|||||||
#include "V3PreShell.h"
|
#include "V3PreShell.h"
|
||||||
#include "V3Ast.h"
|
#include "V3Ast.h"
|
||||||
|
|
||||||
|
// If change this code, run a test with the below size set very small
|
||||||
|
//#define INFILTER_IPC_BUFSIZ 16
|
||||||
#define INFILTER_IPC_BUFSIZ 64*1024 // For debug, try this as a small number
|
#define INFILTER_IPC_BUFSIZ 64*1024 // For debug, try this as a small number
|
||||||
#define INFILTER_CACHE_MAX 64*1024 // Maximum bytes to cache if same file read twice
|
#define INFILTER_CACHE_MAX 64*1024 // Maximum bytes to cache if same file read twice
|
||||||
|
|
||||||
@@ -271,6 +273,7 @@ void V3File::createMakeDir() {
|
|||||||
|
|
||||||
class V3InFilterImp {
|
class V3InFilterImp {
|
||||||
typedef map<string,string> FileContentsMap;
|
typedef map<string,string> FileContentsMap;
|
||||||
|
typedef V3InFilter::StrList StrList;
|
||||||
|
|
||||||
FileContentsMap m_contentsMap; // Cache of file contents
|
FileContentsMap m_contentsMap; // Cache of file contents
|
||||||
bool m_readEof; // Received EOF on read
|
bool m_readEof; // Received EOF on read
|
||||||
@@ -292,27 +295,27 @@ private:
|
|||||||
return level;
|
return level;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool readContents(const string& filename, string& out) {
|
bool readContents(const string& filename, StrList& outl) {
|
||||||
if (m_pid) return readContentsFilter(filename,out);
|
if (m_pid) return readContentsFilter(filename,outl);
|
||||||
else return readContentsFile(filename,out);
|
else return readContentsFile(filename,outl);
|
||||||
}
|
}
|
||||||
bool readContentsFile(const string& filename, string& out) {
|
bool readContentsFile(const string& filename, StrList& outl) {
|
||||||
int fd = open (filename.c_str(), O_RDONLY);
|
int fd = open (filename.c_str(), O_RDONLY);
|
||||||
if (!fd) return false;
|
if (!fd) return false;
|
||||||
m_readEof = false;
|
m_readEof = false;
|
||||||
out = readBlocks(fd, -1);
|
readBlocks(fd, -1, outl);
|
||||||
close(fd);
|
close(fd);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool readContentsFilter(const string& filename, string& out) {
|
bool readContentsFilter(const string& filename, StrList& outl) {
|
||||||
if (filename!="" || out!="") {} // Prevent unused
|
if (filename!="" || outl.empty()) {} // Prevent unused
|
||||||
#ifdef INFILTER_PIPE
|
#ifdef INFILTER_PIPE
|
||||||
writeFilter("read \""+filename+"\"\n");
|
writeFilter("read \""+filename+"\"\n");
|
||||||
string line = readFilterLine();
|
string line = readFilterLine();
|
||||||
if (line.find("Content-Length") != string::npos) {
|
if (line.find("Content-Length") != string::npos) {
|
||||||
int len = 0;
|
int len = 0;
|
||||||
sscanf(line.c_str(), "Content-Length: %d\n", &len);
|
sscanf(line.c_str(), "Content-Length: %d\n", &len);
|
||||||
out = readBlocks(m_readFd, len);
|
readBlocks(m_readFd, len, outl);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if (line!="") v3error("--pipe-filter protocol error, unexpected: "<<line);
|
if (line!="") v3error("--pipe-filter protocol error, unexpected: "<<line);
|
||||||
@@ -334,15 +337,19 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
string readBlocks(int fd, int size=-1) {
|
string readBlocks(int fd, int size, StrList& outl) {
|
||||||
string out;
|
string out;
|
||||||
char buf[INFILTER_IPC_BUFSIZ];
|
char buf[INFILTER_IPC_BUFSIZ];
|
||||||
while (!m_readEof && (size<0 || size>(int)out.length())) {
|
ssize_t sizegot = 0;
|
||||||
int todo = INFILTER_IPC_BUFSIZ;
|
while (!m_readEof && (size<0 || size>sizegot)) {
|
||||||
if (size>0 && size<INFILTER_IPC_BUFSIZ) todo = size;
|
ssize_t todo = INFILTER_IPC_BUFSIZ;
|
||||||
int got = read (fd, buf, todo);
|
if (size>0 && size<todo) todo = size;
|
||||||
|
ssize_t got = read (fd, buf, todo);
|
||||||
//UINFO(9,"RD GOT g "<< got<<" e "<<errno<<" "<<strerror(errno)<<endl); usleep(50*1000);
|
//UINFO(9,"RD GOT g "<< got<<" e "<<errno<<" "<<strerror(errno)<<endl); usleep(50*1000);
|
||||||
if (got>0) out.append(buf, got);
|
if (got>0) {
|
||||||
|
outl.push_back(string(buf, got));
|
||||||
|
sizegot += got;
|
||||||
|
}
|
||||||
else if (errno == EINTR || errno == EAGAIN
|
else if (errno == EINTR || errno == EAGAIN
|
||||||
#ifdef EWOULDBLOCK
|
#ifdef EWOULDBLOCK
|
||||||
|| errno == EWOULDBLOCK
|
|| errno == EWOULDBLOCK
|
||||||
@@ -358,9 +365,11 @@ private:
|
|||||||
UINFO(9,"readFilterLine\n");
|
UINFO(9,"readFilterLine\n");
|
||||||
string line;
|
string line;
|
||||||
while (!m_readEof) {
|
while (!m_readEof) {
|
||||||
string c = readBlocks(m_readFd, 1);
|
StrList outl;
|
||||||
line += c;
|
readBlocks(m_readFd, 1, outl);
|
||||||
if (c == "\n") {
|
string onechar = listString(outl);
|
||||||
|
line += onechar;
|
||||||
|
if (onechar == "\n") {
|
||||||
if (line == "\n") { line=""; continue; }
|
if (line == "\n") { line=""; continue; }
|
||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
@@ -477,21 +486,35 @@ private:
|
|||||||
protected:
|
protected:
|
||||||
friend class V3InFilter;
|
friend class V3InFilter;
|
||||||
// Read file contents and return it
|
// Read file contents and return it
|
||||||
bool readWholefile(const string& filename, string& out) {
|
bool readWholefile(const string& filename, StrList& outl) {
|
||||||
FileContentsMap::iterator it = m_contentsMap.find(filename);
|
FileContentsMap::iterator it = m_contentsMap.find(filename);
|
||||||
if (it != m_contentsMap.end()) {
|
if (it != m_contentsMap.end()) {
|
||||||
out = it->second;
|
outl.push_back(it->second);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!readContents(filename, out)) return false;
|
if (!readContents(filename, outl)) return false;
|
||||||
if (out.length() < INFILTER_CACHE_MAX) {
|
if (listSize(outl) < INFILTER_CACHE_MAX) {
|
||||||
// Cache small files (only to save space)
|
// Cache small files (only to save space)
|
||||||
// It's quite common to `include "timescale" thousands of times
|
// It's quite common to `include "timescale" thousands of times
|
||||||
// This isn't so important if it's just a open(), but filtering can be slow
|
// This isn't so important if it's just a open(), but filtering can be slow
|
||||||
m_contentsMap.insert(make_pair(filename,out));
|
m_contentsMap.insert(make_pair(filename,listString(outl)));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
size_t listSize(StrList& sl) {
|
||||||
|
size_t out = 0;
|
||||||
|
for (StrList::iterator it=sl.begin(); it!=sl.end(); ++it) {
|
||||||
|
out += it->length();
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
string listString(StrList& sl) {
|
||||||
|
string out;
|
||||||
|
for (StrList::iterator it=sl.begin(); it!=sl.end(); ++it) {
|
||||||
|
out += *it;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
V3InFilterImp(const string& command) {
|
V3InFilterImp(const string& command) {
|
||||||
m_readEof = false;
|
m_readEof = false;
|
||||||
@@ -512,9 +535,9 @@ protected:
|
|||||||
V3InFilter::V3InFilter(const string& command) { m_impp = new V3InFilterImp(command); }
|
V3InFilter::V3InFilter(const string& command) { m_impp = new V3InFilterImp(command); }
|
||||||
V3InFilter::~V3InFilter() { if (m_impp) delete m_impp; m_impp=NULL; }
|
V3InFilter::~V3InFilter() { if (m_impp) delete m_impp; m_impp=NULL; }
|
||||||
|
|
||||||
bool V3InFilter::readWholefile(const string& filename, string& out) {
|
bool V3InFilter::readWholefile(const string& filename, V3InFilter::StrList& outl) {
|
||||||
if (!m_impp) v3fatalSrc("readWholefile on invalid filter");
|
if (!m_impp) v3fatalSrc("readWholefile on invalid filter");
|
||||||
return m_impp->readWholefile(filename, out);
|
return m_impp->readWholefile(filename, outl);
|
||||||
}
|
}
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|||||||
+5
-1
@@ -28,6 +28,7 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <list>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
@@ -79,9 +80,12 @@ class V3InFilterImp;
|
|||||||
class V3InFilter {
|
class V3InFilter {
|
||||||
V3InFilterImp* m_impp;
|
V3InFilterImp* m_impp;
|
||||||
public:
|
public:
|
||||||
|
// TYPES
|
||||||
|
typedef list<string> StrList;
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
// Read file contents and return it. Return true on success.
|
// Read file contents and return it. Return true on success.
|
||||||
bool readWholefile(const string& filename, string& out);
|
bool readWholefile(const string& filename, StrList& outl);
|
||||||
|
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
V3InFilter(const string& command);
|
V3InFilter(const string& command);
|
||||||
|
|||||||
@@ -357,6 +357,12 @@ private:
|
|||||||
virtual void visit(AstAlways* nodep, AstNUser*) {
|
virtual void visit(AstAlways* nodep, AstNUser*) {
|
||||||
iterateNewStmt(nodep, (nodep->isJustOneBodyStmt()?NULL:"Multiple Stmts"), NULL);
|
iterateNewStmt(nodep, (nodep->isJustOneBodyStmt()?NULL:"Multiple Stmts"), NULL);
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
|
||||||
|
bool lastslow = m_inSlow;
|
||||||
|
m_inSlow = true;
|
||||||
|
iterateNewStmt(nodep, "AlwaysPublic", NULL);
|
||||||
|
m_inSlow = lastslow;
|
||||||
|
}
|
||||||
virtual void visit(AstCFunc* nodep, AstNUser*) {
|
virtual void visit(AstCFunc* nodep, AstNUser*) {
|
||||||
iterateNewStmt(nodep, "User C Function", "User C Function");
|
iterateNewStmt(nodep, "User C Function", "User C Function");
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-3
@@ -57,6 +57,7 @@ private:
|
|||||||
// AstNodeModule::user1p() // bool. True to inline this module (from InlineMarkVisitor)
|
// AstNodeModule::user1p() // bool. True to inline this module (from InlineMarkVisitor)
|
||||||
// Cleared each cell
|
// Cleared each cell
|
||||||
// AstVar::user2p() // AstVarRef*/AstConst* Points to signal this is a direct connect to
|
// AstVar::user2p() // AstVarRef*/AstConst* Points to signal this is a direct connect to
|
||||||
|
// AstVar::user3() // bool Don't alias the user4, keep it as signal
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
AstNodeModule* m_modp; // Current module
|
AstNodeModule* m_modp; // Current module
|
||||||
@@ -151,6 +152,10 @@ private:
|
|||||||
UINFO(6,"One-to-one "<<connectRefp<<endl);
|
UINFO(6,"One-to-one "<<connectRefp<<endl);
|
||||||
UINFO(6," -to "<<pinNewVarp<<endl);
|
UINFO(6," -to "<<pinNewVarp<<endl);
|
||||||
pinNewVarp->user2p(connectRefp);
|
pinNewVarp->user2p(connectRefp);
|
||||||
|
// Public output inside the cell must go via an assign rather than alias
|
||||||
|
// Else the public logic will set the alias, loosing the value to be propagated up
|
||||||
|
// (InOnly isn't a problem as the AssignAlias will create the assignment for us)
|
||||||
|
pinNewVarp->user3(pinNewVarp->isSigUserRWPublic() && pinNewVarp->isOutOnly());
|
||||||
}
|
}
|
||||||
// Cleanup var names, etc, to not conflict
|
// Cleanup var names, etc, to not conflict
|
||||||
m_cellp = nodep;
|
m_cellp = nodep;
|
||||||
@@ -175,6 +180,7 @@ private:
|
|||||||
// user2p is either a const or a var.
|
// user2p is either a const or a var.
|
||||||
AstConst* exprconstp = nodep->user2p()->castNode()->castConst();
|
AstConst* exprconstp = nodep->user2p()->castNode()->castConst();
|
||||||
AstVarRef* exprvarrefp = nodep->user2p()->castNode()->castVarRef();
|
AstVarRef* exprvarrefp = nodep->user2p()->castNode()->castVarRef();
|
||||||
|
UINFO(1,"connectto: "<<nodep->user2p()->castNode()<<endl);
|
||||||
if (!exprconstp && !exprvarrefp) {
|
if (!exprconstp && !exprvarrefp) {
|
||||||
nodep->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up\n");
|
nodep->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up\n");
|
||||||
}
|
}
|
||||||
@@ -182,6 +188,15 @@ private:
|
|||||||
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
|
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
|
||||||
new AstVarRef(nodep->fileline(), nodep, true),
|
new AstVarRef(nodep->fileline(), nodep, true),
|
||||||
exprconstp->cloneTree(true)));
|
exprconstp->cloneTree(true)));
|
||||||
|
} else if (nodep->user3()) {
|
||||||
|
// Public variable at the lower module end - we need to make sure we propagate
|
||||||
|
// the logic changes up and down; if we aliased, we might remove the change detection
|
||||||
|
// on the output variable.
|
||||||
|
UINFO(9,"public pin assign: "<<exprvarrefp<<endl);
|
||||||
|
if (nodep->isInput()) nodep->v3fatalSrc("Outputs only - inputs use AssignAlias");
|
||||||
|
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
|
||||||
|
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
|
||||||
|
new AstVarRef(nodep->fileline(), nodep, false)));
|
||||||
} else {
|
} else {
|
||||||
m_modp->addStmtp(new AstAssignAlias(nodep->fileline(),
|
m_modp->addStmtp(new AstAssignAlias(nodep->fileline(),
|
||||||
new AstVarRef(nodep->fileline(), nodep, true),
|
new AstVarRef(nodep->fileline(), nodep, true),
|
||||||
@@ -216,8 +231,9 @@ private:
|
|||||||
}
|
}
|
||||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||||
if (m_cellp) {
|
if (m_cellp) {
|
||||||
if (nodep->varp()->user2p() // It's being converted to a alias.
|
if (nodep->varp()->user2p() // It's being converted to an alias.
|
||||||
&& !nodep->backp()->castAssignAlias()) { // Don't constant propagate aliases
|
&& !nodep->varp()->user3()
|
||||||
|
&& !nodep->backp()->castAssignAlias()) { // Don't constant propagate aliases (we just made)
|
||||||
AstConst* exprconstp = nodep->varp()->user2p()->castNode()->castConst();
|
AstConst* exprconstp = nodep->varp()->user2p()->castNode()->castConst();
|
||||||
AstVarRef* exprvarrefp = nodep->varp()->user2p()->castNode()->castVarRef();
|
AstVarRef* exprvarrefp = nodep->varp()->user2p()->castNode()->castVarRef();
|
||||||
if (exprconstp) {
|
if (exprconstp) {
|
||||||
@@ -355,7 +371,7 @@ private:
|
|||||||
m_modp = NULL;
|
m_modp = NULL;
|
||||||
}
|
}
|
||||||
virtual void visit(AstCell* nodep, AstNUser*) {
|
virtual void visit(AstCell* nodep, AstNUser*) {
|
||||||
nodep->modp()->user3( nodep->modp()->user3() + 1);
|
nodep->modp()->user3Inc();
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
}
|
}
|
||||||
virtual void visit(AstPragma* nodep, AstNUser*) {
|
virtual void visit(AstPragma* nodep, AstNUser*) {
|
||||||
|
|||||||
+1
-2
@@ -89,8 +89,7 @@ private:
|
|||||||
if (nodep->modVarp()->isOutOnly() && nodep->exprp()->castConst())
|
if (nodep->modVarp()->isOutOnly() && nodep->exprp()->castConst())
|
||||||
nodep->v3error("Output port is connected to a constant pin, electrical short");
|
nodep->v3error("Output port is connected to a constant pin, electrical short");
|
||||||
// Use user1p on the PIN to indicate we created an assign for this pin
|
// Use user1p on the PIN to indicate we created an assign for this pin
|
||||||
if (!nodep->user1()) {
|
if (!nodep->user1Inc()) {
|
||||||
nodep->user1(1);
|
|
||||||
// Simplify it
|
// Simplify it
|
||||||
V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp);
|
V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp);
|
||||||
// Make a ASSIGNW (expr, pin)
|
// Make a ASSIGNW (expr, pin)
|
||||||
|
|||||||
+23
-1
@@ -288,6 +288,7 @@ private:
|
|||||||
// STATE
|
// STATE
|
||||||
LifeState* m_statep; // Current state
|
LifeState* m_statep; // Current state
|
||||||
bool m_sideEffect; // Side effects discovered in assign RHS
|
bool m_sideEffect; // Side effects discovered in assign RHS
|
||||||
|
bool m_noopt; // Disable optimization of variables in this block
|
||||||
|
|
||||||
// LIFE MAP
|
// LIFE MAP
|
||||||
// For each basic block, we'll make a new map of what variables that if/else is changing
|
// For each basic block, we'll make a new map of what variables that if/else is changing
|
||||||
@@ -327,7 +328,7 @@ private:
|
|||||||
V3Const::constifyEdit(nodep->rhsp()); // rhsp may change
|
V3Const::constifyEdit(nodep->rhsp()); // rhsp may change
|
||||||
}
|
}
|
||||||
// Has to be direct assignment without any EXTRACTing.
|
// Has to be direct assignment without any EXTRACTing.
|
||||||
if (nodep->lhsp()->castVarRef() && !m_sideEffect) {
|
if (nodep->lhsp()->castVarRef() && !m_sideEffect && !m_noopt) {
|
||||||
AstVarScope* vscp = nodep->lhsp()->castVarRef()->varScopep();
|
AstVarScope* vscp = nodep->lhsp()->castVarRef()->varScopep();
|
||||||
if (!vscp) nodep->v3fatalSrc("Scope lost on variable");
|
if (!vscp) nodep->v3fatalSrc("Scope lost on variable");
|
||||||
m_lifep->simpleAssign(vscp, nodep);
|
m_lifep->simpleAssign(vscp, nodep);
|
||||||
@@ -388,6 +389,7 @@ private:
|
|||||||
{
|
{
|
||||||
m_lifep = bodyLifep;
|
m_lifep = bodyLifep;
|
||||||
nodep->bodysp()->iterateAndNext(*this);
|
nodep->bodysp()->iterateAndNext(*this);
|
||||||
|
nodep->incsp()->iterateAndNext(*this);
|
||||||
m_lifep = prevLifep;
|
m_lifep = prevLifep;
|
||||||
}
|
}
|
||||||
UINFO(4," joinfor"<<endl);
|
UINFO(4," joinfor"<<endl);
|
||||||
@@ -397,6 +399,25 @@ private:
|
|||||||
delete condLifep;
|
delete condLifep;
|
||||||
delete bodyLifep;
|
delete bodyLifep;
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstJumpLabel* nodep, AstNUser*) {
|
||||||
|
// As with While's we can't predict if a JumpGo will kill us or not
|
||||||
|
// It's worse though as an IF(..., JUMPGO) may change the control flow.
|
||||||
|
// Just don't optimize blocks with labels; they're rare - so far.
|
||||||
|
LifeBlock* prevLifep = m_lifep;
|
||||||
|
LifeBlock* bodyLifep = new LifeBlock (prevLifep, m_statep);
|
||||||
|
bool prev_noopt = m_noopt;
|
||||||
|
{
|
||||||
|
m_lifep = bodyLifep;
|
||||||
|
m_noopt = true;
|
||||||
|
nodep->stmtsp()->iterateAndNext(*this);
|
||||||
|
m_lifep = prevLifep;
|
||||||
|
m_noopt = prev_noopt;
|
||||||
|
}
|
||||||
|
UINFO(4," joinjump"<<endl);
|
||||||
|
// For the next assignments, clear any variables that were read or written in the block
|
||||||
|
bodyLifep->lifeToAbove();
|
||||||
|
delete bodyLifep;
|
||||||
|
}
|
||||||
virtual void visit(AstCCall* nodep, AstNUser*) {
|
virtual void visit(AstCCall* nodep, AstNUser*) {
|
||||||
//UINFO(4," CCALL "<<nodep<<endl);
|
//UINFO(4," CCALL "<<nodep<<endl);
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
@@ -432,6 +453,7 @@ public:
|
|||||||
UINFO(4," LifeVisitor on "<<nodep<<endl);
|
UINFO(4," LifeVisitor on "<<nodep<<endl);
|
||||||
m_statep = statep;
|
m_statep = statep;
|
||||||
m_sideEffect = false;
|
m_sideEffect = false;
|
||||||
|
m_noopt = false;
|
||||||
{
|
{
|
||||||
m_lifep = new LifeBlock (NULL, m_statep);
|
m_lifep = new LifeBlock (NULL, m_statep);
|
||||||
nodep->accept(*this);
|
nodep->accept(*this);
|
||||||
|
|||||||
+7
-1
@@ -185,7 +185,13 @@ private:
|
|||||||
// Create implicit after warning
|
// Create implicit after warning
|
||||||
if (linkVarName(forrefp)) { forrefp=NULL; return; }
|
if (linkVarName(forrefp)) { forrefp=NULL; return; }
|
||||||
if (!forrefp->varp()) {
|
if (!forrefp->varp()) {
|
||||||
if (!noWarn) forrefp->v3warn(IMPLICIT,"Signal definition not found, creating implicitly: "<<forrefp->prettyName());
|
if (!noWarn) {
|
||||||
|
if (forrefp->fileline()->warnIsOff(V3ErrorCode::I_DEF_NETTYPE_WIRE)) {
|
||||||
|
forrefp->v3error("Signal definition not found, and implicit disabled with `default_nettype: "<<forrefp->prettyName());
|
||||||
|
} else {
|
||||||
|
forrefp->v3warn(IMPLICIT,"Signal definition not found, creating implicitly: "<<forrefp->prettyName());
|
||||||
|
}
|
||||||
|
}
|
||||||
AstVar* newp = new AstVar (forrefp->fileline(), AstVarType::WIRE,
|
AstVar* newp = new AstVar (forrefp->fileline(), AstVarType::WIRE,
|
||||||
forrefp->name(), AstLogicPacked(), 1);
|
forrefp->name(), AstLogicPacked(), 1);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,227 @@
|
|||||||
|
//*************************************************************************
|
||||||
|
// DESCRIPTION: Verilator: Replace return/continue with jumps
|
||||||
|
//
|
||||||
|
// Code available from: http://www.veripool.org/verilator
|
||||||
|
//
|
||||||
|
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
//
|
||||||
|
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||||
|
// redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
// Version 2.0.
|
||||||
|
//
|
||||||
|
// Verilator is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
// V3LinkJump's Transformations:
|
||||||
|
//
|
||||||
|
// Each module:
|
||||||
|
// Look for BEGINs
|
||||||
|
// BEGIN(VAR...) -> VAR ... {renamed}
|
||||||
|
// FOR -> WHILEs
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
|
||||||
|
#include "config_build.h"
|
||||||
|
#include "verilatedos.h"
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "V3Global.h"
|
||||||
|
#include "V3LinkJump.h"
|
||||||
|
#include "V3Ast.h"
|
||||||
|
|
||||||
|
//######################################################################
|
||||||
|
|
||||||
|
class LinkJumpVisitor : public AstNVisitor {
|
||||||
|
private:
|
||||||
|
// TYPES
|
||||||
|
typedef vector<AstBegin*> BeginStack;
|
||||||
|
|
||||||
|
// STATE
|
||||||
|
AstModule* m_modp; // Current module
|
||||||
|
AstNodeFTask* m_ftaskp; // Current function/task
|
||||||
|
AstWhile* m_loopp; // Current loop
|
||||||
|
int m_repeatNum; // Repeat counter
|
||||||
|
BeginStack m_beginStack; // All begin blocks above current node
|
||||||
|
|
||||||
|
// METHODS
|
||||||
|
static int debug() {
|
||||||
|
static int level = -1;
|
||||||
|
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
|
||||||
|
AstJumpLabel* findAddLabel(AstNode* nodep, bool endOfIter) {
|
||||||
|
// Put label under given node, and if WHILE optionally at end of iteration
|
||||||
|
UINFO(4,"Create label for "<<nodep<<endl);
|
||||||
|
if (nodep->castJumpLabel()) return nodep->castJumpLabel(); // Done
|
||||||
|
|
||||||
|
AstNode* underp = NULL;
|
||||||
|
bool under_and_next = true;
|
||||||
|
if (nodep->castBegin()) underp = nodep->castBegin()->stmtsp();
|
||||||
|
else if (nodep->castNodeFTask()) underp = nodep->castNodeFTask()->stmtsp();
|
||||||
|
else if (nodep->castWhile()) {
|
||||||
|
if (endOfIter) {
|
||||||
|
// Note we jump to end of bodysp; a FOR loop has its increment under incsp() which we don't skip
|
||||||
|
underp = nodep->castWhile()->bodysp();
|
||||||
|
} else {
|
||||||
|
underp = nodep; under_and_next=false; // IE we skip the entire while
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nodep->v3fatalSrc("Unknown jump point for break/disable/continue");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!underp) {
|
||||||
|
nodep->v3fatalSrc("Break/disable/continue not under expected statement");
|
||||||
|
return NULL;
|
||||||
|
} else if (underp->castJumpLabel()) {
|
||||||
|
return underp->castJumpLabel();
|
||||||
|
} else { // Move underp stuff to be under a new label
|
||||||
|
AstJumpLabel* labelp = new AstJumpLabel(nodep->fileline(), NULL);
|
||||||
|
|
||||||
|
AstNRelinker repHandle;
|
||||||
|
if (under_and_next) underp->unlinkFrBackWithNext(&repHandle);
|
||||||
|
else underp->unlinkFrBack(&repHandle);
|
||||||
|
repHandle.relink(labelp);
|
||||||
|
|
||||||
|
labelp->addStmtsp(underp);
|
||||||
|
// Keep any AstVars under the function not under the new JumpLabel
|
||||||
|
for (AstNode* nextp, *varp=underp; varp; varp = nextp) {
|
||||||
|
nextp = varp->nextp();
|
||||||
|
if (varp->castVar()) {
|
||||||
|
labelp->addPrev(varp->unlinkFrBack());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return labelp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// VISITORS
|
||||||
|
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||||
|
m_modp = nodep;
|
||||||
|
m_repeatNum = 0;
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
m_modp = NULL;
|
||||||
|
}
|
||||||
|
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
||||||
|
m_ftaskp = nodep;
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
m_ftaskp = NULL;
|
||||||
|
}
|
||||||
|
virtual void visit(AstBegin* nodep, AstNUser*) {
|
||||||
|
UINFO(8," "<<nodep<<endl);
|
||||||
|
m_beginStack.push_back(nodep);
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
m_beginStack.pop_back();
|
||||||
|
}
|
||||||
|
virtual void visit(AstRepeat* nodep, AstNUser*) {
|
||||||
|
// So later optimizations don't need to deal with them,
|
||||||
|
// REPEAT(count,body) -> loop=count,WHILE(loop>0) { body, loop-- }
|
||||||
|
// Note var can be signed or unsigned based on original number.
|
||||||
|
AstNode* countp = nodep->countp()->unlinkFrBackWithNext();
|
||||||
|
string name = string("__Vrepeat")+cvtToStr(m_repeatNum++);
|
||||||
|
// Spec says value is integral, if negative is ignored
|
||||||
|
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP, name,
|
||||||
|
AstLogicPacked(), 32);
|
||||||
|
varp->isSigned(true);
|
||||||
|
varp->dtypep()->isSigned(true);
|
||||||
|
m_modp->addStmtp(varp);
|
||||||
|
AstNode* initsp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
|
||||||
|
countp);
|
||||||
|
AstNode* decp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
|
||||||
|
new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
|
||||||
|
new AstConst(nodep->fileline(), 1)));
|
||||||
|
AstNode* zerosp = new AstConst(nodep->fileline(), 0); zerosp->isSigned(true);
|
||||||
|
AstNode* condp = new AstGtS(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
|
||||||
|
zerosp);
|
||||||
|
AstNode* bodysp = nodep->bodysp(); if (bodysp) bodysp->unlinkFrBackWithNext();
|
||||||
|
AstNode* newp = new AstWhile(nodep->fileline(),
|
||||||
|
condp,
|
||||||
|
bodysp,
|
||||||
|
decp);
|
||||||
|
initsp = initsp->addNext(newp);
|
||||||
|
newp = initsp;
|
||||||
|
nodep->replaceWith(newp);
|
||||||
|
nodep->deleteTree(); nodep=NULL;
|
||||||
|
}
|
||||||
|
virtual void visit(AstWhile* nodep, AstNUser*) {
|
||||||
|
// Don't need to track AstRepeat/AstFor as they have already been converted
|
||||||
|
AstWhile* lastLoopp = m_loopp;
|
||||||
|
m_loopp = nodep;
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
m_loopp = lastLoopp;
|
||||||
|
}
|
||||||
|
virtual void visit(AstReturn* nodep, AstNUser*) {
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
AstFunc* funcp = m_ftaskp->castFunc();
|
||||||
|
if (!m_ftaskp) { nodep->v3error("Return isn't underneath a task or function"); }
|
||||||
|
else if (funcp && !nodep->lhsp()) { nodep->v3error("Return underneath a function should have return value"); }
|
||||||
|
else if (!funcp && nodep->lhsp()) { nodep->v3error("Return underneath a task shouldn't have return value"); }
|
||||||
|
else {
|
||||||
|
if (funcp && nodep->lhsp()) {
|
||||||
|
// Set output variable to return value
|
||||||
|
nodep->addPrev(new AstAssign(nodep->fileline(),
|
||||||
|
new AstVarRef(nodep->fileline(), funcp->fvarp()->castVar(), true),
|
||||||
|
nodep->lhsp()->unlinkFrBackWithNext()));
|
||||||
|
}
|
||||||
|
// Jump to the end of the function call
|
||||||
|
AstJumpLabel* labelp = findAddLabel(m_ftaskp, false);
|
||||||
|
nodep->addPrev(new AstJumpGo(nodep->fileline(), labelp));
|
||||||
|
}
|
||||||
|
nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL;
|
||||||
|
}
|
||||||
|
virtual void visit(AstBreak* nodep, AstNUser*) {
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
if (!m_loopp) { nodep->v3error("break isn't underneath a loop"); }
|
||||||
|
else {
|
||||||
|
// Jump to the end of the loop
|
||||||
|
AstJumpLabel* labelp = findAddLabel(m_loopp, false);
|
||||||
|
nodep->addNextHere(new AstJumpGo(nodep->fileline(), labelp));
|
||||||
|
}
|
||||||
|
nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL;
|
||||||
|
}
|
||||||
|
virtual void visit(AstContinue* nodep, AstNUser*) {
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
if (!m_loopp) { nodep->v3error("continue isn't underneath a loop"); }
|
||||||
|
else {
|
||||||
|
// Jump to the end of this iteration
|
||||||
|
// If a "for" loop then need to still do the post-loop increment
|
||||||
|
AstJumpLabel* labelp = findAddLabel(m_loopp, true);
|
||||||
|
nodep->addNextHere(new AstJumpGo(nodep->fileline(), labelp));
|
||||||
|
}
|
||||||
|
nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
// CONSTUCTORS
|
||||||
|
LinkJumpVisitor(AstNetlist* nodep) {
|
||||||
|
m_modp = NULL;
|
||||||
|
m_ftaskp = NULL;
|
||||||
|
m_loopp = NULL;
|
||||||
|
m_repeatNum = 0;
|
||||||
|
nodep->accept(*this);
|
||||||
|
}
|
||||||
|
virtual ~LinkJumpVisitor() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
//######################################################################
|
||||||
|
// Task class functions
|
||||||
|
|
||||||
|
void V3LinkJump::linkJump(AstNetlist* nodep) {
|
||||||
|
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||||
|
LinkJumpVisitor bvisitor (nodep);
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
// -*- C++ -*-
|
||||||
|
//*************************************************************************
|
||||||
|
// DESCRIPTION: Verilator: Replace return/continue with jumps
|
||||||
|
//
|
||||||
|
// Code available from: http://www.veripool.org/verilator
|
||||||
|
//
|
||||||
|
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
//
|
||||||
|
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||||
|
// redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
// Version 2.0.
|
||||||
|
//
|
||||||
|
// Verilator is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
|
||||||
|
#ifndef _V3LINKJUMP_H_
|
||||||
|
#define _V3LINKJUMP_H_ 1
|
||||||
|
#include "config_build.h"
|
||||||
|
#include "verilatedos.h"
|
||||||
|
#include "V3Error.h"
|
||||||
|
#include "V3Ast.h"
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
class V3LinkJump {
|
||||||
|
public:
|
||||||
|
static void linkJump(AstNetlist* nodep);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // Guard
|
||||||
+30
-10
@@ -77,8 +77,7 @@ private:
|
|||||||
|
|
||||||
// VISITs
|
// VISITs
|
||||||
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
|
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
|
||||||
if (!nodep->user1()) {
|
if (!nodep->user1Inc()) { // Process only once.
|
||||||
nodep->user1(true); // Process only once.
|
|
||||||
UINFO(5," "<<nodep<<endl);
|
UINFO(5," "<<nodep<<endl);
|
||||||
checkExpected(nodep);
|
checkExpected(nodep);
|
||||||
// Due to a need to get the arguments, the ParseRefs are under here,
|
// Due to a need to get the arguments, the ParseRefs are under here,
|
||||||
@@ -165,8 +164,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstSelBit* nodep, AstNUser*) {
|
virtual void visit(AstSelBit* nodep, AstNUser*) {
|
||||||
if (!nodep->user1()) {
|
if (!nodep->user1Inc()) { // Process only once.
|
||||||
nodep->user1(true); // Process only once.
|
|
||||||
if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
||||||
m_dotText = "";
|
m_dotText = "";
|
||||||
nodep->lhsp()->iterateAndNext(*this);
|
nodep->lhsp()->iterateAndNext(*this);
|
||||||
@@ -194,8 +192,7 @@ private:
|
|||||||
}
|
}
|
||||||
virtual void visit(AstNodePreSel* nodep, AstNUser*) {
|
virtual void visit(AstNodePreSel* nodep, AstNUser*) {
|
||||||
// Excludes simple AstSel, see above
|
// Excludes simple AstSel, see above
|
||||||
if (!nodep->user1()) {
|
if (!nodep->user1Inc()) { // Process only once.
|
||||||
nodep->user1(true); // Process only once.
|
|
||||||
if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
||||||
nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed in the cell part of a dotted reference");
|
nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed in the cell part of a dotted reference");
|
||||||
} else if (m_exp==AstParseRefExp::PX_FUNC) {
|
} else if (m_exp==AstParseRefExp::PX_FUNC) {
|
||||||
@@ -217,8 +214,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstText* nodep, AstNUser*) {
|
virtual void visit(AstText* nodep, AstNUser*) {
|
||||||
if (!nodep->user1()) {
|
if (!nodep->user1Inc()) { // Process only once.
|
||||||
nodep->user1(true); // Process only once.
|
|
||||||
if (m_exp != AstParseRefExp::PX_NONE) {
|
if (m_exp != AstParseRefExp::PX_NONE) {
|
||||||
UINFO(7," "<<nodep<<endl);
|
UINFO(7," "<<nodep<<endl);
|
||||||
if (m_inModDot) { // Dotted part, just pass up
|
if (m_inModDot) { // Dotted part, just pass up
|
||||||
@@ -274,12 +270,22 @@ private:
|
|||||||
}
|
}
|
||||||
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC) {
|
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC) {
|
||||||
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
|
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
|
||||||
m_varp->sigPublic(true); m_varp->sigModPublic(true);
|
m_varp->sigUserRWPublic(true); m_varp->sigModPublic(true);
|
||||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||||
}
|
}
|
||||||
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT) {
|
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT) {
|
||||||
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
|
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
|
||||||
m_varp->sigPublic(true);
|
m_varp->sigUserRWPublic(true);
|
||||||
|
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||||
|
}
|
||||||
|
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT_RD) {
|
||||||
|
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
|
||||||
|
m_varp->sigUserRdPublic(true);
|
||||||
|
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||||
|
}
|
||||||
|
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT_RW) {
|
||||||
|
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
|
||||||
|
m_varp->sigUserRWPublic(true);
|
||||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||||
}
|
}
|
||||||
else if (nodep->attrType() == AstAttrType::VAR_ISOLATE_ASSIGNMENTS) {
|
else if (nodep->attrType() == AstAttrType::VAR_ISOLATE_ASSIGNMENTS) {
|
||||||
@@ -294,6 +300,20 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
|
||||||
|
// AlwaysPublic was attached under a var, but it's a statement that should be
|
||||||
|
// at the same level as the var
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
if (m_varp) {
|
||||||
|
nodep->unlinkFrBack();
|
||||||
|
m_varp->addNext(nodep);
|
||||||
|
// lvalue is true, because we know we have a verilator public_flat_rw
|
||||||
|
// but someday we may be more general
|
||||||
|
bool lvalue = m_varp->isSigUserRWPublic();
|
||||||
|
nodep->addStmtp(new AstVarRef(nodep->fileline(), m_varp, lvalue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtual void visit(AstDefImplicitDType* nodep, AstNUser*) {
|
virtual void visit(AstDefImplicitDType* nodep, AstNUser*) {
|
||||||
UINFO(8," DEFIMPLICIT "<<nodep<<endl);
|
UINFO(8," DEFIMPLICIT "<<nodep<<endl);
|
||||||
// Must remember what names we've already created, and combine duplicates
|
// Must remember what names we've already created, and combine duplicates
|
||||||
|
|||||||
@@ -75,6 +75,13 @@ private:
|
|||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
m_modp = NULL;
|
m_modp = NULL;
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstInitial* nodep, AstNUser*) {
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
// Initial assignments under function/tasks can just be simple assignments without the initial
|
||||||
|
if (m_ftaskp) {
|
||||||
|
nodep->replaceWith(nodep->bodysp()->unlinkFrBackWithNext()); nodep=NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
virtual void visit(AstVAssert* nodep, AstNUser*) {
|
virtual void visit(AstVAssert* nodep, AstNUser*) {
|
||||||
if (m_assertp) nodep->v3error("Assert not allowed under another assert");
|
if (m_assertp) nodep->v3error("Assert not allowed under another assert");
|
||||||
m_assertp = nodep;
|
m_assertp = nodep;
|
||||||
|
|||||||
+1
-2
@@ -109,8 +109,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstScope* nodep, AstNUser*) {
|
virtual void visit(AstScope* nodep, AstNUser*) {
|
||||||
if (!nodep->user1()) {
|
if (!nodep->user1Inc()) {
|
||||||
nodep->user1(1);
|
|
||||||
if (nodep->aboveScopep()) nodep->aboveScopep()->iterate(*this);
|
if (nodep->aboveScopep()) nodep->aboveScopep()->iterate(*this);
|
||||||
if (nodep->aboveCellp()) nodep->aboveCellp()->iterate(*this);
|
if (nodep->aboveCellp()) nodep->aboveCellp()->iterate(*this);
|
||||||
// Always recompute name (as many level above scope may have changed)
|
// Always recompute name (as many level above scope may have changed)
|
||||||
|
|||||||
+1
-1
@@ -1023,7 +1023,7 @@ V3Options::V3Options() {
|
|||||||
m_outputSplitCTrace = 0;
|
m_outputSplitCTrace = 0;
|
||||||
m_traceDepth = 0;
|
m_traceDepth = 0;
|
||||||
m_unrollCount = 64;
|
m_unrollCount = 64;
|
||||||
m_unrollStmts = 100;
|
m_unrollStmts = 30000;
|
||||||
|
|
||||||
m_compLimitParens = 0;
|
m_compLimitParens = 0;
|
||||||
m_compLimitBlocks = 0;
|
m_compLimitBlocks = 0;
|
||||||
|
|||||||
+42
-16
@@ -375,7 +375,7 @@ private:
|
|||||||
OrderLoopId processMoveLoopCurrent();
|
OrderLoopId processMoveLoopCurrent();
|
||||||
|
|
||||||
string cfuncName(AstNodeModule* modp, AstSenTree* domainp, AstScope* scopep, AstNode* forWhatp) {
|
string cfuncName(AstNodeModule* modp, AstSenTree* domainp, AstScope* scopep, AstNode* forWhatp) {
|
||||||
modp->user3(1+modp->user3());
|
modp->user3Inc();
|
||||||
int funcnum = modp->user3();
|
int funcnum = modp->user3();
|
||||||
string name = (domainp->hasCombo() ? "_combo"
|
string name = (domainp->hasCombo() ? "_combo"
|
||||||
: (domainp->hasInitial() ? "_initial"
|
: (domainp->hasInitial() ? "_initial"
|
||||||
@@ -666,6 +666,9 @@ private:
|
|||||||
iterateNewStmt(nodep);
|
iterateNewStmt(nodep);
|
||||||
m_inPost = false;
|
m_inPost = false;
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
|
||||||
|
iterateNewStmt(nodep);
|
||||||
|
}
|
||||||
virtual void visit(AstAssignAlias* nodep, AstNUser*) {
|
virtual void visit(AstAssignAlias* nodep, AstNUser*) {
|
||||||
iterateNewStmt(nodep);
|
iterateNewStmt(nodep);
|
||||||
}
|
}
|
||||||
@@ -941,28 +944,51 @@ void OrderVisitor::processBrokeLoop() {
|
|||||||
// Clock propagation
|
// Clock propagation
|
||||||
|
|
||||||
void OrderVisitor::processInputs() {
|
void OrderVisitor::processInputs() {
|
||||||
m_graph.userClearVertices(); // Vertex::user() // true if added as begin/end
|
m_graph.userClearVertices(); // Vertex::user() // true if processed
|
||||||
|
// Start at input vertex, process from input-to-output order
|
||||||
|
m_inputsVxp->isFromInput(true); // By definition
|
||||||
processInputsIterate(m_inputsVxp);
|
processInputsIterate(m_inputsVxp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OrderVisitor::processInputsIterate(OrderEitherVertex* vertexp) {
|
void OrderVisitor::processInputsIterate(OrderEitherVertex* vertexp) {
|
||||||
// Propagate PrimaryIn through simple assignments
|
// Propagate PrimaryIn through simple assignments
|
||||||
if (vertexp->user()) return; // Already processed
|
if (vertexp->user()) return; // Already processed
|
||||||
//UINFO(9," InIt "<<vertexp<<endl);
|
if (0 && debug()>=9) {
|
||||||
vertexp->user(true);
|
UINFO(9," InIt "<<vertexp<<endl);
|
||||||
if (OrderVarStdVertex* vvertexp = dynamic_cast<OrderVarStdVertex*>(vertexp)) {
|
if (OrderLogicVertex* vvertexp = dynamic_cast<OrderLogicVertex*>(vertexp)) {
|
||||||
vvertexp->isFromInput(true);
|
vvertexp->nodep()->dumpTree(cout,"- TT: ");
|
||||||
}
|
|
||||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
|
||||||
OrderEitherVertex* toVertexp = (OrderEitherVertex*)edgep->top();
|
|
||||||
if (OrderVarStdVertex* vvertexp = dynamic_cast<OrderVarStdVertex*>(toVertexp)) {
|
|
||||||
processInputsIterate(vvertexp);
|
|
||||||
}
|
}
|
||||||
if (OrderLogicVertex* vvertexp = dynamic_cast<OrderLogicVertex*>(toVertexp)) {
|
}
|
||||||
if (AstNodeAssign* nodep = vvertexp->nodep()->castNodeAssign()) {
|
vertexp->user(true); // Processing
|
||||||
if (nodep->lhsp()->castVarRef()
|
// First handle all inputs to this vertex, in most cases they'll be already processed earlier
|
||||||
&& nodep->rhsp()->castVarRef()) {
|
// Also, determine if this vertex is an input
|
||||||
UINFO(9," Input reassignment: "<<vvertexp<<endl);
|
int inonly = 1; // 0=no, 1=maybe, 2=yes until a no
|
||||||
|
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) {
|
||||||
|
OrderEitherVertex* frVertexp = (OrderEitherVertex*)edgep->fromp();
|
||||||
|
processInputsIterate(frVertexp);
|
||||||
|
if (frVertexp->isFromInput()) {
|
||||||
|
if (inonly==1) inonly = 2;
|
||||||
|
} else if (dynamic_cast<OrderVarPostVertex*>(frVertexp)) {
|
||||||
|
// Ignore post assignments, just for ordering
|
||||||
|
} else {
|
||||||
|
//UINFO(9," InItStopDueTo "<<frVertexp<<endl);
|
||||||
|
inonly = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (inonly == 2) { // Set it. Note may have already been set earlier, too
|
||||||
|
UINFO(9," Input reassignment: "<<vertexp<<endl);
|
||||||
|
vertexp->isFromInput(true);
|
||||||
|
}
|
||||||
|
// If we're still an input, process all targets of this vertex
|
||||||
|
if (vertexp->isFromInput()) {
|
||||||
|
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||||
|
OrderEitherVertex* toVertexp = (OrderEitherVertex*)edgep->top();
|
||||||
|
if (OrderVarStdVertex* vvertexp = dynamic_cast<OrderVarStdVertex*>(toVertexp)) {
|
||||||
|
processInputsIterate(vvertexp);
|
||||||
|
}
|
||||||
|
if (OrderLogicVertex* vvertexp = dynamic_cast<OrderLogicVertex*>(toVertexp)) {
|
||||||
|
if (vvertexp->nodep()->castNodeAssign()) {
|
||||||
processInputsIterate(vvertexp);
|
processInputsIterate(vvertexp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-6
@@ -132,10 +132,11 @@ class OrderEitherVertex : public V3GraphVertex {
|
|||||||
AstScope* m_scopep; // Scope the vertex is in
|
AstScope* m_scopep; // Scope the vertex is in
|
||||||
AstSenTree* m_domainp; // Clock domain (NULL = to be computed as we iterate)
|
AstSenTree* m_domainp; // Clock domain (NULL = to be computed as we iterate)
|
||||||
OrderLoopId m_inLoop; // Loop number vertex is in
|
OrderLoopId m_inLoop; // Loop number vertex is in
|
||||||
|
bool m_isFromInput; // From input, or derrived therefrom (conservatively false)
|
||||||
public:
|
public:
|
||||||
OrderEitherVertex(V3Graph* graphp, AstScope* scopep, AstSenTree* domainp)
|
OrderEitherVertex(V3Graph* graphp, AstScope* scopep, AstSenTree* domainp)
|
||||||
: V3GraphVertex(graphp), m_scopep(scopep), m_domainp(domainp)
|
: V3GraphVertex(graphp), m_scopep(scopep), m_domainp(domainp)
|
||||||
, m_inLoop(LOOPID_UNKNOWN) {
|
, m_inLoop(LOOPID_UNKNOWN), m_isFromInput(false) {
|
||||||
}
|
}
|
||||||
virtual ~OrderEitherVertex() {}
|
virtual ~OrderEitherVertex() {}
|
||||||
// Methods
|
// Methods
|
||||||
@@ -148,12 +149,16 @@ public:
|
|||||||
AstSenTree* domainp() const { return m_domainp; }
|
AstSenTree* domainp() const { return m_domainp; }
|
||||||
OrderLoopId inLoop() const { return m_inLoop; }
|
OrderLoopId inLoop() const { return m_inLoop; }
|
||||||
void inLoop(OrderLoopId inloop) { m_inLoop = inloop; }
|
void inLoop(OrderLoopId inloop) { m_inLoop = inloop; }
|
||||||
|
void isFromInput(bool flag) { m_isFromInput=flag; }
|
||||||
|
bool isFromInput() const { return m_isFromInput; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class OrderInputsVertex : public OrderEitherVertex {
|
class OrderInputsVertex : public OrderEitherVertex {
|
||||||
public:
|
public:
|
||||||
OrderInputsVertex(V3Graph* graphp, AstSenTree* domainp)
|
OrderInputsVertex(V3Graph* graphp, AstSenTree* domainp)
|
||||||
: OrderEitherVertex(graphp, NULL, domainp) {}
|
: OrderEitherVertex(graphp, NULL, domainp) {
|
||||||
|
isFromInput(true); // By definition
|
||||||
|
}
|
||||||
virtual ~OrderInputsVertex() {}
|
virtual ~OrderInputsVertex() {}
|
||||||
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_INPUTS; }
|
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_INPUTS; }
|
||||||
virtual string name() const { return "*INPUTS*"; }
|
virtual string name() const { return "*INPUTS*"; }
|
||||||
@@ -195,11 +200,10 @@ class OrderVarVertex : public OrderEitherVertex {
|
|||||||
AstVarScope* m_varScp;
|
AstVarScope* m_varScp;
|
||||||
OrderVarVertex* m_pilNewVertexp; // for processInsLoopNewVar
|
OrderVarVertex* m_pilNewVertexp; // for processInsLoopNewVar
|
||||||
bool m_isClock; // Used as clock
|
bool m_isClock; // Used as clock
|
||||||
bool m_isFromInput; // From input, or derrived therefrom (conservatively false)
|
|
||||||
public:
|
public:
|
||||||
OrderVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
|
OrderVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
|
||||||
: OrderEitherVertex(graphp, scopep, NULL), m_varScp(varScp)
|
: OrderEitherVertex(graphp, scopep, NULL), m_varScp(varScp)
|
||||||
, m_pilNewVertexp(NULL), m_isClock(false), m_isFromInput(false)
|
, m_pilNewVertexp(NULL), m_isClock(false)
|
||||||
{}
|
{}
|
||||||
virtual ~OrderVarVertex() {}
|
virtual ~OrderVarVertex() {}
|
||||||
virtual OrderVarVertex* clone (V3Graph* graphp) const = 0;
|
virtual OrderVarVertex* clone (V3Graph* graphp) const = 0;
|
||||||
@@ -208,8 +212,6 @@ public:
|
|||||||
AstVarScope* varScp() const { return m_varScp; }
|
AstVarScope* varScp() const { return m_varScp; }
|
||||||
void isClock(bool flag) { m_isClock=flag; }
|
void isClock(bool flag) { m_isClock=flag; }
|
||||||
bool isClock() const { return m_isClock; }
|
bool isClock() const { return m_isClock; }
|
||||||
void isFromInput(bool flag) { m_isFromInput=flag; }
|
|
||||||
bool isFromInput() const { return m_isFromInput; }
|
|
||||||
OrderVarVertex* pilNewVertexp() const { return m_pilNewVertexp; }
|
OrderVarVertex* pilNewVertexp() const { return m_pilNewVertexp; }
|
||||||
void pilNewVertexp (OrderVarVertex* vertexp) { m_pilNewVertexp = vertexp; }
|
void pilNewVertexp (OrderVarVertex* vertexp) { m_pilNewVertexp = vertexp; }
|
||||||
};
|
};
|
||||||
|
|||||||
+4
-3
@@ -52,10 +52,11 @@
|
|||||||
class ParamVisitor : public AstNVisitor {
|
class ParamVisitor : public AstNVisitor {
|
||||||
private:
|
private:
|
||||||
// NODE STATE
|
// NODE STATE
|
||||||
// AstNodeModule::user4() // bool True if parameters numbered
|
// AstNodeModule::user5() // bool True if parameters numbered
|
||||||
// AstVar::user4() // int Global parameter number (for naming new module)
|
// AstVar::user4() // int Global parameter number (for naming new module)
|
||||||
// // (0=not processed, 1=iterated, but no number, 65+ parameter numbered)
|
// // (0=not processed, 1=iterated, but no number, 65+ parameter numbered)
|
||||||
AstUser4InUse m_inuser4;
|
AstUser4InUse m_inuser4;
|
||||||
|
AstUser5InUse m_inuser5;
|
||||||
// User1/2/3 used by constant function simulations
|
// User1/2/3 used by constant function simulations
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
@@ -130,8 +131,8 @@ private:
|
|||||||
|
|
||||||
// Make sure all parameters are constantified
|
// Make sure all parameters are constantified
|
||||||
virtual void visit(AstVar* nodep, AstNUser*) {
|
virtual void visit(AstVar* nodep, AstNUser*) {
|
||||||
if (!nodep->user4()) {
|
if (!nodep->user5()) {
|
||||||
nodep->user4(1); // Mark done - Note values >1 used for letter numbering
|
nodep->user5(1); // Mark done
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (nodep->isParam()) {
|
if (nodep->isParam()) {
|
||||||
if (!nodep->hasSimpleInit()) { nodep->v3fatalSrc("Parameter without initial value"); }
|
if (!nodep->hasSimpleInit()) { nodep->v3fatalSrc("Parameter without initial value"); }
|
||||||
|
|||||||
+3
-3
@@ -66,12 +66,12 @@ V3ParseImp::~V3ParseImp() {
|
|||||||
if (debug()>=9) { UINFO(0,"~V3ParseImp\n"); symp()->dump(cout, "-vpi: "); }
|
if (debug()>=9) { UINFO(0,"~V3ParseImp\n"); symp()->dump(cout, "-vpi: "); }
|
||||||
}
|
}
|
||||||
|
|
||||||
int V3ParseImp::ppInputToLex(char* buf, int max_size) {
|
size_t V3ParseImp::ppInputToLex(char* buf, size_t max_size) {
|
||||||
int got = 0;
|
size_t got = 0;
|
||||||
while (got < max_size // Haven't got enough
|
while (got < max_size // Haven't got enough
|
||||||
&& !m_ppBuffers.empty()) { // And something buffered
|
&& !m_ppBuffers.empty()) { // And something buffered
|
||||||
string front = m_ppBuffers.front(); m_ppBuffers.pop_front();
|
string front = m_ppBuffers.front(); m_ppBuffers.pop_front();
|
||||||
int len = front.length();
|
size_t len = front.length();
|
||||||
if (len > (max_size-got)) { // Front string too big
|
if (len > (max_size-got)) { // Front string too big
|
||||||
string remainder = front.substr(max_size-got);
|
string remainder = front.substr(max_size-got);
|
||||||
front = front.substr(0, max_size-got);
|
front = front.substr(0, max_size-got);
|
||||||
|
|||||||
+4
-4
@@ -249,7 +249,7 @@ public:
|
|||||||
static bool optFuture(const string& flag) { return v3Global.opt.isFuture(flag); }
|
static bool optFuture(const string& flag) { return v3Global.opt.isFuture(flag); }
|
||||||
|
|
||||||
void ppline (const char* text);
|
void ppline (const char* text);
|
||||||
void incLineno() { fileline()->incLineno(); }
|
void linenoInc() { fileline()->linenoInc(); }
|
||||||
void verilatorCmtLint(const char* text, bool on);
|
void verilatorCmtLint(const char* text, bool on);
|
||||||
void verilatorCmtLintSave();
|
void verilatorCmtLintSave();
|
||||||
void verilatorCmtLintRestore();
|
void verilatorCmtLintRestore();
|
||||||
@@ -260,7 +260,7 @@ public:
|
|||||||
static const char* tokenName(int tok);
|
static const char* tokenName(int tok);
|
||||||
|
|
||||||
void ppPushText(const string& text) { m_ppBuffers.push_back(text); }
|
void ppPushText(const string& text) { m_ppBuffers.push_back(text); }
|
||||||
int ppInputToLex(char* buf, int max_size);
|
size_t ppInputToLex(char* buf, size_t max_size);
|
||||||
|
|
||||||
static V3ParseImp* parsep() { return s_parsep; }
|
static V3ParseImp* parsep() { return s_parsep; }
|
||||||
|
|
||||||
@@ -278,7 +278,7 @@ public:
|
|||||||
m_stringps.push_back(strp);
|
m_stringps.push_back(strp);
|
||||||
return strp;
|
return strp;
|
||||||
}
|
}
|
||||||
string* newString(const char* text, int length) {
|
string* newString(const char* text, size_t length) {
|
||||||
string* strp = new string (text, length);
|
string* strp = new string (text, length);
|
||||||
m_stringps.push_back(strp);
|
m_stringps.push_back(strp);
|
||||||
return strp;
|
return strp;
|
||||||
@@ -307,7 +307,7 @@ public:
|
|||||||
void statePushVlg(); // Parser -> lexer communication
|
void statePushVlg(); // Parser -> lexer communication
|
||||||
void statePop(); // Parser -> lexer communication
|
void statePop(); // Parser -> lexer communication
|
||||||
int stateVerilogRecent(); // Parser -> lexer communication
|
int stateVerilogRecent(); // Parser -> lexer communication
|
||||||
int flexPpInputToLex(char* buf, int max_size) { return ppInputToLex(buf,max_size); }
|
size_t flexPpInputToLex(char* buf, size_t max_size) { return ppInputToLex(buf,max_size); }
|
||||||
|
|
||||||
//==== Symbol tables
|
//==== Symbol tables
|
||||||
V3ParseSym* symp() { return &m_sym; }
|
V3ParseSym* symp() { return &m_sym; }
|
||||||
|
|||||||
+83
-19
@@ -27,12 +27,17 @@
|
|||||||
#ifndef _VPREPROCLEX_H_ // Guard
|
#ifndef _VPREPROCLEX_H_ // Guard
|
||||||
#define _VPREPROCLEX_H_ 1
|
#define _VPREPROCLEX_H_ 1
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
|
||||||
#include "V3Error.h"
|
#include "V3Error.h"
|
||||||
|
|
||||||
|
//======================================================================
|
||||||
|
|
||||||
|
class V3PreProcImp;
|
||||||
|
|
||||||
// Token codes
|
// Token codes
|
||||||
// If changing, see V3Pre.cpp's V3PreImp::tokenName()
|
// If changing, see V3PreProc.cpp's V3PreProcImp::tokenName()
|
||||||
#define VP_EOF 0
|
#define VP_EOF 0
|
||||||
|
|
||||||
#define VP_INCLUDE 256
|
#define VP_INCLUDE 256
|
||||||
@@ -56,10 +61,11 @@
|
|||||||
#define VP_DEFARG 307
|
#define VP_DEFARG 307
|
||||||
#define VP_ERROR 308
|
#define VP_ERROR 308
|
||||||
#define VP_DEFFORM 309
|
#define VP_DEFFORM 309
|
||||||
|
#define VP_STRIFY 310
|
||||||
|
#define VP_BACKQUOTE 311
|
||||||
|
|
||||||
#define VP_PSL 350
|
#define VP_PSL 350
|
||||||
|
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// Externs created by flex
|
// Externs created by flex
|
||||||
// We add a prefix so that other lexers/flexers in the same program won't collide.
|
// We add a prefix so that other lexers/flexers in the same program won't collide.
|
||||||
@@ -84,6 +90,11 @@
|
|||||||
# define yyerrorf V3PreLexerrorf
|
# define yyerrorf V3PreLexerrorf
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef yyourleng
|
||||||
|
# define yyourleng V3PreLexourleng
|
||||||
|
# define yyourtext V3PreLexourtext
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef YY_BUFFER_STATE
|
#ifndef YY_BUFFER_STATE
|
||||||
struct yy_buffer_state;
|
struct yy_buffer_state;
|
||||||
typedef struct yy_buffer_state *YY_BUFFER_STATE;
|
typedef struct yy_buffer_state *YY_BUFFER_STATE;
|
||||||
@@ -92,28 +103,54 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE;
|
|||||||
|
|
||||||
extern int yylex();
|
extern int yylex();
|
||||||
extern void yyrestart(FILE*);
|
extern void yyrestart(FILE*);
|
||||||
extern char* yytext;
|
|
||||||
extern int yyleng;
|
// Accessors, because flex keeps changing the type of yyleng
|
||||||
|
extern char* yyourtext();
|
||||||
|
extern size_t yyourleng();
|
||||||
|
extern void yyourtext(const char* textp, size_t size); // Must call with static
|
||||||
|
|
||||||
YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size );
|
YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size );
|
||||||
void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer );
|
void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer );
|
||||||
void yy_delete_buffer( YY_BUFFER_STATE b );
|
void yy_delete_buffer( YY_BUFFER_STATE b );
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// Class entry for each per-lexter state
|
|
||||||
|
|
||||||
#define KEEPCMT_SUB 2
|
#define KEEPCMT_SUB 2
|
||||||
|
#define KEEPCMT_EXP 3
|
||||||
|
|
||||||
|
//======================================================================
|
||||||
|
// Entry for each file processed; a stack of entries included
|
||||||
|
|
||||||
|
class VPreStream {
|
||||||
|
public:
|
||||||
|
FileLine* m_curFilelinep; // Current processing point (see also m_tokFilelinep)
|
||||||
|
deque<string> m_buffers; // Buffer of characters to process
|
||||||
|
int m_ignNewlines; // Ignore multiline newlines
|
||||||
|
bool m_eof; // "EOF" buffer
|
||||||
|
bool m_file; // Buffer is start of new file
|
||||||
|
int m_termState; // Termination fsm
|
||||||
|
VPreStream(FileLine* fl)
|
||||||
|
: m_curFilelinep(fl), m_ignNewlines(0),
|
||||||
|
m_eof(false), m_file(false), m_termState(0) {
|
||||||
|
}
|
||||||
|
~VPreStream() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
//======================================================================
|
||||||
|
// Class entry for each per-lexer state
|
||||||
|
|
||||||
class V3PreLex {
|
class V3PreLex {
|
||||||
public: // Used only by V3PreLex.cpp and V3PreProc.cpp
|
public: // Used only by V3PreLex.cpp and V3PreProc.cpp
|
||||||
FileLine* m_curFilelinep; // Current processing point
|
V3PreProcImp* m_preimpp; // Preprocessor lexor belongs to
|
||||||
|
stack<VPreStream*> m_streampStack; // Stack of processing files
|
||||||
// Parse state
|
YY_BUFFER_STATE m_bufferState; // Flex state
|
||||||
stack<YY_BUFFER_STATE> m_bufferStack; // Stack of inserted text above current point
|
FileLine* m_tokFilelinep; // Starting position of current token
|
||||||
|
|
||||||
// State to lexer
|
// State to lexer
|
||||||
static V3PreLex* s_currentLexp; // Current lexing point
|
static V3PreLex* s_currentLexp; ///< Current lexing point
|
||||||
int m_keepComments; // Emit comments in output text
|
int m_keepComments; ///< Emit comments in output text
|
||||||
bool m_pedantic; // Obey standard; don't Substitute `error
|
int m_keepWhitespace; ///< Emit all whitespace in output text
|
||||||
|
bool m_pedantic; ///< Obey standard; don't Substitute `error
|
||||||
|
|
||||||
// State from lexer
|
// State from lexer
|
||||||
int m_formalLevel; // Parenthesis counting inside def formals
|
int m_formalLevel; // Parenthesis counting inside def formals
|
||||||
@@ -122,35 +159,62 @@ class V3PreLex {
|
|||||||
bool m_pslMoreNeeded;// Next // comment is really psl
|
bool m_pslMoreNeeded;// Next // comment is really psl
|
||||||
bool m_defCmtSlash; // /*...*/ comment in define had \ ending
|
bool m_defCmtSlash; // /*...*/ comment in define had \ ending
|
||||||
string m_defValue; // Definition value being built.
|
string m_defValue; // Definition value being built.
|
||||||
|
int m_enterExit; // For VL_LINE, the enter/exit level
|
||||||
|
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
V3PreLex() {
|
V3PreLex(V3PreProcImp* preimpp, FileLine* filelinep) {
|
||||||
|
m_preimpp = preimpp;
|
||||||
m_keepComments = 0;
|
m_keepComments = 0;
|
||||||
|
m_keepWhitespace = 1;
|
||||||
m_pedantic = false;
|
m_pedantic = false;
|
||||||
m_formalLevel = 0;
|
m_formalLevel = 0;
|
||||||
m_parenLevel = 0;
|
m_parenLevel = 0;
|
||||||
m_defCmtSlash = false;
|
m_defCmtSlash = false;
|
||||||
|
m_tokFilelinep = filelinep;
|
||||||
|
m_enterExit = 0;
|
||||||
m_pslParenLevel = 0;
|
m_pslParenLevel = 0;
|
||||||
m_pslMoreNeeded = false;
|
m_pslMoreNeeded = false;
|
||||||
|
initFirstBuffer(filelinep);
|
||||||
}
|
}
|
||||||
~V3PreLex() {
|
~V3PreLex() {
|
||||||
while (!m_bufferStack.empty()) { yy_delete_buffer(m_bufferStack.top()); m_bufferStack.pop(); }
|
while (!m_streampStack.empty()) { delete m_streampStack.top(); m_streampStack.pop(); }
|
||||||
|
yy_delete_buffer(m_bufferState); m_bufferState=NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called by V3PreLex.l from lexer
|
// Called by V3PreLex.l from lexer
|
||||||
void appendDefValue(const char* text, int len);
|
VPreStream* curStreamp() { return m_streampStack.top(); } // Can't be empty, "EOF" is on top
|
||||||
void lineDirective(const char* text);
|
FileLine* curFilelinep() { return curStreamp()->m_curFilelinep; }
|
||||||
void incLineno() { m_curFilelinep->incLineno(); }
|
void curFilelinep(FileLine* fl) { curStreamp()->m_curFilelinep = fl; }
|
||||||
|
void appendDefValue(const char* textp, size_t len) { m_defValue.append(textp,len); }
|
||||||
|
void lineDirective(const char* textp);
|
||||||
|
void linenoInc() { if (curStreamp()->m_ignNewlines) curStreamp()->m_ignNewlines--;
|
||||||
|
else curFilelinep()->linenoInc(); }
|
||||||
// Called by V3PreProc.cpp to inform lexer
|
// Called by V3PreProc.cpp to inform lexer
|
||||||
void pushStateDefArg(int level);
|
void pushStateDefArg(int level);
|
||||||
void pushStateDefForm();
|
void pushStateDefForm();
|
||||||
void pushStateDefValue();
|
void pushStateDefValue();
|
||||||
void pushStateIncFilename();
|
void pushStateIncFilename();
|
||||||
void scanBytes(const string& strg);
|
void scanNewFile(FileLine* filelinep);
|
||||||
/// Called by VPreproc.cpp to get data from lexer
|
void scanBytes(const string& str);
|
||||||
|
void scanBytesBack(const string& str);
|
||||||
|
size_t inputToLex(char* buf, size_t max_size);
|
||||||
|
/// Called by V3PreProc.cpp to get data from lexer
|
||||||
YY_BUFFER_STATE currentBuffer();
|
YY_BUFFER_STATE currentBuffer();
|
||||||
|
int lex();
|
||||||
int currentStartState();
|
int currentStartState();
|
||||||
|
void dumpSummary();
|
||||||
void dumpStack();
|
void dumpStack();
|
||||||
|
void unused();
|
||||||
|
/// Utility
|
||||||
|
static int debug();
|
||||||
|
static void debug(int level);
|
||||||
|
static string cleanDbgStrg(const string& in);
|
||||||
|
|
||||||
|
private:
|
||||||
|
string currentUnreadChars();
|
||||||
|
string endOfStream(bool& againr);
|
||||||
|
void initFirstBuffer(FileLine* filelinep);
|
||||||
|
void scanSwitchStream(VPreStream* streamp);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // Guard
|
#endif // Guard
|
||||||
|
|||||||
+251
-33
@@ -1,3 +1,8 @@
|
|||||||
|
%option noyywrap align interactive
|
||||||
|
%option stack
|
||||||
|
%option noc++
|
||||||
|
%option prefix="V3PreLex"
|
||||||
|
%{
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* DESCRIPTION: Verilator: Flex verilog preprocessor
|
* DESCRIPTION: Verilator: Flex verilog preprocessor
|
||||||
*
|
*
|
||||||
@@ -20,12 +25,6 @@
|
|||||||
* lost characters.
|
* lost characters.
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
%option noyywrap align interactive
|
|
||||||
%option stack
|
|
||||||
%option noc++
|
|
||||||
%option prefix="V3PreLex"
|
|
||||||
%{
|
|
||||||
|
|
||||||
#include "V3PreProc.h"
|
#include "V3PreProc.h"
|
||||||
#include "V3PreLex.h"
|
#include "V3PreLex.h"
|
||||||
|
|
||||||
@@ -33,13 +32,21 @@ V3PreLex* V3PreLex::s_currentLexp = NULL; // Current lexing point
|
|||||||
|
|
||||||
#define LEXP V3PreLex::s_currentLexp
|
#define LEXP V3PreLex::s_currentLexp
|
||||||
|
|
||||||
|
#define YY_INPUT(buf,result,max_size) \
|
||||||
|
result = LEXP->inputToLex(buf,max_size);
|
||||||
|
|
||||||
|
// 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; }
|
||||||
|
|
||||||
// Prevent conflicts from perl version
|
// Prevent conflicts from perl version
|
||||||
static void linenoInc() {LEXP->incLineno();}
|
static void linenoInc() {LEXP->linenoInc();}
|
||||||
static bool optPsl() { return V3PreProc::optPsl(); }
|
static bool optPsl() { return V3PreProc::optPsl(); }
|
||||||
static bool pedantic() { return LEXP->m_pedantic; }
|
static bool pedantic() { return LEXP->m_pedantic; }
|
||||||
static void yyerror(char* msg) { LEXP->m_curFilelinep->v3error(msg); }
|
static void yyerror(char* msg) { LEXP->curFilelinep()->v3error(msg); }
|
||||||
static void yyerrorf(const char* msg) { LEXP->m_curFilelinep->v3error(msg); }
|
static void yyerrorf(const char* msg) { LEXP->curFilelinep()->v3error(msg); }
|
||||||
static void appendDefValue(const char* t,int l) { LEXP->appendDefValue(t,l); }
|
static void appendDefValue(const char* t, size_t l) { LEXP->appendDefValue(t,l); }
|
||||||
static int pslParenLevel() { return LEXP->m_pslParenLevel; }
|
static int pslParenLevel() { return LEXP->m_pslParenLevel; }
|
||||||
static void pslParenLevelInc() { LEXP->m_pslParenLevel++; }
|
static void pslParenLevelInc() { LEXP->m_pslParenLevel++; }
|
||||||
static void pslParenLevelDec() { if (pslParenLevel()) LEXP->m_pslParenLevel--; }
|
static void pslParenLevelDec() { if (pslParenLevel()) LEXP->m_pslParenLevel--; }
|
||||||
@@ -71,8 +78,11 @@ ws [ \t\f\r]
|
|||||||
wsn [ \t\f]
|
wsn [ \t\f]
|
||||||
crnl [\r]*[\n]
|
crnl [\r]*[\n]
|
||||||
quote [\"]
|
quote [\"]
|
||||||
|
tickquote [`][\"]
|
||||||
backslash [\\]
|
backslash [\\]
|
||||||
symb ([a-zA-Z_][a-zA-Z0-9_$]*|\\[^ \t\f\r\n]+)
|
symb ([a-zA-Z_][a-zA-Z0-9_$]*|\\[^ \t\f\r\n]+)
|
||||||
|
symbdef ([a-zA-Z_][a-zA-Z0-9_$]*|\\[^ \t\f\r\n`]+)
|
||||||
|
word [a-zA-Z0-9_]+
|
||||||
drop [\032]
|
drop [\032]
|
||||||
psl [p]sl
|
psl [p]sl
|
||||||
|
|
||||||
@@ -95,11 +105,11 @@ psl [p]sl
|
|||||||
|
|
||||||
/* Optional directives we recognize */
|
/* Optional directives we recognize */
|
||||||
<INITIAL>"`__FILE__" { static string rtnfile;
|
<INITIAL>"`__FILE__" { static string rtnfile;
|
||||||
rtnfile = '"'; rtnfile += LEXP->m_curFilelinep->filename().c_str();
|
rtnfile = '"'; rtnfile += LEXP->curFilelinep()->filename().c_str();
|
||||||
rtnfile += '"'; yytext=(char*)rtnfile.c_str(); yyleng = rtnfile.length();
|
rtnfile += '"'; yytext=(char*)rtnfile.c_str(); yyleng = rtnfile.length();
|
||||||
return (VP_STRING); }
|
return (VP_STRING); }
|
||||||
<INITIAL>"`__LINE__" { static char buf[10];
|
<INITIAL>"`__LINE__" { static char buf[10];
|
||||||
sprintf(buf, "%d",LEXP->m_curFilelinep->lineno());
|
sprintf(buf, "%d",LEXP->curFilelinep()->lineno());
|
||||||
yytext = buf; yyleng = strlen(yytext);
|
yytext = buf; yyleng = strlen(yytext);
|
||||||
return (VP_TEXT); }
|
return (VP_TEXT); }
|
||||||
<INITIAL>"`error" { if (!pedantic()) return (VP_ERROR); else return(VP_DEFREF); }
|
<INITIAL>"`error" { if (!pedantic()) return (VP_ERROR); else return(VP_DEFREF); }
|
||||||
@@ -108,6 +118,7 @@ psl [p]sl
|
|||||||
<INITIAL,PSLMULM,PSLONEM>{quote} { yy_push_state(STRMODE); yymore(); }
|
<INITIAL,PSLMULM,PSLONEM>{quote} { yy_push_state(STRMODE); yymore(); }
|
||||||
<STRMODE><<EOF>> { linenoInc(); yyerrorf("EOF in unterminated string"); yyleng=0; yyterminate(); }
|
<STRMODE><<EOF>> { linenoInc(); yyerrorf("EOF in unterminated string"); yyleng=0; yyterminate(); }
|
||||||
<STRMODE>{crnl} { linenoInc(); yyerrorf("Unterminated string"); BEGIN(INITIAL); }
|
<STRMODE>{crnl} { linenoInc(); yyerrorf("Unterminated string"); BEGIN(INITIAL); }
|
||||||
|
<STRMODE>{word} { yymore(); }
|
||||||
<STRMODE>[^\"\\] { yymore(); }
|
<STRMODE>[^\"\\] { yymore(); }
|
||||||
<STRMODE>{backslash}{crnl} { linenoInc(); yymore(); }
|
<STRMODE>{backslash}{crnl} { linenoInc(); yymore(); }
|
||||||
<STRMODE>{backslash}. { yymore(); }
|
<STRMODE>{backslash}. { yymore(); }
|
||||||
@@ -115,6 +126,10 @@ psl [p]sl
|
|||||||
if (LEXP->m_parenLevel || LEXP->m_formalLevel) { appendDefValue(yytext,yyleng); yyleng=0; }
|
if (LEXP->m_parenLevel || LEXP->m_formalLevel) { appendDefValue(yytext,yyleng); yyleng=0; }
|
||||||
else return (VP_STRING); }
|
else return (VP_STRING); }
|
||||||
|
|
||||||
|
/* Stringification */
|
||||||
|
<INITIAL>{tickquote} { return VP_STRIFY; }
|
||||||
|
<INITIAL>"`\\`\"" { return VP_BACKQUOTE; }
|
||||||
|
|
||||||
/* Protected blocks */
|
/* Protected blocks */
|
||||||
<INITIAL>"`protected" { yy_push_state(PRTMODE); yymore(); }
|
<INITIAL>"`protected" { yy_push_state(PRTMODE); yymore(); }
|
||||||
<PRTMODE><<EOF>> { linenoInc(); yyerrorf("EOF in `protected"); yyleng=0; yyterminate(); }
|
<PRTMODE><<EOF>> { linenoInc(); yyerrorf("EOF in `protected"); yyleng=0; yyterminate(); }
|
||||||
@@ -136,7 +151,7 @@ psl [p]sl
|
|||||||
<DEFFPAR><<EOF>> { yy_pop_state(); return VP_DEFFORM; } /* empty formals */
|
<DEFFPAR><<EOF>> { yy_pop_state(); return VP_DEFFORM; } /* empty formals */
|
||||||
<DEFFPAR>. { yy_pop_state(); unput(yytext[yyleng-1]); yyleng=0; return VP_DEFFORM; } /* empty formals */
|
<DEFFPAR>. { yy_pop_state(); unput(yytext[yyleng-1]); yyleng=0; return VP_DEFFORM; } /* empty formals */
|
||||||
|
|
||||||
/* Reading definition formals */
|
/* Reading definition formals (declaration of a define) */
|
||||||
<DEFFORM>[(] { appendDefValue(yytext,yyleng); yyleng=0; ++LEXP->m_formalLevel; }
|
<DEFFORM>[(] { appendDefValue(yytext,yyleng); yyleng=0; ++LEXP->m_formalLevel; }
|
||||||
<DEFFORM>[)] { appendDefValue(yytext,yyleng); yyleng=0; if ((--LEXP->m_formalLevel)==0) { yy_pop_state(); return VP_DEFFORM; } }
|
<DEFFORM>[)] { appendDefValue(yytext,yyleng); yyleng=0; if ((--LEXP->m_formalLevel)==0) { yy_pop_state(); return VP_DEFFORM; } }
|
||||||
<DEFFORM>"/*" { yy_push_state(CMTMODE); yymore(); }
|
<DEFFORM>"/*" { yy_push_state(CMTMODE); yymore(); }
|
||||||
@@ -144,21 +159,24 @@ psl [p]sl
|
|||||||
<DEFFORM>{drop} { }
|
<DEFFORM>{drop} { }
|
||||||
<DEFFORM><<EOF>> { linenoInc(); yy_pop_state(); yyerrorf("Unterminated ( in define formal arguments."); yyleng=0; return VP_DEFFORM; }
|
<DEFFORM><<EOF>> { linenoInc(); yy_pop_state(); yyerrorf("Unterminated ( in define formal arguments."); yyleng=0; return VP_DEFFORM; }
|
||||||
<DEFFORM>{crnl} { linenoInc(); appendDefValue((char*)"\n",1); } /* Include return so can maintain output line count */
|
<DEFFORM>{crnl} { linenoInc(); appendDefValue((char*)"\n",1); } /* Include return so can maintain output line count */
|
||||||
<DEFFORM>[\\]{crnl} { linenoInc(); appendDefValue((char*)"\n",1); } /* Include return so can maintain output line count */
|
<DEFFORM>[\\]{crnl} { linenoInc(); appendDefValue((char*)"\\\n",2); } /* Include return so can maintain output line count */
|
||||||
<DEFFORM>{quote} { yy_push_state(STRMODE); yymore(); }
|
<DEFFORM>{quote} { yy_push_state(STRMODE); yymore(); } /* Legal only in default values */
|
||||||
|
<DEFFORM>"`\\`\"" { appendDefValue(yytext,yyleng); } /* Maybe illegal, otherwise in default value */
|
||||||
|
<DEFFORM>{tickquote} { appendDefValue(yytext,yyleng); } /* Maybe illegal, otherwise in default value */
|
||||||
<DEFFORM>[{\[] { LEXP->m_formalLevel++; appendDefValue(yytext,yyleng); }
|
<DEFFORM>[{\[] { LEXP->m_formalLevel++; appendDefValue(yytext,yyleng); }
|
||||||
<DEFFORM>[}\]] { LEXP->m_formalLevel--; appendDefValue(yytext,yyleng); }
|
<DEFFORM>[}\]] { LEXP->m_formalLevel--; appendDefValue(yytext,yyleng); }
|
||||||
<DEFFORM>[^\/\*\n\r\\(){}\[\]\"]+ |
|
<DEFFORM>[^\/\*\n\r\\(){}\[\]\"]+ |
|
||||||
<DEFFORM>[\\][^\n\r] |
|
<DEFFORM>[\\][^\n\r] |
|
||||||
<DEFFORM>. { appendDefValue(yytext,yyleng); }
|
<DEFFORM>. { appendDefValue(yytext,yyleng); }
|
||||||
|
|
||||||
/* Reading definition value */
|
/* Reading definition value (declaration of a define's text) */
|
||||||
<DEFVAL>"/*" { LEXP->m_defCmtSlash=false; yy_push_state(DEFCMT); yymore(); } /* Special comment parser */
|
<DEFVAL>"/*" { LEXP->m_defCmtSlash=false; yy_push_state(DEFCMT); yymore(); } /* Special comment parser */
|
||||||
|
<DEFVAL>"//"[^\n\r]*[\\]{crnl} { linenoInc(); appendDefValue((char*)"\n",1); } /* Spec says // not part of define value */
|
||||||
<DEFVAL>"//"[^\n\r]* { return (VP_COMMENT);}
|
<DEFVAL>"//"[^\n\r]* { return (VP_COMMENT);}
|
||||||
<DEFVAL>{drop} { }
|
<DEFVAL>{drop} { }
|
||||||
<DEFVAL><<EOF>> { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); } /* Technically illegal, but people complained */
|
<DEFVAL><<EOF>> { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); } /* Technically illegal, but people complained */
|
||||||
<DEFVAL>{crnl} { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); }
|
<DEFVAL>{crnl} { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); }
|
||||||
<DEFVAL>[\\]{crnl} { linenoInc(); appendDefValue((char*)"\n",1); } /* Return, but not \ is part of define value */
|
<DEFVAL>[\\]{crnl} { linenoInc(); appendDefValue((char*)"\\\n",2); } /* Return, AND \ is part of define value */
|
||||||
<DEFVAL>[^\/\*\n\r\\]+ |
|
<DEFVAL>[^\/\*\n\r\\]+ |
|
||||||
<DEFVAL>[\\][^\n\r] |
|
<DEFVAL>[\\][^\n\r] |
|
||||||
<DEFVAL>. { appendDefValue(yytext,yyleng); }
|
<DEFVAL>. { appendDefValue(yytext,yyleng); }
|
||||||
@@ -171,16 +189,19 @@ psl [p]sl
|
|||||||
appendDefValue(yytext,yyleng-2); appendDefValue((char*)"\n",1); } /* Return but not \ */
|
appendDefValue(yytext,yyleng-2); appendDefValue((char*)"\n",1); } /* Return but not \ */
|
||||||
<DEFCMT>{crnl} { linenoInc(); yymore(); if (LEXP->m_defCmtSlash) yyerrorf("One line of /* ... */ is missing \\ before newline");
|
<DEFCMT>{crnl} { linenoInc(); yymore(); if (LEXP->m_defCmtSlash) yyerrorf("One line of /* ... */ is missing \\ before newline");
|
||||||
BEGIN(CMTMODE); }
|
BEGIN(CMTMODE); }
|
||||||
|
<DEFCMT>{word} { yymore(); }
|
||||||
<DEFCMT>. { yymore(); }
|
<DEFCMT>. { yymore(); }
|
||||||
<DEFCMT><<EOF>> { yyerrorf("EOF in '/* ... */' block comment\n"); yyleng=0; yyterminate(); }
|
<DEFCMT><<EOF>> { yyerrorf("EOF in '/* ... */' block comment\n"); yyleng=0; yyterminate(); }
|
||||||
|
|
||||||
/* Define arguments */
|
/* Define arguments (use of a define) */
|
||||||
<ARGMODE>"/*" { yy_push_state(CMTMODE); yymore(); }
|
<ARGMODE>"/*" { yy_push_state(CMTMODE); yymore(); }
|
||||||
<ARGMODE>"//"[^\n\r]* { return (VP_COMMENT);}
|
<ARGMODE>"//"[^\n\r]* { return (VP_COMMENT);}
|
||||||
<ARGMODE>{drop} { }
|
<ARGMODE>{drop} { }
|
||||||
<ARGMODE><<EOF>> { yyerrorf("EOF in define argument list\n"); yyleng = 0; yyterminate(); }
|
<ARGMODE><<EOF>> { yyerrorf("EOF in define argument list\n"); yyleng = 0; yyterminate(); }
|
||||||
<ARGMODE>{crnl} { linenoInc(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); }
|
<ARGMODE>{crnl} { linenoInc(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); }
|
||||||
<ARGMODE>{quote} { yy_push_state(STRMODE); yymore(); }
|
<ARGMODE>{quote} { yy_push_state(STRMODE); yymore(); }
|
||||||
|
<ARGMODE>"`\\`\"" { appendDefValue(yytext,yyleng); } /* Literal text */
|
||||||
|
<ARGMODE>{tickquote} { return(VP_STRIFY); }
|
||||||
<ARGMODE>[{\[] { LEXP->m_parenLevel++; appendDefValue(yytext,yyleng); }
|
<ARGMODE>[{\[] { LEXP->m_parenLevel++; appendDefValue(yytext,yyleng); }
|
||||||
<ARGMODE>[}\]] { LEXP->m_parenLevel--; appendDefValue(yytext,yyleng); }
|
<ARGMODE>[}\]] { LEXP->m_parenLevel--; appendDefValue(yytext,yyleng); }
|
||||||
<ARGMODE>[(] { LEXP->m_parenLevel++;
|
<ARGMODE>[(] { LEXP->m_parenLevel++;
|
||||||
@@ -203,7 +224,7 @@ psl [p]sl
|
|||||||
} else {
|
} else {
|
||||||
yy_pop_state(); return (VP_DEFARG);
|
yy_pop_state(); return (VP_DEFARG);
|
||||||
}}
|
}}
|
||||||
<ARGMODE>"`"{symb} { return (VP_DEFREF); } /* defref in defref */
|
<ARGMODE>"`"{symbdef} { appendDefValue(yytext,yyleng); } /* defref in defref - outer macro expands first */
|
||||||
<ARGMODE>[^\/\*\n\r\\(,){}\[\]\"`]+ |
|
<ARGMODE>[^\/\*\n\r\\(,){}\[\]\"`]+ |
|
||||||
<ARGMODE>. { appendDefValue(yytext,yyleng); }
|
<ARGMODE>. { appendDefValue(yytext,yyleng); }
|
||||||
|
|
||||||
@@ -235,6 +256,7 @@ psl [p]sl
|
|||||||
<CMTBEGM,CMTMODE>"*/" { yy_pop_state(); return(VP_COMMENT); }
|
<CMTBEGM,CMTMODE>"*/" { yy_pop_state(); return(VP_COMMENT); }
|
||||||
<CMTBEGM,CMTMODE>{crnl} { linenoInc(); yymore(); }
|
<CMTBEGM,CMTMODE>{crnl} { linenoInc(); yymore(); }
|
||||||
<CMTBEGM,CMTMODE><<EOF>> { yyerrorf("EOF in '/* ... */' block comment\n"); yyleng=0; yyterminate(); }
|
<CMTBEGM,CMTMODE><<EOF>> { yyerrorf("EOF in '/* ... */' block comment\n"); yyleng=0; yyterminate(); }
|
||||||
|
<CMTMODE>{word} { yymore(); }
|
||||||
<CMTBEGM>. { BEGIN CMTMODE; yymore(); } /* Non 'psl' beginning in comment */
|
<CMTBEGM>. { BEGIN CMTMODE; yymore(); } /* Non 'psl' beginning in comment */
|
||||||
<CMTMODE>. { yymore(); }
|
<CMTMODE>. { yymore(); }
|
||||||
|
|
||||||
@@ -245,7 +267,8 @@ psl [p]sl
|
|||||||
<PSLMULM>"//"[^\n\r]* { return (VP_COMMENT); } /* Comments inside block comments get literal inclusion (later removal) */
|
<PSLMULM>"//"[^\n\r]* { return (VP_COMMENT); } /* Comments inside block comments get literal inclusion (later removal) */
|
||||||
|
|
||||||
/* Define calls */
|
/* Define calls */
|
||||||
<INITIAL,PSLMULM,PSLONEM>"`"{symb} { return (VP_DEFREF); }
|
/* symbdef prevents normal lex rules from makeing `\`"foo a symbol {`"foo} instead of a BACKQUOTE */
|
||||||
|
<INITIAL,PSLMULM,PSLONEM>"`"{symbdef} { return (VP_DEFREF); }
|
||||||
|
|
||||||
/* Generics */
|
/* Generics */
|
||||||
<INITIAL,PSLMULM>{crnl} { linenoInc(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); }
|
<INITIAL,PSLMULM>{crnl} { linenoInc(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); }
|
||||||
@@ -284,14 +307,177 @@ void V3PreLex::pushStateIncFilename() {
|
|||||||
yymore();
|
yymore();
|
||||||
}
|
}
|
||||||
|
|
||||||
void V3PreLex::scanBytes(const string& strg) {
|
void V3PreLex::debug(int level) { yy_flex_debug=level; }
|
||||||
yy_scan_bytes(strg.c_str(), strg.length());
|
int V3PreLex::debug() { return yy_flex_debug; }
|
||||||
m_bufferStack.push(currentBuffer()); // yy_scan_bytes makes new buffer
|
|
||||||
|
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
|
||||||
|
return yylex();
|
||||||
}
|
}
|
||||||
|
|
||||||
void V3PreLex::appendDefValue(const char* textp, int len) {
|
size_t V3PreLex::inputToLex(char* buf, size_t max_size) {
|
||||||
// Append given text to current definition value being formed
|
// We need a custom YY_INPUT because we can't use flex buffers.
|
||||||
m_defValue.append(textp,len);
|
// Flex buffers are limited to 2GB, and we can't chop into 2G pieces
|
||||||
|
// because buffers can't end in the middle of tokens.
|
||||||
|
// Note if we switched streams here (which we don't) "buf" would be
|
||||||
|
// become a stale invalid pointer.
|
||||||
|
//
|
||||||
|
VPreStream* streamp = curStreamp();
|
||||||
|
if (debug()>=10) { 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:
|
||||||
|
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();
|
||||||
|
size_t len = front.length();
|
||||||
|
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);
|
||||||
|
got += len;
|
||||||
|
}
|
||||||
|
if (!got) { // end of stream; try "above" file
|
||||||
|
bool again=false;
|
||||||
|
string forceOut = endOfStream(again/*ref*/);
|
||||||
|
streamp = curStreamp(); // May have been updated
|
||||||
|
if (forceOut != "") {
|
||||||
|
if (forceOut.length() > max_size) {
|
||||||
|
yyerrorf("Output buffer too small for a `line");
|
||||||
|
} else {
|
||||||
|
got = forceOut.length();
|
||||||
|
strncpy(buf, forceOut.c_str(), got);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (streamp->m_eof) {
|
||||||
|
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; }
|
||||||
|
return got;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
if (curStreamp()->m_eof) return ""; // Don't delete the final "EOF" stream
|
||||||
|
bool exited_file = curStreamp()->m_file;
|
||||||
|
if (!exited_file) {
|
||||||
|
// Midpoint of stream, just change buffers
|
||||||
|
delete curStreamp();
|
||||||
|
m_streampStack.pop(); // Must work as size>1; EOF is entry 0
|
||||||
|
againr = true;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
// Multiple steps because we need FLEX to see ending \n and EOS to end
|
||||||
|
// any illegal states, like an unterminated `protected region
|
||||||
|
else if (!curStreamp()->m_termState) {
|
||||||
|
// First shutdown phase for a file
|
||||||
|
// Terminate all files with a newline. This prevents problems if
|
||||||
|
// the user had a define without a terminating newline,
|
||||||
|
// otherwise the resumed file's next line would get tacked on.
|
||||||
|
// Also makes it likely the `line that changes files comes out
|
||||||
|
// immediately.
|
||||||
|
curStreamp()->m_termState = 1;
|
||||||
|
return "\n"; // Exit old file
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
// Now ending `line
|
||||||
|
curStreamp()->m_termState = 3;
|
||||||
|
return curFilelinep()->lineDirectiveStrg(2); // Exit old file
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Final shutdown phase for a stream, we can finally change the
|
||||||
|
// current fileline to the new stream
|
||||||
|
curStreamp()->m_termState = 0;
|
||||||
|
FileLine* filelinep = curFilelinep();
|
||||||
|
delete curStreamp();
|
||||||
|
m_streampStack.pop(); // Must work as size>1; EOF is entry 0
|
||||||
|
if (curStreamp()->m_eof) {
|
||||||
|
// EOF doesn't have a "real" fileline, but a linenumber of 0 from init time
|
||||||
|
// Inherit whatever we last parsed so it's more obvious.
|
||||||
|
curFilelinep(filelinep);
|
||||||
|
}
|
||||||
|
// The caller parser remembered the start location for the text we are parsing,
|
||||||
|
// but we've discovered there was a file switch along the way, so update it.
|
||||||
|
m_tokFilelinep = curFilelinep();
|
||||||
|
//
|
||||||
|
if (curStreamp()->m_eof) {
|
||||||
|
return "";
|
||||||
|
} else {
|
||||||
|
return curFilelinep()->lineDirectiveStrg(0); // Reenter resumed file
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void V3PreLex::initFirstBuffer(FileLine* filelinep) {
|
||||||
|
// Called from constructor to make first buffer
|
||||||
|
// yy_create_buffer also sets yy_fill_buffer=1 so reads from YY_INPUT
|
||||||
|
VPreStream* streamp = new VPreStream(filelinep);
|
||||||
|
streamp->m_eof = true;
|
||||||
|
m_streampStack.push(streamp);
|
||||||
|
//
|
||||||
|
m_bufferState = yy_create_buffer(NULL, YY_BUF_SIZE);
|
||||||
|
yy_switch_to_buffer(m_bufferState);
|
||||||
|
yyrestart(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void V3PreLex::scanNewFile(FileLine* filelinep) {
|
||||||
|
// Called on new open file. scanBytesBack will be called next.
|
||||||
|
VPreStream* streamp = new VPreStream(filelinep);
|
||||||
|
m_tokFilelinep = curFilelinep();
|
||||||
|
streamp->m_file = true;
|
||||||
|
scanSwitchStream(streamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void V3PreLex::scanBytes(const string& str) {
|
||||||
|
// Note buffers also appended in ::scanBytesBack
|
||||||
|
// Not "m_buffers.push_front(string(strp,len))" as we need a `define
|
||||||
|
// to take effect immediately, in the middle of the current buffer
|
||||||
|
// Also we don't use scan_bytes that would set yy_fill_buffer
|
||||||
|
// which would force Flex to bypass our YY_INPUT routine.
|
||||||
|
VPreStream* streamp = new VPreStream(curFilelinep());
|
||||||
|
streamp->m_buffers.push_front(str);
|
||||||
|
scanSwitchStream(streamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void V3PreLex::scanSwitchStream(VPreStream* streamp) {
|
||||||
|
curStreamp()->m_buffers.push_front(currentUnreadChars());
|
||||||
|
m_streampStack.push(streamp);
|
||||||
|
yyrestart(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void V3PreLex::scanBytesBack(const string& str) {
|
||||||
|
// Initial creation, that will pull from YY_INPUT==inputToLex
|
||||||
|
// Note buffers also appended in ::scanBytes
|
||||||
|
if (curStreamp()->m_eof) yyerrorf("scanBytesBack without being under scanNewFile");
|
||||||
|
curStreamp()->m_buffers.push_back(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
string V3PreLex::currentUnreadChars() {
|
||||||
|
// WARNING - Peeking at internals
|
||||||
|
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);
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
YY_BUFFER_STATE V3PreLex::currentBuffer() {
|
YY_BUFFER_STATE V3PreLex::currentBuffer() {
|
||||||
@@ -303,22 +489,54 @@ int V3PreLex::currentStartState() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void V3PreLex::lineDirective(const char* textp) {
|
void V3PreLex::lineDirective(const char* textp) {
|
||||||
m_curFilelinep->lineDirective(textp);
|
curFilelinep()->lineDirective(textp, m_enterExit/*ref*/);
|
||||||
// Make sure we have a dependency on whatever file was specified
|
// Make sure we have a dependency on whatever file was specified
|
||||||
V3File::addSrcDepend(m_curFilelinep->filename());
|
V3File::addSrcDepend(curFilelinep()->filename());
|
||||||
|
}
|
||||||
|
|
||||||
|
void V3PreLex::dumpSummary() {
|
||||||
|
cout<<"- pp::dumpSummary curBuf="<<(void*)(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="<<dec<<left;
|
||||||
|
#endif
|
||||||
|
cout<<endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void V3PreLex::dumpStack() {
|
void V3PreLex::dumpStack() {
|
||||||
// For debug use
|
// For debug use
|
||||||
stack<YY_BUFFER_STATE> tmpstack = m_bufferStack;
|
dumpSummary();
|
||||||
printf(" bufferStack[%p]:",this);
|
stack<VPreStream*> tmpstack = LEXP->m_streampStack;
|
||||||
while (!tmpstack.empty()) {
|
while (!tmpstack.empty()) {
|
||||||
printf(" %p",tmpstack.top());
|
VPreStream* streamp = tmpstack.top();
|
||||||
|
cout<<"- bufferStack["<<(void*)(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;
|
||||||
tmpstack.pop();
|
tmpstack.pop();
|
||||||
}
|
}
|
||||||
printf("\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string V3PreLex::cleanDbgStrg(const string& in) {
|
||||||
|
string out = in;
|
||||||
|
string::size_type pos;
|
||||||
|
while ((pos=out.find("\n")) != string::npos) { out.replace(pos, 1, "\\n"); }
|
||||||
|
while ((pos=out.find("\r")) != string::npos) { out.replace(pos, 1, "\\r"); }
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void V3PreLex::unused() {
|
||||||
|
if (0) {
|
||||||
|
// Prevent unused warnings
|
||||||
|
yy_top_state();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*###################################################################
|
/*###################################################################
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* mode: C++
|
* mode: C++
|
||||||
|
|||||||
+472
-244
File diff suppressed because it is too large
Load Diff
+14
-5
@@ -29,8 +29,12 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <list>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
// Compatibility with Verilog-Perl's preprocessor
|
||||||
|
#define fatalSrc(msg) v3fatalSrc(msg)
|
||||||
|
|
||||||
class V3InFilter;
|
class V3InFilter;
|
||||||
|
|
||||||
class V3PreProc {
|
class V3PreProc {
|
||||||
@@ -39,14 +43,14 @@ class V3PreProc {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
// STATE
|
// STATE
|
||||||
FileLine* m_fileline; // Last token's starting point
|
|
||||||
int m_debug; // Debugging
|
int m_debug; // Debugging
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTANTS
|
// CONSTANTS
|
||||||
enum MiscConsts {
|
enum MiscConsts {
|
||||||
DEFINE_RECURSION_LEVEL_MAX = 50, // How many `def substitutions before an error
|
DEFINE_RECURSION_LEVEL_MAX = 50, // How many `def substitutions before an error
|
||||||
INCLUDE_DEPTH_MAX = 500 // How many `includes deep before an error
|
INCLUDE_DEPTH_MAX = 500, // How many `includes deep before an error
|
||||||
|
NEWLINES_VS_TICKLINE = 20 // Use `line in place of this many newlines
|
||||||
};
|
};
|
||||||
|
|
||||||
// ACCESSORS
|
// ACCESSORS
|
||||||
@@ -59,11 +63,12 @@ public:
|
|||||||
int debug() const { return m_debug; }
|
int debug() const { return m_debug; }
|
||||||
void debug(int level) { m_debug = level; }
|
void debug(int level) { m_debug = level; }
|
||||||
|
|
||||||
FileLine* fileline() { return m_fileline; } // File/Line number for last getline call
|
FileLine* fileline(); ///< File/Line number for last getline call
|
||||||
|
|
||||||
// CONTROL METHODS
|
// CONTROL METHODS
|
||||||
// These options control how the parsing proceeds
|
// These options control how the parsing proceeds
|
||||||
int keepComments() { return 2; } // Return comments, 0=no, 1=yes, 2=callback
|
int keepComments() { return 2; } // Return comments, 0=no, 1=yes, 2=callback
|
||||||
|
bool keepWhitespace() { return false; }
|
||||||
bool lineDirectives() { return true; } // Insert `line directives
|
bool lineDirectives() { return true; } // Insert `line directives
|
||||||
bool pedantic() { return false; } // Obey standard; Don't substitute `error
|
bool pedantic() { return false; } // Obey standard; Don't substitute `error
|
||||||
static bool optPsl();
|
static bool optPsl();
|
||||||
@@ -82,12 +87,16 @@ public:
|
|||||||
}
|
}
|
||||||
virtual string removeDefines(const string& text)=0; // Remove defines in a text string
|
virtual string removeDefines(const string& text)=0; // Remove defines in a text string
|
||||||
|
|
||||||
|
// UTILITIES
|
||||||
|
void error(string msg) { fileline()->v3error(msg); } ///< Report a error
|
||||||
|
void fatal(string msg) { fileline()->v3fatalSrc(msg); } ///< Report a fatal error
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// CONSTUCTORS
|
// CONSTUCTORS
|
||||||
V3PreProc(FileLine* fl) {
|
V3PreProc() {
|
||||||
m_fileline=fl;
|
|
||||||
m_debug=0;
|
m_debug=0;
|
||||||
};
|
};
|
||||||
|
void configure(FileLine* fl);
|
||||||
public:
|
public:
|
||||||
static V3PreProc* createPreProc(FileLine* fileline);
|
static V3PreProc* createPreProc(FileLine* fileline);
|
||||||
virtual ~V3PreProc() {}
|
virtual ~V3PreProc() {}
|
||||||
|
|||||||
+7
-2
@@ -48,9 +48,12 @@ protected:
|
|||||||
//---------------------------------------
|
//---------------------------------------
|
||||||
// METHODS
|
// METHODS
|
||||||
|
|
||||||
static int debug() {
|
static int debug(bool reset=false) {
|
||||||
static int level = -1;
|
static int level = -1;
|
||||||
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
|
if (VL_UNLIKELY(level < 0) || reset) {
|
||||||
|
level = v3Global.opt.debugSrcLevel(__FILE__);
|
||||||
|
if (s_preprocp) s_preprocp->debug(debug());
|
||||||
|
}
|
||||||
return level;
|
return level;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,6 +75,8 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void preproc (FileLine* fl, const string& modname, V3InFilter* filterp, V3ParseImp* parsep) {
|
void preproc (FileLine* fl, const string& modname, V3InFilter* filterp, V3ParseImp* parsep) {
|
||||||
|
debug(true); // Recheck if debug on - first check was before command line passed
|
||||||
|
|
||||||
// Preprocess the given module, putting output in vppFilename
|
// Preprocess the given module, putting output in vppFilename
|
||||||
UINFONL(1," Preprocessing "<<modname<<endl);
|
UINFONL(1," Preprocessing "<<modname<<endl);
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -170,6 +170,7 @@ private:
|
|||||||
m_inWhilep = NULL;
|
m_inWhilep = NULL;
|
||||||
startStatement(nodep);
|
startStatement(nodep);
|
||||||
nodep->bodysp()->iterateAndNext(*this);
|
nodep->bodysp()->iterateAndNext(*this);
|
||||||
|
nodep->incsp()->iterateAndNext(*this);
|
||||||
m_stmtp = NULL;
|
m_stmtp = NULL;
|
||||||
}
|
}
|
||||||
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
||||||
@@ -195,9 +196,8 @@ private:
|
|||||||
}
|
}
|
||||||
void visitShift (AstNodeBiop* nodep) {
|
void visitShift (AstNodeBiop* nodep) {
|
||||||
// Shifts of > 32/64 bits in C++ will wrap-around and generate non-0s
|
// Shifts of > 32/64 bits in C++ will wrap-around and generate non-0s
|
||||||
if (!nodep->user2()) {
|
if (!nodep->user2Inc()) {
|
||||||
UINFO(4," ShiftFix "<<nodep<<endl);
|
UINFO(4," ShiftFix "<<nodep<<endl);
|
||||||
nodep->user2(true);
|
|
||||||
if (nodep->widthMin()<=64 // Else we'll use large operators which work right
|
if (nodep->widthMin()<=64 // Else we'll use large operators which work right
|
||||||
// C operator's width must be < maximum shift which is based on Verilog width
|
// C operator's width must be < maximum shift which is based on Verilog width
|
||||||
&& nodep->width() < (1LL<<nodep->rhsp()->widthMin())) {
|
&& nodep->width() < (1LL<<nodep->rhsp()->widthMin())) {
|
||||||
|
|||||||
@@ -165,6 +165,14 @@ private:
|
|||||||
m_scopep->addActivep(clonep);
|
m_scopep->addActivep(clonep);
|
||||||
clonep->iterateChildren(*this); // We iterate under the *clone*
|
clonep->iterateChildren(*this); // We iterate under the *clone*
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
|
||||||
|
// Add to list of blocks under this scope
|
||||||
|
UINFO(4," Move "<<nodep<<endl);
|
||||||
|
AstNode* clonep = nodep->cloneTree(false);
|
||||||
|
nodep->user2p(clonep);
|
||||||
|
m_scopep->addActivep(clonep);
|
||||||
|
clonep->iterateChildren(*this); // We iterate under the *clone*
|
||||||
|
}
|
||||||
virtual void visit(AstCoverToggle* nodep, AstNUser*) {
|
virtual void visit(AstCoverToggle* nodep, AstNUser*) {
|
||||||
// Add to list of blocks under this scope
|
// Add to list of blocks under this scope
|
||||||
UINFO(4," Move "<<nodep<<endl);
|
UINFO(4," Move "<<nodep<<endl);
|
||||||
@@ -291,6 +299,9 @@ private:
|
|||||||
virtual void visit(AstAlways* nodep, AstNUser*) {
|
virtual void visit(AstAlways* nodep, AstNUser*) {
|
||||||
movedDeleteOrIterate(nodep);
|
movedDeleteOrIterate(nodep);
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
|
||||||
|
movedDeleteOrIterate(nodep);
|
||||||
|
}
|
||||||
virtual void visit(AstCoverToggle* nodep, AstNUser*) {
|
virtual void visit(AstCoverToggle* nodep, AstNUser*) {
|
||||||
movedDeleteOrIterate(nodep);
|
movedDeleteOrIterate(nodep);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ private:
|
|||||||
|
|
||||||
//=======
|
//=======
|
||||||
// These have proper signedness set when they were created.
|
// These have proper signedness set when they were created.
|
||||||
|
virtual void visit(AstReturn* nodep, AstNUser*) { nodep->iterateChildren(*this); }
|
||||||
virtual void visit(AstNodeDType* nodep, AstNUser*) { nodep->iterateChildren(*this); }
|
virtual void visit(AstNodeDType* nodep, AstNUser*) { nodep->iterateChildren(*this); }
|
||||||
|
|
||||||
// Inherit from others
|
// Inherit from others
|
||||||
|
|||||||
+60
-8
@@ -88,6 +88,7 @@ private:
|
|||||||
bool m_inDlyAssign; ///< Under delayed assignment
|
bool m_inDlyAssign; ///< Under delayed assignment
|
||||||
int m_instrCount; ///< Number of nodes
|
int m_instrCount; ///< Number of nodes
|
||||||
int m_dataCount; ///< Bytes of data
|
int m_dataCount; ///< Bytes of data
|
||||||
|
AstJumpGo* m_jumpp; ///< Jump label we're branching from
|
||||||
// Simulating:
|
// Simulating:
|
||||||
deque<V3Number*> m_numFreeps; ///< List of all numbers free and not in use
|
deque<V3Number*> m_numFreeps; ///< List of all numbers free and not in use
|
||||||
deque<V3Number*> m_numAllps; ///< List of all numbers free and in use
|
deque<V3Number*> m_numAllps; ///< List of all numbers free and in use
|
||||||
@@ -230,8 +231,14 @@ private:
|
|||||||
: v3Global.opt.unrollCount();
|
: v3Global.opt.unrollCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool jumpingOver(AstNode* nodep) {
|
||||||
|
// True to jump over this node - all visitors must call this up front
|
||||||
|
return (m_jumpp && m_jumpp->labelp()!=nodep);
|
||||||
|
}
|
||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
virtual void visit(AstAlways* nodep, AstNUser*) {
|
virtual void visit(AstAlways* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
checkNodeInfo(nodep);
|
checkNodeInfo(nodep);
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
}
|
}
|
||||||
@@ -239,6 +246,7 @@ private:
|
|||||||
// Sensitivities aren't inputs per se; we'll keep our tree under the same sens.
|
// Sensitivities aren't inputs per se; we'll keep our tree under the same sens.
|
||||||
}
|
}
|
||||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
if (!optimizable()) return; // Accelerate
|
if (!optimizable()) return; // Accelerate
|
||||||
AstNode* vscp = varOrScope(nodep);
|
AstNode* vscp = varOrScope(nodep);
|
||||||
|
|
||||||
@@ -285,16 +293,19 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstVarXRef* nodep, AstNUser*) {
|
virtual void visit(AstVarXRef* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
if (m_scoped) { badNodeType(nodep); return; }
|
if (m_scoped) { badNodeType(nodep); return; }
|
||||||
else { clearOptimizable(nodep,"Language violation: Dotted hierarchical references not allowed in constant functions"); }
|
else { clearOptimizable(nodep,"Language violation: Dotted hierarchical references not allowed in constant functions"); }
|
||||||
}
|
}
|
||||||
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
if (!m_params) { badNodeType(nodep); return; }
|
if (!m_params) { badNodeType(nodep); return; }
|
||||||
if (nodep->dpiImport()) { clearOptimizable(nodep,"DPI import functions aren't simulatable"); }
|
if (nodep->dpiImport()) { clearOptimizable(nodep,"DPI import functions aren't simulatable"); }
|
||||||
checkNodeInfo(nodep);
|
checkNodeInfo(nodep);
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
}
|
}
|
||||||
virtual void visit(AstNodeIf* nodep, AstNUser*) {
|
virtual void visit(AstNodeIf* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
UINFO(5," IF "<<nodep<<endl);
|
UINFO(5," IF "<<nodep<<endl);
|
||||||
checkNodeInfo(nodep);
|
checkNodeInfo(nodep);
|
||||||
if (m_checkOnly) {
|
if (m_checkOnly) {
|
||||||
@@ -364,6 +375,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
if (!optimizable()) return; // Accelerate
|
if (!optimizable()) return; // Accelerate
|
||||||
if (nodep->castAssignDly()) {
|
if (nodep->castAssignDly()) {
|
||||||
if (m_anyAssignComb) clearOptimizable(nodep, "Mix of dly/non dly assigns");
|
if (m_anyAssignComb) clearOptimizable(nodep, "Mix of dly/non dly assigns");
|
||||||
@@ -400,6 +412,7 @@ private:
|
|||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
}
|
}
|
||||||
virtual void visit(AstNodeCase* nodep, AstNUser*) {
|
virtual void visit(AstNodeCase* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
UINFO(5," CASE "<<nodep<<endl);
|
UINFO(5," CASE "<<nodep<<endl);
|
||||||
checkNodeInfo(nodep);
|
checkNodeInfo(nodep);
|
||||||
if (m_checkOnly) {
|
if (m_checkOnly) {
|
||||||
@@ -436,12 +449,30 @@ private:
|
|||||||
|
|
||||||
virtual void visit(AstCaseItem* nodep, AstNUser*) {
|
virtual void visit(AstCaseItem* nodep, AstNUser*) {
|
||||||
// Real handling is in AstNodeCase
|
// Real handling is in AstNodeCase
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
checkNodeInfo(nodep);
|
checkNodeInfo(nodep);
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void visit(AstComment*, AstNUser*) {}
|
virtual void visit(AstComment*, AstNUser*) {}
|
||||||
|
|
||||||
|
virtual void visit(AstJumpGo* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
|
checkNodeInfo(nodep);
|
||||||
|
if (!m_checkOnly) {
|
||||||
|
UINFO(5," JUMP GO "<<nodep<<endl);
|
||||||
|
m_jumpp = nodep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
virtual void visit(AstJumpLabel* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
|
checkNodeInfo(nodep);
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
if (m_jumpp && m_jumpp->labelp() == nodep) {
|
||||||
|
UINFO(5," JUMP DONE "<<nodep<<endl);
|
||||||
|
m_jumpp = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
virtual void visit(AstStop* nodep, AstNUser*) {
|
virtual void visit(AstStop* nodep, AstNUser*) {
|
||||||
if (m_params) { // This message seems better than an obscure $stop
|
if (m_params) { // This message seems better than an obscure $stop
|
||||||
// The spec says $stop is just ignored, it seems evil to ignore assertions
|
// The spec says $stop is just ignored, it seems evil to ignore assertions
|
||||||
@@ -479,6 +510,7 @@ private:
|
|||||||
|
|
||||||
virtual void visit(AstWhile* nodep, AstNUser*) {
|
virtual void visit(AstWhile* nodep, AstNUser*) {
|
||||||
// Doing lots of Whiles is slow, so only for parameters
|
// Doing lots of Whiles is slow, so only for parameters
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
UINFO(5," WHILE "<<nodep<<endl);
|
UINFO(5," WHILE "<<nodep<<endl);
|
||||||
if (!m_params) { badNodeType(nodep); return; }
|
if (!m_params) { badNodeType(nodep); return; }
|
||||||
checkNodeInfo(nodep);
|
checkNodeInfo(nodep);
|
||||||
@@ -489,12 +521,19 @@ private:
|
|||||||
while (1) {
|
while (1) {
|
||||||
UINFO(5," WHILE-ITER "<<nodep<<endl);
|
UINFO(5," WHILE-ITER "<<nodep<<endl);
|
||||||
nodep->precondsp()->iterateAndNext(*this);
|
nodep->precondsp()->iterateAndNext(*this);
|
||||||
|
if (jumpingOver(nodep)) break;
|
||||||
nodep->condp()->iterateAndNext(*this);
|
nodep->condp()->iterateAndNext(*this);
|
||||||
|
if (jumpingOver(nodep)) break;
|
||||||
if (!optimizable()) break;
|
if (!optimizable()) break;
|
||||||
if (!fetchNumber(nodep->condp())->isNeqZero()) {
|
if (!fetchNumber(nodep->condp())->isNeqZero()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
nodep->bodysp()->iterateAndNext(*this);
|
nodep->bodysp()->iterateAndNext(*this);
|
||||||
|
if (jumpingOver(nodep)) break;
|
||||||
|
nodep->incsp()->iterateAndNext(*this);
|
||||||
|
if (jumpingOver(nodep)) break;
|
||||||
|
|
||||||
|
// Prep for next loop
|
||||||
if (loops++ > unrollCount()*16) {
|
if (loops++ > unrollCount()*16) {
|
||||||
clearOptimizable(nodep, "Loop unrolling took too long; probably this is an infinite loop, or set --unroll-count above "+cvtToStr(unrollCount()));
|
clearOptimizable(nodep, "Loop unrolling took too long; probably this is an infinite loop, or set --unroll-count above "+cvtToStr(unrollCount()));
|
||||||
break;
|
break;
|
||||||
@@ -504,6 +543,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void visit(AstFuncRef* nodep, AstNUser*) {
|
virtual void visit(AstFuncRef* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
UINFO(5," FUNCREF "<<nodep<<endl);
|
UINFO(5," FUNCREF "<<nodep<<endl);
|
||||||
if (!m_params) { badNodeType(nodep); return; }
|
if (!m_params) { badNodeType(nodep); return; }
|
||||||
AstNodeFTask* funcp = nodep->taskp()->castNodeFTask(); if (!funcp) nodep->v3fatalSrc("Not linked");
|
AstNodeFTask* funcp = nodep->taskp()->castNodeFTask(); if (!funcp) nodep->v3fatalSrc("Not linked");
|
||||||
@@ -540,6 +580,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void visit(AstVar* nodep, AstNUser*) {
|
virtual void visit(AstVar* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
if (!m_params) { badNodeType(nodep); return; }
|
if (!m_params) { badNodeType(nodep); return; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,20 +589,30 @@ private:
|
|||||||
// AstCoverInc, AstDisplay, AstArraySel, AstStop, AstFinish,
|
// AstCoverInc, AstDisplay, AstArraySel, AstStop, AstFinish,
|
||||||
// AstRand, AstTime, AstUCFunc, AstCCall, AstCStmt, AstUCStmt
|
// AstRand, AstTime, AstUCFunc, AstCCall, AstCStmt, AstUCStmt
|
||||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
badNodeType(nodep);
|
badNodeType(nodep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// MEMBERS - called by constructor
|
||||||
|
void setMode(bool scoped, bool checkOnly, bool params) {
|
||||||
|
m_checkOnly = checkOnly;
|
||||||
|
m_scoped = scoped;
|
||||||
|
m_params = params;
|
||||||
|
}
|
||||||
|
void mainGuts(AstNode* nodep) {
|
||||||
|
nodep->accept(*this);
|
||||||
|
if (m_jumpp) {
|
||||||
|
m_jumpp->v3fatalSrc("JumpGo branched to label that wasn't found");
|
||||||
|
m_jumpp = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
SimulateVisitor() {
|
SimulateVisitor() {
|
||||||
setMode(false,false,false);
|
setMode(false,false,false);
|
||||||
clear(); // We reuse this structure in the main loop, so put initializers inside clear()
|
clear(); // We reuse this structure in the main loop, so put initializers inside clear()
|
||||||
}
|
}
|
||||||
void setMode(bool scoped, bool checkOnly, bool params) {
|
|
||||||
m_checkOnly = checkOnly;
|
|
||||||
m_scoped = scoped;
|
|
||||||
m_params = params;
|
|
||||||
}
|
|
||||||
void clear() {
|
void clear() {
|
||||||
m_whyNotOptimizable = "";
|
m_whyNotOptimizable = "";
|
||||||
m_whyNotNodep = NULL;
|
m_whyNotNodep = NULL;
|
||||||
@@ -570,6 +621,7 @@ public:
|
|||||||
m_inDlyAssign = false;
|
m_inDlyAssign = false;
|
||||||
m_instrCount = 0;
|
m_instrCount = 0;
|
||||||
m_dataCount = 0;
|
m_dataCount = 0;
|
||||||
|
m_jumpp = NULL;
|
||||||
|
|
||||||
AstNode::user1ClearTree(); // user1p() used on entire tree
|
AstNode::user1ClearTree(); // user1p() used on entire tree
|
||||||
AstNode::user2ClearTree(); // user2p() used on entire tree
|
AstNode::user2ClearTree(); // user2p() used on entire tree
|
||||||
@@ -580,15 +632,15 @@ public:
|
|||||||
}
|
}
|
||||||
void mainTableCheck (AstNode* nodep) {
|
void mainTableCheck (AstNode* nodep) {
|
||||||
setMode(true/*scoped*/,true/*checking*/, false/*params*/);
|
setMode(true/*scoped*/,true/*checking*/, false/*params*/);
|
||||||
nodep->accept(*this);
|
mainGuts(nodep);
|
||||||
}
|
}
|
||||||
void mainTableEmulate (AstNode* nodep) {
|
void mainTableEmulate (AstNode* nodep) {
|
||||||
setMode(true/*scoped*/,false/*checking*/, false/*params*/);
|
setMode(true/*scoped*/,false/*checking*/, false/*params*/);
|
||||||
nodep->accept(*this);
|
mainGuts(nodep);
|
||||||
}
|
}
|
||||||
void mainParamEmulate (AstNode* nodep) {
|
void mainParamEmulate (AstNode* nodep) {
|
||||||
setMode(false/*scoped*/,false/*checking*/, true/*params*/);
|
setMode(false/*scoped*/,false/*checking*/, true/*params*/);
|
||||||
nodep->accept(*this);
|
mainGuts(nodep);
|
||||||
}
|
}
|
||||||
virtual ~SimulateVisitor() {
|
virtual ~SimulateVisitor() {
|
||||||
for (deque<V3Number*>::iterator it = m_numAllps.begin(); it != m_numAllps.end(); ++it) {
|
for (deque<V3Number*>::iterator it = m_numAllps.begin(); it != m_numAllps.end(); ++it) {
|
||||||
|
|||||||
+176
-34
@@ -54,6 +54,14 @@ class SliceCloneVisitor : public AstNVisitor {
|
|||||||
// AstArraySel::user1p() -> AstVarRef. The VarRef that the final ArraySel points to
|
// AstArraySel::user1p() -> AstVarRef. The VarRef that the final ArraySel points to
|
||||||
// AstNodeAssign::user2() -> int. The number of clones needed for this assign
|
// AstNodeAssign::user2() -> int. The number of clones needed for this assign
|
||||||
|
|
||||||
|
// ENUMS
|
||||||
|
enum RedOp { // The type of unary operation to be expanded
|
||||||
|
REDOP_UNKNOWN, // Unknown/Unsupported
|
||||||
|
REDOP_OR, // Or Reduction
|
||||||
|
REDOP_AND, // And Reduction
|
||||||
|
REDOP_XOR, // Xor Reduction
|
||||||
|
REDOP_XNOR}; // Xnor Reduction
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
vector<vector<unsigned> > m_selBits; // Indexes of the ArraySel we are expanding
|
vector<vector<unsigned> > m_selBits; // Indexes of the ArraySel we are expanding
|
||||||
int m_vecIdx; // Current vector index
|
int m_vecIdx; // Current vector index
|
||||||
@@ -76,8 +84,9 @@ class SliceCloneVisitor : public AstNVisitor {
|
|||||||
if (m_vecIdx == (int)m_selBits.size()) {
|
if (m_vecIdx == (int)m_selBits.size()) {
|
||||||
m_selBits.push_back(vector<unsigned>());
|
m_selBits.push_back(vector<unsigned>());
|
||||||
AstVar* varp = m_refp->varp();
|
AstVar* varp = m_refp->varp();
|
||||||
int dimensions = varp->dimensions();
|
pair<uint32_t,uint32_t> arrDim = varp->dimensions();
|
||||||
for (int i = 0; i < dimensions; ++i) {
|
uint32_t dimensions = arrDim.first + arrDim.second;
|
||||||
|
for (uint32_t i = 0; i < dimensions; ++i) {
|
||||||
m_selBits[m_vecIdx].push_back(0);
|
m_selBits[m_vecIdx].push_back(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,6 +121,7 @@ class SliceCloneVisitor : public AstNVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
||||||
|
if (nodep->user2() < 2) return; // Don't need clones
|
||||||
m_selBits.clear();
|
m_selBits.clear();
|
||||||
UINFO(4, "Cloning "<<nodep->user2()<<" times: "<<nodep<<endl);
|
UINFO(4, "Cloning "<<nodep->user2()<<" times: "<<nodep<<endl);
|
||||||
for (int i = 0; i < nodep->user2(); ++i) {
|
for (int i = 0; i < nodep->user2(); ++i) {
|
||||||
@@ -124,13 +134,77 @@ class SliceCloneVisitor : public AstNVisitor {
|
|||||||
nodep->unlinkFrBack()->deleteTree(); nodep = NULL;
|
nodep->unlinkFrBack()->deleteTree(); nodep = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Not all Uniop nodes should be cloned down to a single bit
|
||||||
|
void cloneUniop(AstNodeUniop* nodep) {
|
||||||
|
if (nodep->user2() < 2) return; // Don't need clones
|
||||||
|
m_selBits.clear();
|
||||||
|
UINFO(4, "Cloning "<<nodep->user2()<<" times: "<<nodep<<endl);
|
||||||
|
|
||||||
|
// Figure out what type of operation this is so we don't have to cast on
|
||||||
|
// every clone.
|
||||||
|
RedOp redOpType = REDOP_UNKNOWN;
|
||||||
|
if (nodep->castRedOr()) redOpType = REDOP_OR;
|
||||||
|
else if (nodep->castRedAnd()) redOpType = REDOP_AND;
|
||||||
|
else if (nodep->castRedXor()) redOpType = REDOP_XOR;
|
||||||
|
else if (nodep->castRedXnor()) redOpType = REDOP_XNOR;
|
||||||
|
|
||||||
|
AstNode* lhsp = NULL;
|
||||||
|
AstNode* rhsp = NULL;
|
||||||
|
for (int i = 0; i < nodep->user2(); ++i) {
|
||||||
|
// Clone the node and iterate over the clone
|
||||||
|
m_vecIdx = -1;
|
||||||
|
AstNodeUniop* clonep = nodep->cloneTree(false)->castNodeUniop();
|
||||||
|
clonep->iterateChildren(*this);
|
||||||
|
if (!lhsp) lhsp = clonep;
|
||||||
|
else rhsp = clonep;
|
||||||
|
if (lhsp && rhsp) {
|
||||||
|
switch (redOpType) {
|
||||||
|
case REDOP_OR:
|
||||||
|
lhsp = new AstLogOr(nodep->fileline(), lhsp, rhsp);
|
||||||
|
break;
|
||||||
|
case REDOP_AND:
|
||||||
|
lhsp = new AstLogAnd(nodep->fileline(), lhsp, rhsp);
|
||||||
|
break;
|
||||||
|
case REDOP_XOR:
|
||||||
|
lhsp = new AstXor(nodep->fileline(), lhsp, rhsp);
|
||||||
|
break;
|
||||||
|
case REDOP_XNOR:
|
||||||
|
lhsp = new AstXnor(nodep->fileline(), lhsp, rhsp);
|
||||||
|
break;
|
||||||
|
default: // REDOP_UNKNOWN
|
||||||
|
nodep->v3fatalSrc("Unsupported: Unary operation on multiple packed dimensions");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rhsp = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nodep->addNextHere(lhsp);
|
||||||
|
nodep->unlinkFrBack()->deleteTree(); nodep = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(AstRedOr* nodep, AstNUser*) {
|
||||||
|
cloneUniop(nodep);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(AstRedAnd* nodep, AstNUser*) {
|
||||||
|
cloneUniop(nodep);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(AstRedXor* nodep, AstNUser*) {
|
||||||
|
cloneUniop(nodep);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(AstRedXnor* nodep, AstNUser*) {
|
||||||
|
cloneUniop(nodep);
|
||||||
|
}
|
||||||
|
|
||||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||||
// Default: Just iterate
|
// Default: Just iterate
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
// CONSTUCTORS
|
// CONSTUCTORS
|
||||||
SliceCloneVisitor(AstNodeAssign* assignp) {
|
SliceCloneVisitor(AstNode* assignp) {
|
||||||
assignp->accept(*this);
|
assignp->accept(*this);
|
||||||
}
|
}
|
||||||
virtual ~SliceCloneVisitor() {}
|
virtual ~SliceCloneVisitor() {}
|
||||||
@@ -142,15 +216,20 @@ class SliceVisitor : public AstNVisitor {
|
|||||||
// NODE STATE
|
// NODE STATE
|
||||||
// Cleared on netlist
|
// Cleared on netlist
|
||||||
// AstNodeAssign::user1() -> bool. True if find is complete
|
// AstNodeAssign::user1() -> bool. True if find is complete
|
||||||
// AstNodeAssign::user2() -> int. The number of clones needed for this assign
|
// AstUniop::user1() -> bool. True if find is complete
|
||||||
// AstArraySel::user1p() -> AstVarRef. The VarRef that the final ArraySel points to
|
// AstArraySel::user1p() -> AstVarRef. The VarRef that the final ArraySel points to
|
||||||
|
// AstNode::user2() -> int. The number of clones needed for this node
|
||||||
AstUser1InUse m_inuser1;
|
AstUser1InUse m_inuser1;
|
||||||
AstUser2InUse m_inuser2;
|
AstUser2InUse m_inuser2;
|
||||||
|
|
||||||
|
// TYPEDEFS
|
||||||
|
typedef pair<uint32_t, uint32_t> ArrayDimensions; // Array Dimensions (packed, unpacked)
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
AstNode* m_assignp; // Assignment we are under
|
AstNode* m_assignp; // Assignment we are under
|
||||||
AstNodeVarRef* m_lhsVarRefp; // Var on the LHS
|
AstNodeVarRef* m_lhsVarRefp; // Var on the LHS
|
||||||
bool m_extend; // We have found an extend node
|
bool m_extend; // We have found an extend node
|
||||||
|
bool m_assignError; // True if the current assign already has an error
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
static int debug() {
|
static int debug() {
|
||||||
@@ -178,15 +257,13 @@ class SliceVisitor : public AstNVisitor {
|
|||||||
return dim;
|
return dim;
|
||||||
}
|
}
|
||||||
|
|
||||||
AstNode* insertImplicit(AstVarRef* nodep, unsigned start, unsigned count) {
|
AstArraySel* insertImplicit(AstNode* nodep, unsigned start, unsigned count) {
|
||||||
// Insert any implicit slices as explicit slices (ArraySel nodes).
|
// Insert any implicit slices as explicit slices (ArraySel nodes).
|
||||||
// Return a new pointer to replace fromp() in the ArraySel.
|
// Return a new pointer to replace nodep() in the ArraySel.
|
||||||
AstVarRef* fromp = nodep;
|
AstVarRef* refp = nodep->user1p()->castNode()->castVarRef();
|
||||||
if (!fromp) nodep->v3fatalSrc("NULL VarRef passed to insertImplicit");
|
if (!refp) nodep->v3fatalSrc("No VarRef in user1 of node "<<nodep);
|
||||||
AstVar* varp = fromp->varp();
|
AstVar* varp = refp->varp();
|
||||||
// Get the DType and insert a new ArraySel
|
AstNode* topp = nodep;
|
||||||
AstArraySel* topp = NULL;
|
|
||||||
AstArraySel* bottomp = NULL;
|
|
||||||
for (unsigned i = start; i < start + count; ++i) {
|
for (unsigned i = start; i < start + count; ++i) {
|
||||||
AstNodeDType* dtypep = varp->dtypeDimensionp(i-1);
|
AstNodeDType* dtypep = varp->dtypeDimensionp(i-1);
|
||||||
AstArrayDType* adtypep = dtypep->castArrayDType();
|
AstArrayDType* adtypep = dtypep->castArrayDType();
|
||||||
@@ -197,17 +274,13 @@ class SliceVisitor : public AstNVisitor {
|
|||||||
// Below code assumes big bit endian; just works out if we swap
|
// Below code assumes big bit endian; just works out if we swap
|
||||||
int x = msb; msb = lsb; lsb = x;
|
int x = msb; msb = lsb; lsb = x;
|
||||||
}
|
}
|
||||||
AstArraySel* newp = new AstArraySel(nodep->fileline(), fromp, new AstConst(nodep->fileline(),lsb));
|
AstArraySel* newp = new AstArraySel(nodep->fileline(), topp, new AstConst(nodep->fileline(),lsb));
|
||||||
|
newp->user1p(refp);
|
||||||
newp->start(lsb);
|
newp->start(lsb);
|
||||||
newp->length(msb - lsb + 1);
|
newp->length(msb - lsb + 1);
|
||||||
if (!topp) topp = newp;
|
topp = newp->castNode();
|
||||||
fromp = newp->fromp()->unlinkFrBack()->castVarRef();
|
|
||||||
|
|
||||||
if (bottomp) bottomp->fromp(newp);
|
|
||||||
bottomp = newp;
|
|
||||||
}
|
}
|
||||||
bottomp->fromp(fromp);
|
return topp->castArraySel();
|
||||||
return topp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int countClones(AstArraySel* nodep) {
|
int countClones(AstArraySel* nodep) {
|
||||||
@@ -228,9 +301,12 @@ class SliceVisitor : public AstNVisitor {
|
|||||||
// The LHS/RHS of an Assign may be to a Var that is an array. In this
|
// The LHS/RHS of an Assign may be to a Var that is an array. In this
|
||||||
// case we need to create a slice accross the entire Var
|
// case we need to create a slice accross the entire Var
|
||||||
if (m_assignp && !nodep->backp()->castArraySel()) {
|
if (m_assignp && !nodep->backp()->castArraySel()) {
|
||||||
uint32_t dimensions = nodep->varp()->dimensions();
|
pair<uint32_t,uint32_t> arrDim = nodep->varp()->dimensions();
|
||||||
|
uint32_t dimensions = arrDim.first + arrDim.second;
|
||||||
if (dimensions > 0) {
|
if (dimensions > 0) {
|
||||||
AstNode* newp = insertImplicit(nodep->cloneTree(false), 1, dimensions);
|
AstVarRef* clonep = nodep->cloneTree(false);
|
||||||
|
clonep->user1p(nodep);
|
||||||
|
AstNode* newp = insertImplicit(clonep, 1, dimensions);
|
||||||
nodep->replaceWith(newp); nodep = NULL;
|
nodep->replaceWith(newp); nodep = NULL;
|
||||||
newp->accept(*this);
|
newp->accept(*this);
|
||||||
}
|
}
|
||||||
@@ -239,8 +315,18 @@ class SliceVisitor : public AstNVisitor {
|
|||||||
|
|
||||||
virtual void visit(AstExtend* nodep, AstNUser*) {
|
virtual void visit(AstExtend* nodep, AstNUser*) {
|
||||||
m_extend = true;
|
m_extend = true;
|
||||||
if (m_assignp && m_assignp->user2() > 1) {
|
if (m_assignp && m_assignp->user2() > 1 && !m_assignError) {
|
||||||
m_assignp->v3error("Unsupported: Assignment between packed arrays of different dimensions");
|
m_assignp->v3error("Unsupported: Assignment between packed arrays of different dimensions");
|
||||||
|
m_assignError = true;
|
||||||
|
}
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(AstConst* nodep, AstNUser*) {
|
||||||
|
m_extend = true;
|
||||||
|
if (m_assignp && m_assignp->user2() > 1 && !m_assignError) {
|
||||||
|
m_assignp->v3error("Unsupported: Assignment between a constant and an array slice");
|
||||||
|
m_assignError = true;
|
||||||
}
|
}
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
}
|
}
|
||||||
@@ -249,22 +335,24 @@ class SliceVisitor : public AstNVisitor {
|
|||||||
if (!m_assignp) return;
|
if (!m_assignp) return;
|
||||||
unsigned dim = explicitDimensions(nodep);
|
unsigned dim = explicitDimensions(nodep);
|
||||||
AstVarRef* refp = nodep->user1p()->castNode()->castVarRef();
|
AstVarRef* refp = nodep->user1p()->castNode()->castVarRef();
|
||||||
unsigned implicit = refp->varp()->dimensions() - dim;
|
pair<uint32_t,uint32_t> arrDim = refp->varp()->dimensions();
|
||||||
|
uint32_t implicit = (arrDim.first + arrDim.second) - dim;
|
||||||
if (implicit > 0) {
|
if (implicit > 0) {
|
||||||
AstNode* backp = refp->backp();
|
AstArraySel* newp = insertImplicit(nodep->cloneTree(false), dim+1, implicit);
|
||||||
AstNode* newp = insertImplicit(refp->cloneTree(false), dim+1, implicit);
|
nodep->replaceWith(newp); nodep = newp;
|
||||||
backp->castArraySel()->fromp()->replaceWith(newp);
|
|
||||||
}
|
}
|
||||||
int clones = countClones(nodep);
|
int clones = countClones(nodep);
|
||||||
if (m_assignp->user2() > 0 && m_assignp->user2() != clones) {
|
if (m_assignp->user2() > 0 && m_assignp->user2() != clones) {
|
||||||
m_assignp->v3error("Slices of arrays in assignments must have the same unpacked dimensions");
|
m_assignp->v3error("Slices of arrays in assignments must have the same unpacked dimensions");
|
||||||
} else if (m_assignp->user2() == 0) {
|
} else if (m_assignp->user2() == 0 && !m_assignError) {
|
||||||
if (m_extend && clones > 1) {
|
if (m_extend && clones > 1) {
|
||||||
m_assignp->v3error("Unsupported: Assignment between packed arrays of different dimensions");
|
m_assignp->v3error("Unsupported: Assignment between packed arrays of different dimensions");
|
||||||
|
m_assignError = true;
|
||||||
}
|
}
|
||||||
if (clones > 1 && !refp->lvalue() && refp->varp() == m_lhsVarRefp->varp() && !m_assignp->castAssignDly()) {
|
if (clones > 1 && !refp->lvalue() && refp->varp() == m_lhsVarRefp->varp() && !m_assignp->castAssignDly()) {
|
||||||
// LHS Var != RHS Var for a non-delayed assignment
|
// LHS Var != RHS Var for a non-delayed assignment
|
||||||
m_assignp->v3error("Unsupported: Slices in a non-delayed assignment with the same Var on both sides");
|
m_assignp->v3error("Unsupported: Slices in a non-delayed assignment with the same Var on both sides");
|
||||||
|
m_assignError = true;
|
||||||
}
|
}
|
||||||
m_assignp->user2(clones);
|
m_assignp->user2(clones);
|
||||||
}
|
}
|
||||||
@@ -272,8 +360,9 @@ class SliceVisitor : public AstNVisitor {
|
|||||||
|
|
||||||
virtual void visit(AstSel* nodep, AstNUser*) {
|
virtual void visit(AstSel* nodep, AstNUser*) {
|
||||||
m_extend = true;
|
m_extend = true;
|
||||||
if (m_assignp && m_assignp->user2() > 1) {
|
if (m_assignp && m_assignp->user2() > 1 && !m_assignError) {
|
||||||
m_assignp->v3error("Unsupported: Assignment between packed arrays of different dimensions");
|
m_assignp->v3error("Unsupported: Assignment between packed arrays of different dimensions");
|
||||||
|
m_assignError = true;
|
||||||
}
|
}
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
}
|
}
|
||||||
@@ -314,6 +403,7 @@ class SliceVisitor : public AstNVisitor {
|
|||||||
void findImplicit(AstNodeAssign* nodep) {
|
void findImplicit(AstNodeAssign* nodep) {
|
||||||
if (m_assignp) nodep->v3fatalSrc("Found a NodeAssign under another NodeAssign");
|
if (m_assignp) nodep->v3fatalSrc("Found a NodeAssign under another NodeAssign");
|
||||||
m_assignp = nodep;
|
m_assignp = nodep;
|
||||||
|
m_assignError = false;
|
||||||
m_extend = false;
|
m_extend = false;
|
||||||
nodep->user1(true);
|
nodep->user1(true);
|
||||||
// Record the LHS Var so we can check if the Var on the RHS is the same
|
// Record the LHS Var so we can check if the Var on the RHS is the same
|
||||||
@@ -322,9 +412,7 @@ class SliceVisitor : public AstNVisitor {
|
|||||||
// Iterate children looking for ArraySel nodes. From that we get the number of elements
|
// Iterate children looking for ArraySel nodes. From that we get the number of elements
|
||||||
// in the array so we know how many times we need to clone this assignment.
|
// in the array so we know how many times we need to clone this assignment.
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (nodep->user2() > 1) {
|
if (nodep->user2() > 1) SliceCloneVisitor scv(nodep);
|
||||||
SliceCloneVisitor scv(nodep);
|
|
||||||
}
|
|
||||||
m_assignp = NULL;
|
m_assignp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,6 +423,60 @@ class SliceVisitor : public AstNVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void expandUniOp(AstNodeUniop* nodep) {
|
||||||
|
nodep->user1(true);
|
||||||
|
unsigned dim = 0;
|
||||||
|
if (AstArraySel* selp = nodep->lhsp()->castArraySel()) {
|
||||||
|
// We have explicit dimensions, either packed or unpacked
|
||||||
|
dim = explicitDimensions(selp);
|
||||||
|
}
|
||||||
|
if (dim == 0 && !nodep->lhsp()->castVarRef()) {
|
||||||
|
// No ArraySel or VarRef, not something we can expand
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
} else {
|
||||||
|
AstVarRef* refp = findVarRefRecurse(nodep->lhsp());
|
||||||
|
ArrayDimensions varDim = refp->varp()->dimensions();
|
||||||
|
if ((int)(dim - varDim.second) < 0) {
|
||||||
|
// Unpacked dimensions are referenced first, make sure we have them all
|
||||||
|
nodep->v3error("Unary operator used across unpacked dimensions");
|
||||||
|
} else if ((int)(dim - (varDim.first + varDim.second)) < 0) {
|
||||||
|
// Implicit packed dimensions are allowed, make them explicit
|
||||||
|
uint32_t newDim = (varDim.first + varDim.second) - dim;
|
||||||
|
AstNode* clonep = nodep->lhsp()->cloneTree(false);
|
||||||
|
clonep->user1p(refp);
|
||||||
|
AstNode* newp = insertImplicit(clonep, dim+1, newDim);
|
||||||
|
nodep->lhsp()->replaceWith(newp); refp = NULL;
|
||||||
|
int clones = countClones(nodep->lhsp()->castArraySel());
|
||||||
|
nodep->user2(clones);
|
||||||
|
SliceCloneVisitor scv(nodep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(AstRedOr* nodep, AstNUser*) {
|
||||||
|
if (!nodep->user1()) {
|
||||||
|
expandUniOp(nodep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(AstRedAnd* nodep, AstNUser*) {
|
||||||
|
if (!nodep->user1()) {
|
||||||
|
expandUniOp(nodep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(AstRedXor* nodep, AstNUser*) {
|
||||||
|
if (!nodep->user1()) {
|
||||||
|
expandUniOp(nodep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(AstRedXnor* nodep, AstNUser*) {
|
||||||
|
if (!nodep->user1()) {
|
||||||
|
expandUniOp(nodep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||||
// Default: Just iterate
|
// Default: Just iterate
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
@@ -354,6 +496,6 @@ public:
|
|||||||
// Link class functions
|
// Link class functions
|
||||||
|
|
||||||
void V3Slice::sliceAll(AstNetlist* rootp) {
|
void V3Slice::sliceAll(AstNetlist* rootp) {
|
||||||
UINFO(4,__FUNCTION__<<": "<<endl);
|
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||||
SliceVisitor visitor(rootp);
|
SliceVisitor visitor(rootp);
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -1034,12 +1034,13 @@ private:
|
|||||||
AstNodeFTask* funcp = nodep->taskp();
|
AstNodeFTask* funcp = nodep->taskp();
|
||||||
if (!funcp) nodep->v3fatalSrc("unlinked");
|
if (!funcp) nodep->v3fatalSrc("unlinked");
|
||||||
if (!funcp->isFunction()) nodep->v3fatalSrc("func reference to non-function");
|
if (!funcp->isFunction()) nodep->v3fatalSrc("func reference to non-function");
|
||||||
|
if (!m_scopep) nodep->v3fatalSrc("func ref not under scope");
|
||||||
// Inline func refs in the function
|
// Inline func refs in the function
|
||||||
iterateIntoFTask(funcp);
|
iterateIntoFTask(funcp);
|
||||||
// Create output variable
|
// Create output variable
|
||||||
string namePrefix = "__Vfunc_"+nodep->taskp()->shortName()+"__"+cvtToStr(m_modNCalls++);
|
string namePrefix = "__Vfunc_"+nodep->taskp()->shortName()+"__"+cvtToStr(m_modNCalls++);
|
||||||
AstVarScope* outvscp = createVarScope (funcp->fvarp()->castVar(),
|
AstVarScope* outvscp = createVarScope (funcp->fvarp()->castVar(),
|
||||||
namePrefix+"__out");
|
namePrefix+"__Vfuncout");
|
||||||
// Create cloned statements
|
// Create cloned statements
|
||||||
if (debug()>=9) { nodep->taskp()->dumpTree(cout,"-oldfunc:"); }
|
if (debug()>=9) { nodep->taskp()->dumpTree(cout,"-oldfunc:"); }
|
||||||
if (!nodep->taskp()) nodep->v3fatalSrc("Unlinked?");
|
if (!nodep->taskp()) nodep->v3fatalSrc("Unlinked?");
|
||||||
@@ -1066,10 +1067,8 @@ private:
|
|||||||
AstNode* prevInsStmtp = m_insStmtp;
|
AstNode* prevInsStmtp = m_insStmtp;
|
||||||
m_insMode = IM_BEFORE;
|
m_insMode = IM_BEFORE;
|
||||||
m_insStmtp = nodep->stmtsp(); // Might be null if no statements, but we won't use it
|
m_insStmtp = nodep->stmtsp(); // Might be null if no statements, but we won't use it
|
||||||
if (!nodep->user1()) { // Just one creation needed per function
|
if (!nodep->user1Inc()) { // Just one creation needed per function
|
||||||
// Expand functions in it
|
// Expand functions in it
|
||||||
nodep->user1(true);
|
|
||||||
|
|
||||||
int modes = 0;
|
int modes = 0;
|
||||||
if (nodep->dpiImport()) modes++;
|
if (nodep->dpiImport()) modes++;
|
||||||
if (nodep->dpiExport()) modes++;
|
if (nodep->dpiExport()) modes++;
|
||||||
@@ -1127,6 +1126,7 @@ private:
|
|||||||
// Body insert just before themselves
|
// Body insert just before themselves
|
||||||
m_insStmtp = NULL; // First thing should be new statement
|
m_insStmtp = NULL; // First thing should be new statement
|
||||||
nodep->bodysp()->iterateAndNext(*this);
|
nodep->bodysp()->iterateAndNext(*this);
|
||||||
|
nodep->incsp()->iterateAndNext(*this);
|
||||||
// Done the loop
|
// Done the loop
|
||||||
m_insStmtp = NULL; // Next thing should be new statement
|
m_insStmtp = NULL; // Next thing should be new statement
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-4
@@ -322,8 +322,7 @@ private:
|
|||||||
|
|
||||||
void visit(AstSel* nodep, AstNUser*) {
|
void visit(AstSel* nodep, AstNUser*) {
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (!nodep->user1()) {
|
if (!nodep->user1Inc()) {
|
||||||
nodep->user1(1);
|
|
||||||
// Guard against reading/writing past end of bit vector array
|
// Guard against reading/writing past end of bit vector array
|
||||||
int maxmsb = 0;
|
int maxmsb = 0;
|
||||||
bool lvalue = false;
|
bool lvalue = false;
|
||||||
@@ -373,8 +372,7 @@ private:
|
|||||||
|
|
||||||
virtual void visit(AstArraySel* nodep, AstNUser*) {
|
virtual void visit(AstArraySel* nodep, AstNUser*) {
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (!nodep->user1()) {
|
if (!nodep->user1Inc()) {
|
||||||
nodep->user1(1);
|
|
||||||
if (debug()==9) nodep->dumpTree(cout,"-in: ");
|
if (debug()==9) nodep->dumpTree(cout,"-in: ");
|
||||||
// Guard against reading/writing past end of arrays
|
// Guard against reading/writing past end of arrays
|
||||||
AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp());
|
AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp());
|
||||||
|
|||||||
+35
-13
@@ -82,6 +82,20 @@ private:
|
|||||||
: v3Global.opt.unrollCount();
|
: v3Global.opt.unrollCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool bodySizeOverRecurse(AstNode* nodep, int& bodySize, int bodyLimit) {
|
||||||
|
if (!nodep) return false;
|
||||||
|
bodySize++;
|
||||||
|
// Exit once exceeds limits, rather than always total
|
||||||
|
// so don't go O(n^2) when can't unroll
|
||||||
|
if (bodySize > bodyLimit) return true;
|
||||||
|
if (bodySizeOverRecurse(nodep->op1p(), bodySize, bodyLimit)) return true;
|
||||||
|
if (bodySizeOverRecurse(nodep->op2p(), bodySize, bodyLimit)) return true;
|
||||||
|
if (bodySizeOverRecurse(nodep->op3p(), bodySize, bodyLimit)) return true;
|
||||||
|
if (bodySizeOverRecurse(nodep->op4p(), bodySize, bodyLimit)) return true;
|
||||||
|
// Tail recurse.
|
||||||
|
return bodySizeOverRecurse(nodep->nextp(), bodySize, bodyLimit);
|
||||||
|
}
|
||||||
|
|
||||||
bool forUnrollCheck(AstNode* nodep,
|
bool forUnrollCheck(AstNode* nodep,
|
||||||
AstNode* initp, // Maybe under nodep (no nextp), or standalone (ignore nextp)
|
AstNode* initp, // Maybe under nodep (no nextp), or standalone (ignore nextp)
|
||||||
AstNode* precondsp, AstNode* condp,
|
AstNode* precondsp, AstNode* condp,
|
||||||
@@ -174,19 +188,19 @@ private:
|
|||||||
//
|
//
|
||||||
if (!m_generate) {
|
if (!m_generate) {
|
||||||
UINFO(8, " ~Iters: "<<((valStop - valInit)/valInc)<<" c="<<unrollCount()<<endl);
|
UINFO(8, " ~Iters: "<<((valStop - valInit)/valInc)<<" c="<<unrollCount()<<endl);
|
||||||
if (((valStop - valInit)/valInc) > unrollCount())
|
int loops = ((valStop - valInit)/valInc);
|
||||||
|
if (loops > unrollCount())
|
||||||
return cantUnroll(nodep, "too many iterations");
|
return cantUnroll(nodep, "too many iterations");
|
||||||
|
|
||||||
// Less than 10 statements in the body?
|
// Less than 10 statements in the body?
|
||||||
int bodySize = 0;
|
int bodySize = 0;
|
||||||
for (AstNode* bodp = precondsp; bodp; bodp=bodp->nextp()) {
|
int bodyLimit = v3Global.opt.unrollStmts();
|
||||||
bodySize++;
|
if (loops>0) bodyLimit = v3Global.opt.unrollStmts() / loops;
|
||||||
}
|
if (bodySizeOverRecurse(precondsp, bodySize/*ref*/, bodyLimit)
|
||||||
for (AstNode* bodp = bodysp; bodp; bodp=bodp->nextp()) {
|
|| bodySizeOverRecurse(bodysp, bodySize/*ref*/, bodyLimit)
|
||||||
bodySize++;
|
|| bodySizeOverRecurse(incp, bodySize/*ref*/, bodyLimit)) {
|
||||||
}
|
|
||||||
if (bodySize > v3Global.opt.unrollStmts())
|
|
||||||
return cantUnroll(nodep, "too many statements");
|
return cantUnroll(nodep, "too many statements");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// Now, make sure there's no assignment to this variable in the loop
|
// Now, make sure there's no assignment to this variable in the loop
|
||||||
@@ -195,6 +209,7 @@ private:
|
|||||||
m_ignoreIncp = incp;
|
m_ignoreIncp = incp;
|
||||||
precondsp->iterateAndNext(*this);
|
precondsp->iterateAndNext(*this);
|
||||||
bodysp->iterateAndNext(*this);
|
bodysp->iterateAndNext(*this);
|
||||||
|
incp->iterateAndNext(*this);
|
||||||
m_varModeCheck = false;
|
m_varModeCheck = false;
|
||||||
m_ignoreIncp = NULL;
|
m_ignoreIncp = NULL;
|
||||||
if (m_varAssignHit) return cantUnroll(nodep, "genvar assigned *inside* loop");
|
if (m_varAssignHit) return cantUnroll(nodep, "genvar assigned *inside* loop");
|
||||||
@@ -231,6 +246,10 @@ private:
|
|||||||
bodysp->unlinkFrBackWithNext();
|
bodysp->unlinkFrBackWithNext();
|
||||||
stmtsp = stmtsp->addNextNull(bodysp); // Maybe null if no body
|
stmtsp = stmtsp->addNextNull(bodysp); // Maybe null if no body
|
||||||
}
|
}
|
||||||
|
if (incp && !nodep->castGenFor()) { // Generates don't need to increment loop index
|
||||||
|
incp->unlinkFrBackWithNext();
|
||||||
|
stmtsp = stmtsp->addNextNull(incp); // Maybe null if no body
|
||||||
|
}
|
||||||
// If it's a While, then incp is already part of bodysp.
|
// If it's a While, then incp is already part of bodysp.
|
||||||
V3Number loopValue(nodep->fileline(), m_forVarp->width()); // May differ in size from numInitp
|
V3Number loopValue(nodep->fileline(), m_forVarp->width()); // May differ in size from numInitp
|
||||||
loopValue.opAssign(numInit);
|
loopValue.opAssign(numInit);
|
||||||
@@ -279,7 +298,6 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Leaving the iterator at the final value is handled by the increment statements being left the final body
|
|
||||||
// Replace the FOR()
|
// Replace the FOR()
|
||||||
if (newbodysp) nodep->replaceWith(newbodysp);
|
if (newbodysp) nodep->replaceWith(newbodysp);
|
||||||
else nodep->unlinkFrBack();
|
else nodep->unlinkFrBack();
|
||||||
@@ -303,9 +321,13 @@ private:
|
|||||||
if (nodep->backp()->nextp() == nodep) initp=nodep->backp();
|
if (nodep->backp()->nextp() == nodep) initp=nodep->backp();
|
||||||
// Grab assignment
|
// Grab assignment
|
||||||
AstNode* incp = NULL; // Should be last statement
|
AstNode* incp = NULL; // Should be last statement
|
||||||
for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {}
|
if (nodep->incsp()) V3Const::constifyEdit(nodep->incsp());
|
||||||
if (incp) { V3Const::constifyEdit(incp); incp=NULL; }
|
if (nodep->incsp()) incp = nodep->incsp();
|
||||||
for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {} // Again, as may have changed
|
else {
|
||||||
|
for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {}
|
||||||
|
if (incp) { V3Const::constifyEdit(incp); incp=NULL; }
|
||||||
|
for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {} // Again, as may have changed
|
||||||
|
}
|
||||||
// And check it
|
// And check it
|
||||||
if (forUnrollCheck(nodep, initp,
|
if (forUnrollCheck(nodep, initp,
|
||||||
nodep->precondsp(), nodep->condp(),
|
nodep->precondsp(), nodep->condp(),
|
||||||
@@ -338,7 +360,7 @@ private:
|
|||||||
nodep->incsp(), nodep->bodysp())) {
|
nodep->incsp(), nodep->bodysp())) {
|
||||||
pushDeletep(nodep); nodep=NULL; // Did replacement
|
pushDeletep(nodep); nodep=NULL; // Did replacement
|
||||||
} else {
|
} else {
|
||||||
nodep->v3error("For loop doesn't have genvar index, or is misformed");
|
nodep->v3error("For loop doesn't have genvar index, or is malformed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-2
@@ -84,6 +84,7 @@ private:
|
|||||||
bool m_paramsOnly; // Computing parameter value; limit operation
|
bool m_paramsOnly; // Computing parameter value; limit operation
|
||||||
AstRange* m_cellRangep; // Range for arrayed instantiations, NULL for normal instantiations
|
AstRange* m_cellRangep; // Range for arrayed instantiations, NULL for normal instantiations
|
||||||
AstNodeCase* m_casep; // Current case statement CaseItem is under
|
AstNodeCase* m_casep; // Current case statement CaseItem is under
|
||||||
|
AstFunc* m_funcp; // Current function
|
||||||
|
|
||||||
// CLASSES
|
// CLASSES
|
||||||
#define ANYSIZE 0
|
#define ANYSIZE 0
|
||||||
@@ -711,6 +712,7 @@ private:
|
|||||||
nodep->precondsp()->iterateAndNext(*this);
|
nodep->precondsp()->iterateAndNext(*this);
|
||||||
nodep->condp()->iterateAndNext(*this,WidthVP(1,1,BOTH).p());
|
nodep->condp()->iterateAndNext(*this,WidthVP(1,1,BOTH).p());
|
||||||
nodep->bodysp()->iterateAndNext(*this);
|
nodep->bodysp()->iterateAndNext(*this);
|
||||||
|
nodep->incsp()->iterateAndNext(*this);
|
||||||
widthCheckReduce(nodep,"For Test Condition",nodep->condp(),1,1); // it's like an if() condition.
|
widthCheckReduce(nodep,"For Test Condition",nodep->condp(),1,1); // it's like an if() condition.
|
||||||
}
|
}
|
||||||
virtual void visit(AstNodeIf* nodep, AstNUser*) {
|
virtual void visit(AstNodeIf* nodep, AstNUser*) {
|
||||||
@@ -924,6 +926,20 @@ private:
|
|||||||
nodep->width(nodep->fvarp()->width(), nodep->fvarp()->width());
|
nodep->width(nodep->fvarp()->width(), nodep->fvarp()->width());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
m_funcp = NULL;
|
||||||
|
}
|
||||||
|
virtual void visit(AstReturn* nodep, AstNUser* vup) {
|
||||||
|
if (!m_funcp) {
|
||||||
|
if (nodep->lhsp()) { // Return w/o value ok other places
|
||||||
|
nodep->v3error("Return with return value isn't underneath a function");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (nodep->lhsp()) {
|
||||||
|
// Function hasn't been widthed, so make it so.
|
||||||
|
nodep->iterateChildren(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||||
|
nodep->widthSignedFrom(m_funcp->fvarp());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstFuncRef* nodep, AstNUser* vup) {
|
virtual void visit(AstFuncRef* nodep, AstNUser* vup) {
|
||||||
visit(nodep->castNodeFTaskRef(), vup);
|
visit(nodep->castNodeFTaskRef(), vup);
|
||||||
@@ -974,8 +990,9 @@ private:
|
|||||||
lastloop = true; // so exit early; next loop will correct it
|
lastloop = true; // so exit early; next loop will correct it
|
||||||
}
|
}
|
||||||
else if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::STRING
|
else if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::STRING
|
||||||
&& !pinp->castCvtPackString()
|
&& !pinp->castCvtPackString()
|
||||||
&& !(pinp->castVarRef() && pinp->castVarRef()->varp()->basicp()->keyword()==AstBasicDTypeKwd::STRING)) {
|
&& !pinp->castSFormatF() // Already generates a string
|
||||||
|
&& !(pinp->castVarRef() && pinp->castVarRef()->varp()->basicp()->keyword()==AstBasicDTypeKwd::STRING)) {
|
||||||
UINFO(4," Add CvtPackString: "<<pinp<<endl);
|
UINFO(4," Add CvtPackString: "<<pinp<<endl);
|
||||||
AstNRelinker handle;
|
AstNRelinker handle;
|
||||||
pinp->unlinkFrBack(&handle); // No next, that's the next pin
|
pinp->unlinkFrBack(&handle); // No next, that's the next pin
|
||||||
@@ -1028,6 +1045,7 @@ public:
|
|||||||
m_taskDepth = 0;
|
m_taskDepth = 0;
|
||||||
m_cellRangep = NULL;
|
m_cellRangep = NULL;
|
||||||
m_casep = NULL;
|
m_casep = NULL;
|
||||||
|
m_funcp = NULL;
|
||||||
}
|
}
|
||||||
AstNode* mainAcceptEdit(AstNode* nodep) {
|
AstNode* mainAcceptEdit(AstNode* nodep) {
|
||||||
return nodep->acceptSubtreeReturnEdits(*this, WidthVP(ANYSIZE,0,BOTH).p());
|
return nodep->acceptSubtreeReturnEdits(*this, WidthVP(ANYSIZE,0,BOTH).p());
|
||||||
|
|||||||
+5
-2
@@ -52,8 +52,8 @@
|
|||||||
#include "V3File.h"
|
#include "V3File.h"
|
||||||
#include "V3Cdc.h"
|
#include "V3Cdc.h"
|
||||||
#include "V3Gate.h"
|
#include "V3Gate.h"
|
||||||
#include "V3Graph.h"
|
|
||||||
#include "V3GenClk.h"
|
#include "V3GenClk.h"
|
||||||
|
#include "V3Graph.h"
|
||||||
#include "V3Inline.h"
|
#include "V3Inline.h"
|
||||||
#include "V3Inst.h"
|
#include "V3Inst.h"
|
||||||
#include "V3Life.h"
|
#include "V3Life.h"
|
||||||
@@ -61,9 +61,10 @@
|
|||||||
#include "V3Link.h"
|
#include "V3Link.h"
|
||||||
#include "V3LinkCells.h"
|
#include "V3LinkCells.h"
|
||||||
#include "V3LinkDot.h"
|
#include "V3LinkDot.h"
|
||||||
|
#include "V3LinkJump.h"
|
||||||
|
#include "V3LinkLValue.h"
|
||||||
#include "V3LinkLevel.h"
|
#include "V3LinkLevel.h"
|
||||||
#include "V3LinkParse.h"
|
#include "V3LinkParse.h"
|
||||||
#include "V3LinkLValue.h"
|
|
||||||
#include "V3LinkResolve.h"
|
#include "V3LinkResolve.h"
|
||||||
#include "V3Localize.h"
|
#include "V3Localize.h"
|
||||||
#include "V3Name.h"
|
#include "V3Name.h"
|
||||||
@@ -143,6 +144,8 @@ void process () {
|
|||||||
V3LinkResolve::linkResolve(v3Global.rootp());
|
V3LinkResolve::linkResolve(v3Global.rootp());
|
||||||
// Set Lvalue's in variable refs
|
// Set Lvalue's in variable refs
|
||||||
V3LinkLValue::linkLValue(v3Global.rootp());
|
V3LinkLValue::linkLValue(v3Global.rootp());
|
||||||
|
// Convert return/continue/disable to jumps
|
||||||
|
V3LinkJump::linkJump(v3Global.rootp());
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("link.tree"));
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("link.tree"));
|
||||||
V3Error::abortIfErrors();
|
V3Error::abortIfErrors();
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
//**********************************************************************
|
//**********************************************************************
|
||||||
//**** Version and host name
|
//**** Version and host name
|
||||||
|
|
||||||
#define DTVERSION "Verilator 3.800 2010/02/07"
|
#define DTVERSION "Verilator 3.803 2010/07/10"
|
||||||
|
|
||||||
//**********************************************************************
|
//**********************************************************************
|
||||||
//**** Functions
|
//**** Functions
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
|
|
||||||
# DESCRIPTION: Edits flex output to get around various broken flex issues.
|
# DESCRIPTION: Edits flex output to get around various broken flex issues.
|
||||||
|
|
||||||
|
my $Opt_Prefix = $ARGV[0] or die "%Error: No prefix specified,";
|
||||||
|
|
||||||
foreach my $line (<STDIN>) {
|
foreach my $line (<STDIN>) {
|
||||||
# Fix flex 2.5.4 namespace omission
|
# Fix flex 2.5.4 namespace omission
|
||||||
$line =~ s/^class istream;/\#include <iostream>\nusing namespace std;\n/;
|
$line =~ s/^class istream;/\#include <iostream>\nusing namespace std;\n/;
|
||||||
@@ -28,6 +30,8 @@ foreach my $line (<STDIN>) {
|
|||||||
$line =~ s!for \( n = 0; n < max_size && !for ( n = 0; ((size_t)n < (size_t)max_size) && !g;
|
$line =~ s!for \( n = 0; n < max_size && !for ( n = 0; ((size_t)n < (size_t)max_size) && !g;
|
||||||
# Fix flex 2.5.4 and GCC 4.0.2 under FLEX_DEBUG
|
# Fix flex 2.5.4 and GCC 4.0.2 under FLEX_DEBUG
|
||||||
$line =~ s!--accepting rule at line %d !--accepting rule at line %ld !g;
|
$line =~ s!--accepting rule at line %d !--accepting rule at line %ld !g;
|
||||||
|
# Fix compiler warning filenames
|
||||||
|
$line =~ s!(#line \d+ ".*)_pretmp!$1!;
|
||||||
|
|
||||||
print "$line";
|
print "$line";
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-8
@@ -42,7 +42,7 @@ extern void yyerrorf(const char* format, ...);
|
|||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
#define NEXTLINE() {PARSEP->incLineno();}
|
#define NEXTLINE() {PARSEP->linenoInc();}
|
||||||
#define CRELINE() (PARSEP->copyOrSameFileLine())
|
#define CRELINE() (PARSEP->copyOrSameFileLine())
|
||||||
|
|
||||||
#define FL { yylval.fl = CRELINE(); }
|
#define FL { yylval.fl = CRELINE(); }
|
||||||
@@ -53,7 +53,8 @@ extern void yyerrorf(const char* format, ...);
|
|||||||
|
|
||||||
void V3ParseImp::ppline (const char* textp) {
|
void V3ParseImp::ppline (const char* textp) {
|
||||||
// Handle `line directive
|
// Handle `line directive
|
||||||
fileline()->lineDirective(textp);
|
int enterExit;
|
||||||
|
fileline()->lineDirective(textp, enterExit/*ref*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
void V3ParseImp::verilatorCmtLint(const char* textp, bool warnOff) {
|
void V3ParseImp::verilatorCmtLint(const char* textp, bool warnOff) {
|
||||||
@@ -144,6 +145,7 @@ crnl [\r]*[\n]
|
|||||||
id [a-zA-Z_][a-zA-Z0-9_$]*
|
id [a-zA-Z_][a-zA-Z0-9_$]*
|
||||||
/* escaped identifier */
|
/* escaped identifier */
|
||||||
escid \\[^ \t\f\r\n]+
|
escid \\[^ \t\f\r\n]+
|
||||||
|
word [a-zA-Z0-9_]+
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
@@ -382,10 +384,12 @@ escid \\[^ \t\f\r\n]+
|
|||||||
"always_ff" { FL; return yALWAYS; }
|
"always_ff" { FL; return yALWAYS; }
|
||||||
"always_latch" { FL; return yALWAYS; }
|
"always_latch" { FL; return yALWAYS; }
|
||||||
"bit" { FL; return yBIT; }
|
"bit" { FL; return yBIT; }
|
||||||
|
"break" { FL; return yBREAK; }
|
||||||
"byte" { FL; return yBYTE; }
|
"byte" { FL; return yBYTE; }
|
||||||
"chandle" { FL; return yCHANDLE; }
|
"chandle" { FL; return yCHANDLE; }
|
||||||
"clocking" { FL; return yCLOCKING; }
|
"clocking" { FL; return yCLOCKING; }
|
||||||
"context" { FL; return yCONTEXT; }
|
"context" { FL; return yCONTEXT; }
|
||||||
|
"continue" { FL; return yCONTINUE; }
|
||||||
"do" { FL; return yDO; }
|
"do" { FL; return yDO; }
|
||||||
"endclocking" { FL; return yENDCLOCKING; }
|
"endclocking" { FL; return yENDCLOCKING; }
|
||||||
"endpackage" { FL; return yENDPACKAGE; }
|
"endpackage" { FL; return yENDPACKAGE; }
|
||||||
@@ -403,6 +407,7 @@ escid \\[^ \t\f\r\n]+
|
|||||||
"priority" { FL; return yPRIORITY; }
|
"priority" { FL; return yPRIORITY; }
|
||||||
"program" { FL; return yPROGRAM; }
|
"program" { FL; return yPROGRAM; }
|
||||||
"pure" { FL; return yPURE; }
|
"pure" { FL; return yPURE; }
|
||||||
|
"return" { FL; return yRETURN; }
|
||||||
"shortint" { FL; return ySHORTINT; }
|
"shortint" { FL; return ySHORTINT; }
|
||||||
"static" { FL; return ySTATIC; }
|
"static" { FL; return ySTATIC; }
|
||||||
"string" { FL; return ySTRING; }
|
"string" { FL; return ySTRING; }
|
||||||
@@ -419,10 +424,8 @@ escid \\[^ \t\f\r\n]+
|
|||||||
"bind" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"bind" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"binsof" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"binsof" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"break" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
|
||||||
"class" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"class" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"constraint" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"constraint" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"continue" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
|
||||||
"covergroup" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"covergroup" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"coverpoint" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"coverpoint" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"cross" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"cross" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
@@ -457,7 +460,6 @@ escid \\[^ \t\f\r\n]+
|
|||||||
"randomize" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"randomize" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"randsequence" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"randsequence" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"ref" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"ref" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"return" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
|
||||||
"shortreal" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"shortreal" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"solve" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"solve" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"struct" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"struct" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
@@ -632,6 +634,8 @@ escid \\[^ \t\f\r\n]+
|
|||||||
"/*verilator parallel_case*/" { FL; return yVL_PARALLEL_CASE; }
|
"/*verilator parallel_case*/" { FL; return yVL_PARALLEL_CASE; }
|
||||||
"/*verilator public*/" { FL; return yVL_PUBLIC; }
|
"/*verilator public*/" { FL; return yVL_PUBLIC; }
|
||||||
"/*verilator public_flat*/" { FL; return yVL_PUBLIC_FLAT; }
|
"/*verilator public_flat*/" { FL; return yVL_PUBLIC_FLAT; }
|
||||||
|
"/*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 public_module*/" { FL; return yVL_PUBLIC_MODULE; }
|
||||||
"/*verilator sc_clock*/" { FL; return yVL_CLOCK; }
|
"/*verilator sc_clock*/" { FL; return yVL_CLOCK; }
|
||||||
"/*verilator sformat*/" { FL; return yVL_SFORMAT; }
|
"/*verilator sformat*/" { FL; return yVL_SFORMAT; }
|
||||||
@@ -645,7 +649,8 @@ escid \\[^ \t\f\r\n]+
|
|||||||
"/*verilator lint_restore*/" {PARSEP->verilatorCmtLintRestore(); }
|
"/*verilator lint_restore*/" {PARSEP->verilatorCmtLintRestore(); }
|
||||||
"/*verilator lint_save*/" {PARSEP->verilatorCmtLintSave(); }
|
"/*verilator lint_save*/" {PARSEP->verilatorCmtLintSave(); }
|
||||||
|
|
||||||
"/*"[^*]*"*/" {PARSEP->verilatorCmtBad(yytext); }
|
"/**/" { }
|
||||||
|
"/*"[^*]+"*/" {PARSEP->verilatorCmtBad(yytext); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
@@ -829,12 +834,14 @@ escid \\[^ \t\f\r\n]+
|
|||||||
<STRING>\" { yy_pop_state();
|
<STRING>\" { yy_pop_state();
|
||||||
FL; yylval.strp = PARSEP->newString(yytext+1,yyleng-2);
|
FL; yylval.strp = PARSEP->newString(yytext+1,yyleng-2);
|
||||||
return yaSTRING; }
|
return yaSTRING; }
|
||||||
|
<STRING>{word} { yymore(); }
|
||||||
<STRING>. { yymore(); }
|
<STRING>. { yymore(); }
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/* Attributes */
|
/* Attributes */
|
||||||
<ATTRMODE>{crnl} { yymore(); NEXTLINE(); }
|
<ATTRMODE>{crnl} { yymore(); NEXTLINE(); }
|
||||||
<ATTRMODE>"*)" { yy_pop_state(); }
|
<ATTRMODE>"*)" { yy_pop_state(); }
|
||||||
|
<ATTRMODE>{word} { yymore(); }
|
||||||
<ATTRMODE>. { yymore(); }
|
<ATTRMODE>. { yymore(); }
|
||||||
<ATTRMODE><<EOF>> { yyerrorf("EOF in (*");
|
<ATTRMODE><<EOF>> { yyerrorf("EOF in (*");
|
||||||
yyleng = 0; yy_pop_state(); }
|
yyleng = 0; yy_pop_state(); }
|
||||||
@@ -863,7 +870,10 @@ escid \\[^ \t\f\r\n]+
|
|||||||
"`autoexpand_vectornets" { } // Verilog-XL compatibility
|
"`autoexpand_vectornets" { } // Verilog-XL compatibility
|
||||||
"`celldefine" { PARSEP->inCellDefine(true); }
|
"`celldefine" { PARSEP->inCellDefine(true); }
|
||||||
"`default_decay_time"{ws}+[^\n\r]* { } // Verilog spec - delays only
|
"`default_decay_time"{ws}+[^\n\r]* { } // Verilog spec - delays only
|
||||||
"`default_nettype"{ws}+[a-zA-Z0-9]* { yyerrorf("Unsupported: Verilog 2001 directive not implemented: %s",yytext); } // Verilog 2001
|
"`default_nettype"{ws}+"wire" { PARSEP->fileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE,true); }
|
||||||
|
"`default_nettype"{ws}+"none" { PARSEP->fileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE,false); }
|
||||||
|
"`default_nettype"{ws}+[a-zA-Z0-9]* { yyerrorf("Unsupported: `default_nettype of other than none or wire: %s",yytext); }
|
||||||
|
"`default_trireg_strength"{ws}+[^\n\r]* { yyerrorf("Unsupported: Verilog optional directive not implemented: %s",yytext); }
|
||||||
"`delay_mode_distributed" { } // Verilog spec - delays only
|
"`delay_mode_distributed" { } // Verilog spec - delays only
|
||||||
"`delay_mode_path" { } // Verilog spec - delays only
|
"`delay_mode_path" { } // Verilog spec - delays only
|
||||||
"`delay_mode_unit" { } // Verilog spec - delays only
|
"`delay_mode_unit" { } // Verilog spec - delays only
|
||||||
@@ -887,7 +897,7 @@ escid \\[^ \t\f\r\n]+
|
|||||||
"`psl" { if (PARSEP->optPsl()) { BEGIN PSL; } else { BEGIN IGNORE; } }
|
"`psl" { if (PARSEP->optPsl()) { BEGIN PSL; } else { BEGIN IGNORE; } }
|
||||||
"`remove_gatenames" { } // Verilog-XL compatibility
|
"`remove_gatenames" { } // Verilog-XL compatibility
|
||||||
"`remove_netnames" { } // Verilog-XL compatibility
|
"`remove_netnames" { } // Verilog-XL compatibility
|
||||||
"`resetall" { }
|
"`resetall" { PARSEP->fileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE,true); } // Rest handled by preproc
|
||||||
"`suppress_faults" { } // Verilog-XL compatibility
|
"`suppress_faults" { } // Verilog-XL compatibility
|
||||||
"`timescale"{ws}+[^\n\r]* { } // Verilog spec - not supported
|
"`timescale"{ws}+[^\n\r]* { } // Verilog spec - not supported
|
||||||
|
|
||||||
|
|||||||
+57
-34
@@ -84,7 +84,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
AstNodeDType* createArray(AstNodeDType* basep, AstRange* rangep);
|
AstNodeDType* createArray(AstNodeDType* basep, AstRange* rangep, bool isPacked);
|
||||||
AstVar* createVariable(FileLine* fileline, string name, AstRange* arrayp, AstNode* attrsp);
|
AstVar* createVariable(FileLine* fileline, string name, AstRange* arrayp, AstNode* attrsp);
|
||||||
AstNode* createSupplyExpr(FileLine* fileline, string name, int value);
|
AstNode* createSupplyExpr(FileLine* fileline, string name, int value);
|
||||||
AstText* createTextQuoted(FileLine* fileline, string text) {
|
AstText* createTextQuoted(FileLine* fileline, string text) {
|
||||||
@@ -113,7 +113,7 @@ public:
|
|||||||
}
|
}
|
||||||
return pkgp;
|
return pkgp;
|
||||||
}
|
}
|
||||||
AstNodeDType* addRange(AstBasicDType* dtypep, AstRange* rangesp) {
|
AstNodeDType* addRange(AstBasicDType* dtypep, AstRange* rangesp, bool isPacked) {
|
||||||
// If dtypep isn't basic, don't use this, call createArray() instead
|
// If dtypep isn't basic, don't use this, call createArray() instead
|
||||||
if (!rangesp) {
|
if (!rangesp) {
|
||||||
return dtypep;
|
return dtypep;
|
||||||
@@ -134,7 +134,7 @@ public:
|
|||||||
dtypep->rangep(finalp);
|
dtypep->rangep(finalp);
|
||||||
dtypep->implicit(false);
|
dtypep->implicit(false);
|
||||||
}
|
}
|
||||||
return createArray(dtypep, rangearraysp);
|
return createArray(dtypep, rangearraysp, isPacked);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
string deQuote(FileLine* fileline, string text);
|
string deQuote(FileLine* fileline, string text);
|
||||||
@@ -264,6 +264,7 @@ class AstSenTree;
|
|||||||
%token<fl> yAUTOMATIC "automatic"
|
%token<fl> yAUTOMATIC "automatic"
|
||||||
%token<fl> yBEGIN "begin"
|
%token<fl> yBEGIN "begin"
|
||||||
%token<fl> yBIT "bit"
|
%token<fl> yBIT "bit"
|
||||||
|
%token<fl> yBREAK "break"
|
||||||
%token<fl> yBUF "buf"
|
%token<fl> yBUF "buf"
|
||||||
%token<fl> yBUFIF0 "bufif0"
|
%token<fl> yBUFIF0 "bufif0"
|
||||||
%token<fl> yBUFIF1 "bufif1"
|
%token<fl> yBUFIF1 "bufif1"
|
||||||
@@ -275,6 +276,7 @@ class AstSenTree;
|
|||||||
%token<fl> yCLOCKING "clocking"
|
%token<fl> yCLOCKING "clocking"
|
||||||
%token<fl> yCMOS "cmos"
|
%token<fl> yCMOS "cmos"
|
||||||
%token<fl> yCONTEXT "context"
|
%token<fl> yCONTEXT "context"
|
||||||
|
%token<fl> yCONTINUE "continue"
|
||||||
%token<fl> yCOVER "cover"
|
%token<fl> yCOVER "cover"
|
||||||
%token<fl> yDEFAULT "default"
|
%token<fl> yDEFAULT "default"
|
||||||
%token<fl> yDEFPARAM "defparam"
|
%token<fl> yDEFPARAM "defparam"
|
||||||
@@ -340,6 +342,7 @@ class AstSenTree;
|
|||||||
%token<fl> yRCMOS "rcmos"
|
%token<fl> yRCMOS "rcmos"
|
||||||
%token<fl> yREG "reg"
|
%token<fl> yREG "reg"
|
||||||
%token<fl> yREPEAT "repeat"
|
%token<fl> yREPEAT "repeat"
|
||||||
|
%token<fl> yRETURN "return"
|
||||||
%token<fl> yRNMOS "rnmos"
|
%token<fl> yRNMOS "rnmos"
|
||||||
%token<fl> yRPMOS "rpmos"
|
%token<fl> yRPMOS "rpmos"
|
||||||
%token<fl> yRTRAN "rtran"
|
%token<fl> yRTRAN "rtran"
|
||||||
@@ -431,6 +434,8 @@ class AstSenTree;
|
|||||||
%token<fl> yVL_PARALLEL_CASE "/*verilator parallel_case*/"
|
%token<fl> yVL_PARALLEL_CASE "/*verilator parallel_case*/"
|
||||||
%token<fl> yVL_PUBLIC "/*verilator public*/"
|
%token<fl> yVL_PUBLIC "/*verilator public*/"
|
||||||
%token<fl> yVL_PUBLIC_FLAT "/*verilator public_flat*/"
|
%token<fl> yVL_PUBLIC_FLAT "/*verilator public_flat*/"
|
||||||
|
%token<fl> yVL_PUBLIC_FLAT_RD "/*verilator public_flat_rd*/"
|
||||||
|
%token<fl> yVL_PUBLIC_FLAT_RW "/*verilator public_flat_rw*/"
|
||||||
%token<fl> yVL_PUBLIC_MODULE "/*verilator public_module*/"
|
%token<fl> yVL_PUBLIC_MODULE "/*verilator public_module*/"
|
||||||
|
|
||||||
%token<fl> yP_TICK "'"
|
%token<fl> yP_TICK "'"
|
||||||
@@ -814,7 +819,7 @@ port<nodep>: // ==IEEE: port
|
|||||||
| portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE
|
| portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE
|
||||||
{ $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); }
|
{ $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); }
|
||||||
| portDirNetE signingE rangeList portSig variable_dimensionListE sigAttrListE
|
| portDirNetE signingE rangeList portSig variable_dimensionListE sigAttrListE
|
||||||
{ $$=$4; VARDTYPE(GRAMMARP->addRange(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2), $3)); $$->addNextNull(VARDONEP($$,$5,$6)); }
|
{ $$=$4; VARDTYPE(GRAMMARP->addRange(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2), $3,false)); $$->addNextNull(VARDONEP($$,$5,$6)); }
|
||||||
| portDirNetE /*implicit*/ portSig variable_dimensionListE sigAttrListE
|
| portDirNetE /*implicit*/ portSig variable_dimensionListE sigAttrListE
|
||||||
{ $$=$2; /*VARDTYPE-same*/ $$->addNextNull(VARDONEP($$,$3,$4)); }
|
{ $$=$2; /*VARDTYPE-same*/ $$->addNextNull(VARDONEP($$,$3,$4)); }
|
||||||
//
|
//
|
||||||
@@ -1026,7 +1031,7 @@ port_declaration<nodep>: // ==IEEE: port_declaration
|
|||||||
list_of_variable_decl_assignments { $$ = $6; }
|
list_of_variable_decl_assignments { $$ = $6; }
|
||||||
| port_directionReset port_declNetE yVAR implicit_typeE { VARDTYPE($4); }
|
| port_directionReset port_declNetE yVAR implicit_typeE { VARDTYPE($4); }
|
||||||
list_of_variable_decl_assignments { $$ = $6; }
|
list_of_variable_decl_assignments { $$ = $6; }
|
||||||
| port_directionReset port_declNetE signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($4->fileline(), LOGIC_IMPLICIT, $3),$4)); }
|
| port_directionReset port_declNetE signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($4->fileline(), LOGIC_IMPLICIT, $3),$4,false)); }
|
||||||
list_of_variable_decl_assignments { $$ = $6; }
|
list_of_variable_decl_assignments { $$ = $6; }
|
||||||
| port_directionReset port_declNetE signing { VARDTYPE(new AstBasicDType($<fl>3, LOGIC_IMPLICIT, $3)); }
|
| port_directionReset port_declNetE signing { VARDTYPE(new AstBasicDType($<fl>3, LOGIC_IMPLICIT, $3)); }
|
||||||
list_of_variable_decl_assignments { $$ = $5; }
|
list_of_variable_decl_assignments { $$ = $5; }
|
||||||
@@ -1076,7 +1081,7 @@ data_type<dtypep>: // ==IEEE: data_type
|
|||||||
// // This expansion also replicated elsewhere, IE data_type__AndID
|
// // This expansion also replicated elsewhere, IE data_type__AndID
|
||||||
data_typeNoRef { $$ = $1; }
|
data_typeNoRef { $$ = $1; }
|
||||||
// // IEEE: [ class_scope | package_scope ] type_identifier { packed_dimension }
|
// // IEEE: [ class_scope | package_scope ] type_identifier { packed_dimension }
|
||||||
| ps_type packed_dimensionListE { $$ = GRAMMARP->createArray($1,$2); }
|
| ps_type packed_dimensionListE { $$ = GRAMMARP->createArray($1,$2,true); }
|
||||||
//UNSUP class_scope_type packed_dimensionListE { UNSUP }
|
//UNSUP class_scope_type packed_dimensionListE { UNSUP }
|
||||||
// // IEEE: class_type
|
// // IEEE: class_type
|
||||||
//UNSUP class_typeWithoutId { $$ = $1; }
|
//UNSUP class_typeWithoutId { $$ = $1; }
|
||||||
@@ -1085,7 +1090,7 @@ data_type<dtypep>: // ==IEEE: data_type
|
|||||||
;
|
;
|
||||||
|
|
||||||
data_typeBasic<dtypep>: // IEEE: part of data_type
|
data_typeBasic<dtypep>: // IEEE: part of data_type
|
||||||
integer_vector_type signingE rangeListE { $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3); }
|
integer_vector_type signingE rangeListE { $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3,true); }
|
||||||
| integer_atom_type signingE { $1->setSignedState($2); $$ = $1; }
|
| integer_atom_type signingE { $1->setSignedState($2); $$ = $1; }
|
||||||
//UNSUP non_integer_type { UNSUP }
|
//UNSUP non_integer_type { UNSUP }
|
||||||
;
|
;
|
||||||
@@ -1187,12 +1192,12 @@ enum_base_typeE<dtypep>: // IEEE: enum_base_type
|
|||||||
/* empty */ { $$ = new AstBasicDType(CRELINE(),AstBasicDTypeKwd::INT); }
|
/* empty */ { $$ = new AstBasicDType(CRELINE(),AstBasicDTypeKwd::INT); }
|
||||||
// // Not in spec, but obviously "enum [1:0]" should work
|
// // Not in spec, but obviously "enum [1:0]" should work
|
||||||
// // implicit_type expanded, without empty
|
// // implicit_type expanded, without empty
|
||||||
| signingE rangeList { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2); }
|
| signingE rangeList { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2,false); }
|
||||||
| signing { $$ = new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $1); }
|
| signing { $$ = new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $1); }
|
||||||
//
|
//
|
||||||
| integer_atom_type signingE { $1->setSignedState($2); $$ = $1; }
|
| integer_atom_type signingE { $1->setSignedState($2); $$ = $1; }
|
||||||
| integer_vector_type signingE rangeListE { $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3); }
|
| integer_vector_type signingE rangeListE { $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3,false); }
|
||||||
| yaID__aTYPE rangeListE { $$ = GRAMMARP->createArray(new AstRefDType($<fl>1, *$1), $2); }
|
| yaID__aTYPE rangeListE { $$ = GRAMMARP->createArray(new AstRefDType($<fl>1, *$1), $2, false); }
|
||||||
;
|
;
|
||||||
|
|
||||||
enum_nameList<nodep>:
|
enum_nameList<nodep>:
|
||||||
@@ -1241,7 +1246,7 @@ data_declarationVarFront: // IEEE: part of data_declaration
|
|||||||
// // implicit_type expanded into /*empty*/ or "signingE rangeList"
|
// // implicit_type expanded into /*empty*/ or "signingE rangeList"
|
||||||
constE yVAR lifetimeE data_type { /*VARRESET-in-ddVar*/ VARDTYPE($4); }
|
constE yVAR lifetimeE data_type { /*VARRESET-in-ddVar*/ VARDTYPE($4); }
|
||||||
| constE yVAR lifetimeE { /*VARRESET-in-ddVar*/ VARDTYPE(new AstBasicDType($<fl>2, LOGIC_IMPLICIT)); }
|
| constE yVAR lifetimeE { /*VARRESET-in-ddVar*/ VARDTYPE(new AstBasicDType($<fl>2, LOGIC_IMPLICIT)); }
|
||||||
| constE yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($<fl>2, LOGIC_IMPLICIT, $4),$5)); }
|
| constE yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($<fl>2, LOGIC_IMPLICIT, $4),$5,false)); }
|
||||||
//
|
//
|
||||||
// // Expanded: "constE lifetimeE data_type"
|
// // Expanded: "constE lifetimeE data_type"
|
||||||
| /**/ data_type { /*VARRESET-in-ddVar*/ VARDTYPE($1); }
|
| /**/ data_type { /*VARRESET-in-ddVar*/ VARDTYPE($1); }
|
||||||
@@ -1258,13 +1263,13 @@ constE: // IEEE: part of data_declaration
|
|||||||
implicit_typeE<dtypep>: // IEEE: part of *data_type_or_implicit
|
implicit_typeE<dtypep>: // IEEE: part of *data_type_or_implicit
|
||||||
// // Also expanded in data_declaration
|
// // Also expanded in data_declaration
|
||||||
/* empty */ { $$ = NULL; }
|
/* empty */ { $$ = NULL; }
|
||||||
| signingE rangeList { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2); }
|
| signingE rangeList { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2,false); }
|
||||||
| signing { $$ = new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $1); }
|
| signing { $$ = new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $1); }
|
||||||
;
|
;
|
||||||
|
|
||||||
type_declaration<nodep>: // ==IEEE: type_declaration
|
type_declaration<nodep>: // ==IEEE: type_declaration
|
||||||
// // Use idAny, as we can redeclare a typedef on an existing typedef
|
// // Use idAny, as we can redeclare a typedef on an existing typedef
|
||||||
/*U*/ yTYPEDEF data_type idAny variable_dimensionListE ';' { $$ = new AstTypedef($<fl>1, *$3, GRAMMARP->createArray($2,$4)); SYMP->reinsert($$); }
|
yTYPEDEF data_type idAny variable_dimensionListE ';' { $$ = new AstTypedef($<fl>1, *$3, GRAMMARP->createArray($2,$4,false)); SYMP->reinsert($$); }
|
||||||
//UNSUP yTYPEDEF id/*interface*/ '.' idAny/*type*/ idAny/*type*/ ';' { $$ = NULL; $1->v3error("Unsupported: SystemVerilog 2005 typedef in this context"); } //UNSUP
|
//UNSUP yTYPEDEF id/*interface*/ '.' idAny/*type*/ idAny/*type*/ ';' { $$ = NULL; $1->v3error("Unsupported: SystemVerilog 2005 typedef in this context"); } //UNSUP
|
||||||
// // Combines into above "data_type id" rule
|
// // Combines into above "data_type id" rule
|
||||||
// // Verilator: Not important what it is in the AST, just need to make sure the yaID__aTYPE gets returned
|
// // Verilator: Not important what it is in the AST, just need to make sure the yaID__aTYPE gets returned
|
||||||
@@ -1436,6 +1441,7 @@ genvar_iteration<nodep>: // ==IEEE: genvar_iteration
|
|||||||
| varRefBase yP_SRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftR ($2,$1->cloneTree(true),$3)); }
|
| varRefBase yP_SRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftR ($2,$1->cloneTree(true),$3)); }
|
||||||
| varRefBase yP_SSRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftRS($2,$1->cloneTree(true),$3)); }
|
| varRefBase yP_SSRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftRS($2,$1->cloneTree(true),$3)); }
|
||||||
// // inc_or_dec_operator
|
// // inc_or_dec_operator
|
||||||
|
// When support ++ as a real AST type, maybe AstWhile::precondsp() becomes generic AstMathStmt?
|
||||||
| yP_PLUSPLUS varRefBase { $$ = new AstAssign($1,$2,new AstAdd ($1,$2->cloneTree(true),new AstConst($1,V3Number($1,"'b1")))); }
|
| yP_PLUSPLUS varRefBase { $$ = new AstAssign($1,$2,new AstAdd ($1,$2->cloneTree(true),new AstConst($1,V3Number($1,"'b1")))); }
|
||||||
| yP_MINUSMINUS varRefBase { $$ = new AstAssign($1,$2,new AstSub ($1,$2->cloneTree(true),new AstConst($1,V3Number($1,"'b1")))); }
|
| yP_MINUSMINUS varRefBase { $$ = new AstAssign($1,$2,new AstSub ($1,$2->cloneTree(true),new AstConst($1,V3Number($1,"'b1")))); }
|
||||||
| varRefBase yP_PLUSPLUS { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true),new AstConst($2,V3Number($2,"'b1")))); }
|
| varRefBase yP_PLUSPLUS { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true),new AstConst($2,V3Number($2,"'b1")))); }
|
||||||
@@ -1537,6 +1543,10 @@ sigAttr<nodep>:
|
|||||||
| yVL_CLOCK_ENABLE { $$ = new AstAttrOf($1,AstAttrType::VAR_CLOCK_ENABLE); }
|
| yVL_CLOCK_ENABLE { $$ = new AstAttrOf($1,AstAttrType::VAR_CLOCK_ENABLE); }
|
||||||
| yVL_PUBLIC { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC); }
|
| yVL_PUBLIC { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC); }
|
||||||
| yVL_PUBLIC_FLAT { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT); }
|
| yVL_PUBLIC_FLAT { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT); }
|
||||||
|
| yVL_PUBLIC_FLAT_RD { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT_RD); }
|
||||||
|
| yVL_PUBLIC_FLAT_RW { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT_RW); }
|
||||||
|
| yVL_PUBLIC_FLAT_RW attr_event_control { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT_RW);
|
||||||
|
$$ = $$->addNext(new AstAlwaysPublic($1,$2,NULL)); }
|
||||||
| yVL_ISOLATE_ASSIGNMENTS { $$ = new AstAttrOf($1,AstAttrType::VAR_ISOLATE_ASSIGNMENTS); }
|
| yVL_ISOLATE_ASSIGNMENTS { $$ = new AstAttrOf($1,AstAttrType::VAR_ISOLATE_ASSIGNMENTS); }
|
||||||
| yVL_SFORMAT { $$ = new AstAttrOf($1,AstAttrType::VAR_SFORMAT); }
|
| yVL_SFORMAT { $$ = new AstAttrOf($1,AstAttrType::VAR_SFORMAT); }
|
||||||
;
|
;
|
||||||
@@ -1553,7 +1563,7 @@ rangeList<rangep>: // IEEE: {packed_dimension}
|
|||||||
|
|
||||||
wirerangeE<dtypep>:
|
wirerangeE<dtypep>:
|
||||||
/* empty */ { $$ = new AstBasicDType(CRELINE(), LOGIC); } // not implicit
|
/* empty */ { $$ = new AstBasicDType(CRELINE(), LOGIC); } // not implicit
|
||||||
| rangeList { $$ = GRAMMARP->addRange(new AstBasicDType(CRELINE(), LOGIC),$1); } // not implicit
|
| rangeList { $$ = GRAMMARP->addRange(new AstBasicDType(CRELINE(), LOGIC),$1,false); } // not implicit
|
||||||
;
|
;
|
||||||
|
|
||||||
// IEEE: select
|
// IEEE: select
|
||||||
@@ -1661,13 +1671,18 @@ cellpinItemE<pinp>: // IEEE: named_port_connection + named_parameter_assignment
|
|||||||
| '.' idSVKwd { $$ = NULL; PINNUMINC(); }
|
| '.' idSVKwd { $$ = NULL; PINNUMINC(); }
|
||||||
| '.' idAny { $$ = new AstPin($1,PINNUMINC(),*$2,new AstVarRef($1,*$2,false)); $$->svImplicit(true);}
|
| '.' idAny { $$ = new AstPin($1,PINNUMINC(),*$2,new AstVarRef($1,*$2,false)); $$->svImplicit(true);}
|
||||||
| '.' idAny '(' ')' { $$ = NULL; PINNUMINC(); }
|
| '.' idAny '(' ')' { $$ = NULL; PINNUMINC(); }
|
||||||
|
// // mintypmax is expanded here, as it might be a UDP or gate primitive
|
||||||
| '.' idAny '(' expr ')' { $$ = new AstPin($1,PINNUMINC(),*$2,$4); }
|
| '.' idAny '(' expr ')' { $$ = new AstPin($1,PINNUMINC(),*$2,$4); }
|
||||||
|
//UNSUP '.' idAny '(' expr ':' expr ')' { }
|
||||||
|
//UNSUP '.' idAny '(' expr ':' expr ':' expr ')' { }
|
||||||
// // For parameters
|
// // For parameters
|
||||||
//UNSUP '.' idAny '(' data_type ')' { PINDONE($1,$2,$4); GRAMMARP->pinNumInc(); }
|
//UNSUP '.' idAny '(' data_type ')' { PINDONE($1,$2,$4); GRAMMARP->pinNumInc(); }
|
||||||
// // For parameters
|
// // For parameters
|
||||||
//UNSUP data_type { PINDONE($1->fileline(),"",$1); GRAMMARP->pinNumInc(); }
|
//UNSUP data_type { PINDONE($1->fileline(),"",$1); GRAMMARP->pinNumInc(); }
|
||||||
//
|
//
|
||||||
| expr { $$ = new AstPin($1->fileline(),PINNUMINC(),"",$1); }
|
| expr { $$ = new AstPin($1->fileline(),PINNUMINC(),"",$1); }
|
||||||
|
//UNSUP expr ':' expr { }
|
||||||
|
//UNSUP expr ':' expr ':' expr { }
|
||||||
// // Floatnum should only occur with UDPs, but since ports aren't floats, it's legal to round always
|
// // Floatnum should only occur with UDPs, but since ports aren't floats, it's legal to round always
|
||||||
| yaFLOATNUM { $$ = new AstPin($<fl>1,PINNUMINC(),"",new AstConst($<fl>1,AstConst::Unsized32(),(int)(($1<0)?($1-0.5):($1+0.5)))); }
|
| yaFLOATNUM { $$ = new AstPin($<fl>1,PINNUMINC(),"",new AstConst($<fl>1,AstConst::Unsized32(),(int)(($1<0)?($1-0.5):($1+0.5)))); }
|
||||||
;
|
;
|
||||||
@@ -1675,6 +1690,12 @@ cellpinItemE<pinp>: // IEEE: named_port_connection + named_parameter_assignment
|
|||||||
//************************************************
|
//************************************************
|
||||||
// EventControl lists
|
// EventControl lists
|
||||||
|
|
||||||
|
attr_event_control<sentreep>: // ==IEEE: event_control
|
||||||
|
'@' '(' event_expression ')' { $$ = new AstSenTree($1,$3); }
|
||||||
|
| '@' '(' '*' ')' { $$ = NULL; }
|
||||||
|
| '@' '*' { $$ = NULL; }
|
||||||
|
;
|
||||||
|
|
||||||
event_controlE<sentreep>:
|
event_controlE<sentreep>:
|
||||||
/* empty */ { $$ = NULL; }
|
/* empty */ { $$ = NULL; }
|
||||||
| event_control { $$ = $1; }
|
| event_control { $$ = $1; }
|
||||||
@@ -1831,7 +1852,7 @@ statement_item<nodep>: // IEEE: statement_item
|
|||||||
| statementVerilatorPragmas { $$ = $1; }
|
| statementVerilatorPragmas { $$ = $1; }
|
||||||
//
|
//
|
||||||
// // IEEE: disable_statement
|
// // IEEE: disable_statement
|
||||||
//UNSUP yDISABLE hierarchical_identifier/*task_or_block*/ ';' { UNSUP }
|
//UNSUP yDISABLE idAny/*hierarchical_identifier-task_or_block*/ ';' { UNSUP }
|
||||||
//UNSUP yDISABLE yFORK ';' { UNSUP }
|
//UNSUP yDISABLE yFORK ';' { UNSUP }
|
||||||
// // IEEE: event_trigger
|
// // IEEE: event_trigger
|
||||||
//UNSUP yP_MINUSGT hierarchical_identifier/*event*/ ';' { UNSUP }
|
//UNSUP yP_MINUSGT hierarchical_identifier/*event*/ ';' { UNSUP }
|
||||||
@@ -1842,15 +1863,15 @@ statement_item<nodep>: // IEEE: statement_item
|
|||||||
| yWHILE '(' expr ')' stmtBlock { $$ = new AstWhile($1,$3,$5);}
|
| yWHILE '(' expr ')' stmtBlock { $$ = new AstWhile($1,$3,$5);}
|
||||||
// // for's first ';' is in for_initalization
|
// // for's first ';' is in for_initalization
|
||||||
| yFOR '(' for_initialization expr ';' for_stepE ')' stmtBlock
|
| yFOR '(' for_initialization expr ';' for_stepE ')' stmtBlock
|
||||||
{ $$ = new AstBegin($1,"",$3); $3->addNext(new AstFor($1,NULL,$4,$6,$8));}
|
{ $$ = new AstBegin($1,"",$3); $3->addNext(new AstWhile($1, $4,$8,$6)); }
|
||||||
| yDO stmtBlock yWHILE '(' expr ')' { $$ = $2->cloneTree(true); $$->addNext(new AstWhile($1,$5,$2));}
|
| yDO stmtBlock yWHILE '(' expr ')' ';' { $$ = $2->cloneTree(true); $$->addNext(new AstWhile($1,$5,$2));}
|
||||||
//UNSUP yFOREACH '(' idClassForeach/*array_id[loop_variables]*/ ')' stmt { UNSUP }
|
//UNSUP yFOREACH '(' idClassForeach/*array_id[loop_variables]*/ ')' stmt { UNSUP }
|
||||||
//
|
//
|
||||||
// // IEEE: jump_statement
|
// // IEEE: jump_statement
|
||||||
//UNSUP yRETURN ';' { UNSUP }
|
| yRETURN ';' { $$ = new AstReturn($1); }
|
||||||
//UNSUP yRETURN expr ';' { UNSUP }
|
| yRETURN expr ';' { $$ = new AstReturn($1,$2); }
|
||||||
//UNSUP yBREAK ';' { UNSUP }
|
| yBREAK ';' { $$ = new AstBreak($1); }
|
||||||
//UNSUP yCONTINUE ';' { UNSUP }
|
| yCONTINUE ';' { $$ = new AstContinue($1); }
|
||||||
//
|
//
|
||||||
//UNSUP par_block { $$ = $1; }
|
//UNSUP par_block { $$ = $1; }
|
||||||
// // IEEE: procedural_timing_control_statement + procedural_timing_control
|
// // IEEE: procedural_timing_control_statement + procedural_timing_control
|
||||||
@@ -2141,7 +2162,7 @@ funcId<ftaskp>: // IEEE: function_data_type_or_implicit + part of function_bod
|
|||||||
SYMP->pushNewUnder($$, NULL); }
|
SYMP->pushNewUnder($$, NULL); }
|
||||||
| signingE rangeList tfIdScoped
|
| signingE rangeList tfIdScoped
|
||||||
{ $$ = new AstFunc ($<fl>3,*$<strp>3,NULL,
|
{ $$ = new AstFunc ($<fl>3,*$<strp>3,NULL,
|
||||||
GRAMMARP->addRange(new AstBasicDType($<fl>3, LOGIC_IMPLICIT, $1), $2));
|
GRAMMARP->addRange(new AstBasicDType($<fl>3, LOGIC_IMPLICIT, $1), $2,false));
|
||||||
SYMP->pushNewUnder($$, NULL); }
|
SYMP->pushNewUnder($$, NULL); }
|
||||||
| signing tfIdScoped
|
| signing tfIdScoped
|
||||||
{ $$ = new AstFunc ($<fl>2,*$<strp>2,NULL,
|
{ $$ = new AstFunc ($<fl>2,*$<strp>2,NULL,
|
||||||
@@ -2211,14 +2232,14 @@ tf_port_item<nodep>: // ==IEEE: tf_port_item
|
|||||||
|
|
||||||
tf_port_itemFront: // IEEE: part of tf_port_item, which has the data type
|
tf_port_itemFront: // IEEE: part of tf_port_item, which has the data type
|
||||||
data_type { VARDTYPE($1); }
|
data_type { VARDTYPE($1); }
|
||||||
| signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1), $2)); }
|
| signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1), $2, false)); }
|
||||||
| signing { VARDTYPE(new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $1)); }
|
| signing { VARDTYPE(new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $1)); }
|
||||||
| yVAR data_type { VARDTYPE($2); }
|
| yVAR data_type { VARDTYPE($2); }
|
||||||
| yVAR implicit_typeE { VARDTYPE($2); }
|
| yVAR implicit_typeE { VARDTYPE($2); }
|
||||||
//
|
//
|
||||||
| tf_port_itemDir /*implicit*/ { VARDTYPE(NULL); /*default_nettype-see spec*/ }
|
| tf_port_itemDir /*implicit*/ { VARDTYPE(NULL); /*default_nettype-see spec*/ }
|
||||||
| tf_port_itemDir data_type { VARDTYPE($2); }
|
| tf_port_itemDir data_type { VARDTYPE($2); }
|
||||||
| tf_port_itemDir signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2),$3)); }
|
| tf_port_itemDir signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2),$3,false)); }
|
||||||
| tf_port_itemDir signing { VARDTYPE(new AstBasicDType($<fl>2, LOGIC_IMPLICIT, $2)); }
|
| tf_port_itemDir signing { VARDTYPE(new AstBasicDType($<fl>2, LOGIC_IMPLICIT, $2)); }
|
||||||
| tf_port_itemDir yVAR data_type { VARDTYPE($3); }
|
| tf_port_itemDir yVAR data_type { VARDTYPE($3); }
|
||||||
| tf_port_itemDir yVAR implicit_typeE { VARDTYPE($3); }
|
| tf_port_itemDir yVAR implicit_typeE { VARDTYPE($3); }
|
||||||
@@ -2738,9 +2759,14 @@ specifyJunk:
|
|||||||
;
|
;
|
||||||
|
|
||||||
specparam_declaration<nodep>: // ==IEEE: specparam_declaration
|
specparam_declaration<nodep>: // ==IEEE: specparam_declaration
|
||||||
ySPECPARAM junkToSemi ';' { $$ = NULL; }
|
ySPECPARAM junkToSemiList ';' { $$ = NULL; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
junkToSemiList:
|
||||||
|
junkToSemi { } /* ignored */
|
||||||
|
| junkToSemiList junkToSemi { } /* ignored */
|
||||||
|
;
|
||||||
|
|
||||||
junkToSemi:
|
junkToSemi:
|
||||||
BISONPRE_NOT(';',yENDSPECIFY,yENDMODULE) { }
|
BISONPRE_NOT(';',yENDSPECIFY,yENDMODULE) { }
|
||||||
| error {}
|
| error {}
|
||||||
@@ -2882,16 +2908,13 @@ concurrent_assertion_statement<nodep>: // ==IEEE: concurrent_assertion_statement
|
|||||||
|
|
||||||
property_spec<nodep>: // IEEE: property_spec
|
property_spec<nodep>: // IEEE: property_spec
|
||||||
//UNSUP: This rule has been super-specialized to what is supported now
|
//UNSUP: This rule has been super-specialized to what is supported now
|
||||||
'@' '(' senitemEdge ')' property_specDisable expr { $$ = new AstPslClocked($1,$3,$5,$6); }
|
'@' '(' senitemEdge ')' yDISABLE yIFF '(' expr ')' expr
|
||||||
|
{ $$ = new AstPslClocked($1,$3,$8,$10); }
|
||||||
| '@' '(' senitemEdge ')' expr { $$ = new AstPslClocked($1,$3,NULL,$5); }
|
| '@' '(' senitemEdge ')' expr { $$ = new AstPslClocked($1,$3,NULL,$5); }
|
||||||
| property_specDisable expr { $$ = new AstPslClocked($2->fileline(),NULL,$1,$2); }
|
| yDISABLE yIFF '(' expr ')' expr { $$ = new AstPslClocked($4->fileline(),NULL,$4,$6); }
|
||||||
| expr { $$ = new AstPslClocked($1->fileline(),NULL,NULL,$1); }
|
| expr { $$ = new AstPslClocked($1->fileline(),NULL,NULL,$1); }
|
||||||
;
|
;
|
||||||
|
|
||||||
property_specDisable<nodep>: // IEEE: part of property_spec
|
|
||||||
yDISABLE yIFF '(' expr ')' { $$ = $4; }
|
|
||||||
;
|
|
||||||
|
|
||||||
immediate_assert_statement<nodep>: // ==IEEE: immediate_assert_statement
|
immediate_assert_statement<nodep>: // ==IEEE: immediate_assert_statement
|
||||||
// // action_block expanded here, for compatibility with AstVAssert
|
// // action_block expanded here, for compatibility with AstVAssert
|
||||||
yASSERT '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE { $$ = new AstVAssert($1,$3,$5, GRAMMARP->createDisplayError($1)); }
|
yASSERT '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE { $$ = new AstVAssert($1,$3,$5, GRAMMARP->createDisplayError($1)); }
|
||||||
@@ -3045,7 +3068,7 @@ AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, string name, int v
|
|||||||
return nodep;
|
return nodep;
|
||||||
}
|
}
|
||||||
|
|
||||||
AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstRange* rangep) {
|
AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstRange* rangep, bool isPacked) {
|
||||||
// Split RANGE0-RANGE1-RANGE2 into ARRAYDTYPE0(ARRAYDTYPE1(ARRAYDTYPE2(BASICTYPE3),RANGE),RANGE)
|
// Split RANGE0-RANGE1-RANGE2 into ARRAYDTYPE0(ARRAYDTYPE1(ARRAYDTYPE2(BASICTYPE3),RANGE),RANGE)
|
||||||
AstNodeDType* arrayp = basep;
|
AstNodeDType* arrayp = basep;
|
||||||
if (rangep) { // Maybe no range - return unmodified base type
|
if (rangep) { // Maybe no range - return unmodified base type
|
||||||
@@ -3053,7 +3076,7 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstRange* rangep)
|
|||||||
while (rangep) {
|
while (rangep) {
|
||||||
AstRange* prevp = rangep->backp()->castRange();
|
AstRange* prevp = rangep->backp()->castRange();
|
||||||
if (prevp) rangep->unlinkFrBack();
|
if (prevp) rangep->unlinkFrBack();
|
||||||
arrayp = new AstArrayDType(rangep->fileline(), arrayp, rangep);
|
arrayp = new AstArrayDType(rangep->fileline(), arrayp, rangep, isPacked);
|
||||||
rangep = prevp;
|
rangep = prevp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3085,7 +3108,7 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, string name, AstRange
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Split RANGE0-RANGE1-RANGE2 into ARRAYDTYPE0(ARRAYDTYPE1(ARRAYDTYPE2(BASICTYPE3),RANGE),RANGE)
|
// Split RANGE0-RANGE1-RANGE2 into ARRAYDTYPE0(ARRAYDTYPE1(ARRAYDTYPE2(BASICTYPE3),RANGE),RANGE)
|
||||||
AstNodeDType* arrayDTypep = createArray(dtypep,arrayp);
|
AstNodeDType* arrayDTypep = createArray(dtypep,arrayp,false);
|
||||||
|
|
||||||
AstVar* nodep = new AstVar(fileline, type, name, arrayDTypep);
|
AstVar* nodep = new AstVar(fileline, type, name, arrayDTypep);
|
||||||
nodep->addAttrsp(attrsp);
|
nodep->addAttrsp(attrsp);
|
||||||
|
|||||||
+40
-4
@@ -40,6 +40,7 @@ our @Orig_ARGV = @ARGV;
|
|||||||
our @Orig_ARGV_Sw; foreach (@Orig_ARGV) { push @Orig_ARGV_Sw, $_ if /^-/ && !/^-j/; }
|
our @Orig_ARGV_Sw; foreach (@Orig_ARGV) { push @Orig_ARGV_Sw, $_ if /^-/ && !/^-j/; }
|
||||||
|
|
||||||
$Debug = 0;
|
$Debug = 0;
|
||||||
|
my $opt_atsim;
|
||||||
my $opt_benchmark;
|
my $opt_benchmark;
|
||||||
my @opt_tests;
|
my @opt_tests;
|
||||||
my $opt_gdb;
|
my $opt_gdb;
|
||||||
@@ -61,6 +62,7 @@ Getopt::Long::config ("pass_through");
|
|||||||
if (! GetOptions (
|
if (! GetOptions (
|
||||||
"benchmark:i" => sub { $opt_benchmark = $_[1] ? $_[1] : 1; },
|
"benchmark:i" => sub { $opt_benchmark = $_[1] ? $_[1] : 1; },
|
||||||
"debug" => \&debug,
|
"debug" => \&debug,
|
||||||
|
"atsim|athdl!"=> \$opt_atsim,
|
||||||
"gdb!" => \$opt_gdb,
|
"gdb!" => \$opt_gdb,
|
||||||
"gdbbt!" => \$opt_gdbbt,
|
"gdbbt!" => \$opt_gdbbt,
|
||||||
"gdbsim!" => \$opt_gdbsim,
|
"gdbsim!" => \$opt_gdbsim,
|
||||||
@@ -86,7 +88,7 @@ $opt_jobs = calc_jobs() if defined $opt_jobs && $opt_jobs==0;
|
|||||||
|
|
||||||
$Fork->max_proc($opt_jobs);
|
$Fork->max_proc($opt_jobs);
|
||||||
|
|
||||||
if (!$opt_iv && !$opt_vcs && !$opt_nc && !$opt_vlt) {
|
if (!$opt_atsim && !$opt_iv && !$opt_vcs && !$opt_nc && !$opt_vlt) {
|
||||||
$opt_vlt = 1;
|
$opt_vlt = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,6 +103,7 @@ my $leftcnt=0; my $okcnt=0; my $failcnt=0; my $skcnt=0;
|
|||||||
my @fails;
|
my @fails;
|
||||||
|
|
||||||
foreach my $testpl (@opt_tests) {
|
foreach my $testpl (@opt_tests) {
|
||||||
|
one_test(pl_filename => $testpl, atsim=>1) if $opt_atsim;
|
||||||
one_test(pl_filename => $testpl, iv=>1) if $opt_iv;
|
one_test(pl_filename => $testpl, iv=>1) if $opt_iv;
|
||||||
one_test(pl_filename => $testpl, nc=>1) if $opt_nc;
|
one_test(pl_filename => $testpl, nc=>1) if $opt_nc;
|
||||||
one_test(pl_filename => $testpl, vcs=>1) if $opt_vcs;
|
one_test(pl_filename => $testpl, vcs=>1) if $opt_vcs;
|
||||||
@@ -183,7 +186,7 @@ sub parameter {
|
|||||||
elsif ($param =~ /\.pl/) {
|
elsif ($param =~ /\.pl/) {
|
||||||
push @opt_tests, $param;
|
push @opt_tests, $param;
|
||||||
}
|
}
|
||||||
elsif ($param =~ /^--debugi/) {
|
elsif ($param =~ /^-?-debugi/) {
|
||||||
push @Opt_Driver_Verilator_Flags, $param;
|
push @Opt_Driver_Verilator_Flags, $param;
|
||||||
$_Parameter_Next_Level = $param;
|
$_Parameter_Next_Level = $param;
|
||||||
}
|
}
|
||||||
@@ -261,6 +264,12 @@ sub new {
|
|||||||
v_flags2 => [], # Overridden in some sim files
|
v_flags2 => [], # Overridden in some sim files
|
||||||
v_other_filenames => [], # After the filename so we can spec multiple files
|
v_other_filenames => [], # After the filename so we can spec multiple files
|
||||||
all_run_flags => [],
|
all_run_flags => [],
|
||||||
|
# ATSIM
|
||||||
|
atsim => 0,
|
||||||
|
atsim_flags => [split(/\s+/,"-c +sv +define+atsim"),
|
||||||
|
"+sv_dir+$self->{obj_dir}/.athdl_compile"],
|
||||||
|
atsim_flags2 => [], # Overridden in some sim files
|
||||||
|
atsimrun_flags => [],
|
||||||
# IV
|
# IV
|
||||||
iv => 0,
|
iv => 0,
|
||||||
iv_flags => [split(/\s+/,"+define+iverilog -o $self->{obj_dir}/simiv")],
|
iv_flags => [split(/\s+/,"+define+iverilog -o $self->{obj_dir}/simiv")],
|
||||||
@@ -288,6 +297,7 @@ sub new {
|
|||||||
%$self};
|
%$self};
|
||||||
bless $self, $class;
|
bless $self, $class;
|
||||||
|
|
||||||
|
$self->{mode} ||= "atsim" if $self->{atsim};
|
||||||
$self->{mode} ||= "vcs" if $self->{vcs};
|
$self->{mode} ||= "vcs" if $self->{vcs};
|
||||||
$self->{mode} ||= "vlt" if $self->{vlt};
|
$self->{mode} ||= "vlt" if $self->{vlt};
|
||||||
$self->{mode} ||= "nc" if $self->{nc};
|
$self->{mode} ||= "nc" if $self->{nc};
|
||||||
@@ -387,6 +397,20 @@ sub compile {
|
|||||||
$self->{trace} = 1 if ($opt_trace || $checkflags =~ /-trace\b/);
|
$self->{trace} = 1 if ($opt_trace || $checkflags =~ /-trace\b/);
|
||||||
$self->{coverage} = 1 if ($checkflags =~ /-coverage\b/);
|
$self->{coverage} = 1 if ($checkflags =~ /-coverage\b/);
|
||||||
|
|
||||||
|
if ($param{atsim}) {
|
||||||
|
$self->_make_top();
|
||||||
|
$self->_run(logfile=>"$self->{obj_dir}/atsim_compile.log",
|
||||||
|
fails=>$param{fails},
|
||||||
|
cmd=>[($ENV{VERILATOR_ATSIM}||"atsim"),
|
||||||
|
@{$param{atsim_flags}},
|
||||||
|
@{$param{atsim_flags2}},
|
||||||
|
@{$param{v_flags}},
|
||||||
|
@{$param{v_flags2}},
|
||||||
|
$param{top_filename},
|
||||||
|
$param{top_shell_filename},
|
||||||
|
@{$param{v_other_filenames}},
|
||||||
|
]);
|
||||||
|
}
|
||||||
if ($param{vcs}) {
|
if ($param{vcs}) {
|
||||||
$self->_make_top();
|
$self->_make_top();
|
||||||
$self->_run(logfile=>"$self->{obj_dir}/vcs_compile.log",
|
$self->_run(logfile=>"$self->{obj_dir}/vcs_compile.log",
|
||||||
@@ -511,6 +535,14 @@ sub execute {
|
|||||||
my $run_env = $param{run_env};
|
my $run_env = $param{run_env};
|
||||||
$run_env .= ' ' if $run_env;
|
$run_env .= ' ' if $run_env;
|
||||||
|
|
||||||
|
if ($param{atsim}) {
|
||||||
|
$self->_run(logfile=>"$self->{obj_dir}/atsim_sim.log",
|
||||||
|
fails=>$param{fails},
|
||||||
|
cmd=>["echo q | ".$run_env."$self->{obj_dir}/athdl_sv",
|
||||||
|
@{$param{atsimrun_flags}},
|
||||||
|
@{$param{all_run_flags}},
|
||||||
|
]);
|
||||||
|
}
|
||||||
if ($param{iv}) {
|
if ($param{iv}) {
|
||||||
$self->_run(logfile=>"$self->{obj_dir}/iv_sim.log",
|
$self->_run(logfile=>"$self->{obj_dir}/iv_sim.log",
|
||||||
fails=>$param{fails},
|
fails=>$param{fails},
|
||||||
@@ -522,7 +554,7 @@ sub execute {
|
|||||||
if ($param{nc}) {
|
if ($param{nc}) {
|
||||||
$self->_run(logfile=>"$self->{obj_dir}/nc_sim.log",
|
$self->_run(logfile=>"$self->{obj_dir}/nc_sim.log",
|
||||||
fails=>$param{fails},
|
fails=>$param{fails},
|
||||||
cmd=>[$run_env.($ENV{VERILATOR_NCVERILOG}||"ncverilog"),
|
cmd=>["echo q | ".$run_env.($ENV{VERILATOR_NCVERILOG}||"ncverilog"),
|
||||||
@{$param{ncrun_flags}},
|
@{$param{ncrun_flags}},
|
||||||
@{$param{all_run_flags}},
|
@{$param{all_run_flags}},
|
||||||
]);
|
]);
|
||||||
@@ -531,7 +563,7 @@ sub execute {
|
|||||||
#my $fh = IO::File->new(">simv.key") or die "%Error: $! simv.key,";
|
#my $fh = IO::File->new(">simv.key") or die "%Error: $! simv.key,";
|
||||||
#$fh->print("quit\n"); $fh->close;
|
#$fh->print("quit\n"); $fh->close;
|
||||||
$self->_run(logfile=>"$self->{obj_dir}/vcs_sim.log",
|
$self->_run(logfile=>"$self->{obj_dir}/vcs_sim.log",
|
||||||
cmd=>[$run_env."./simv",
|
cmd=>["echo q | ".$run_env."./simv",
|
||||||
@{$param{all_run_flags}},
|
@{$param{all_run_flags}},
|
||||||
],
|
],
|
||||||
%param,
|
%param,
|
||||||
@@ -1166,6 +1198,10 @@ driver.pl invokes Verilator or another simulator on each little test file.
|
|||||||
|
|
||||||
=over 4
|
=over 4
|
||||||
|
|
||||||
|
=item --atsim
|
||||||
|
|
||||||
|
Run using ATSIM.
|
||||||
|
|
||||||
=item --benchmark [<cycles>]
|
=item --benchmark [<cycles>]
|
||||||
|
|
||||||
Show execution times of each step. If an optional number is given,
|
Show execution times of each step. If an optional number is given,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
|||||||
# Version 2.0.
|
# Version 2.0.
|
||||||
|
|
||||||
compile (
|
compile (
|
||||||
v_flags2 => ["--stats"],
|
verilator_flags2 => ["--stats"],
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($Self->{v3}) {
|
if ($Self->{v3}) {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
|||||||
# Version 2.0.
|
# Version 2.0.
|
||||||
|
|
||||||
compile (
|
compile (
|
||||||
v_flags2 => ["--stats"],
|
verilator_flags2 => ["--stats"],
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($Self->{v3}) {
|
if ($Self->{v3}) {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ compile (
|
|||||||
);
|
);
|
||||||
|
|
||||||
execute (
|
execute (
|
||||||
fails => 1,
|
fails => $Self->{vlt},
|
||||||
);
|
);
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ compile (
|
|||||||
|
|
||||||
execute (
|
execute (
|
||||||
check_finished=>0,
|
check_finished=>0,
|
||||||
fails=>1,
|
fails=> $Self->{vlt},
|
||||||
expect=>
|
expect=>
|
||||||
'%Error: t_assert_synth.v:\d+: Assertion failed in top.v: synthesis full_case'
|
'%Error: t_assert_synth.v:\d+: Assertion failed in top.v: synthesis full_case'
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ compile (
|
|||||||
|
|
||||||
execute (
|
execute (
|
||||||
check_finished=>0,
|
check_finished=>0,
|
||||||
fails=>1,
|
fails => $Self->{v3},
|
||||||
expect=>
|
expect=>
|
||||||
'%Error: t_assert_synth.v:\d+: Assertion failed in top.v: synthesis parallel_case'
|
'%Error: t_assert_synth.v:\d+: Assertion failed in top.v: synthesis parallel_case'
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
|||||||
$Self->{golden_out} ||= "t/$Self->{name}.out";
|
$Self->{golden_out} ||= "t/$Self->{name}.out";
|
||||||
|
|
||||||
compile (
|
compile (
|
||||||
v_flags2 => [$Self->{v3}?"--stats --O3 -x-assign fast":""],
|
verilator_flags2 => ["--stats --O3 -x-assign fast"],
|
||||||
);
|
);
|
||||||
|
|
||||||
execute (
|
execute (
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
|||||||
$Self->{golden_out} ||= "t/$Self->{name}.out";
|
$Self->{golden_out} ||= "t/$Self->{name}.out";
|
||||||
|
|
||||||
compile (
|
compile (
|
||||||
v_flags2 => [$Self->{v3}?"--stats --O3 -x-assign fast":""],
|
verilator_flags2 => ["--stats --O3 -x-assign fast"],
|
||||||
);
|
);
|
||||||
|
|
||||||
execute (
|
execute (
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
|||||||
# Version 2.0.
|
# Version 2.0.
|
||||||
|
|
||||||
compile (
|
compile (
|
||||||
v_flags2 => ["--x-assign 0"],
|
verilator_flags2 => ["--x-assign 0"],
|
||||||
);
|
);
|
||||||
|
|
||||||
execute (
|
execute (
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed into the Public Domain, for any use,
|
||||||
|
// without warranty, 2010 by Wilson Snyder.
|
||||||
|
|
||||||
|
#include <verilated.h>
|
||||||
|
#ifdef T_CLK_2IN_VEC
|
||||||
|
# include "Vt_clk_2in_vec.h"
|
||||||
|
#else
|
||||||
|
# include "Vt_clk_2in.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
unsigned int main_time = false;
|
||||||
|
|
||||||
|
double sc_time_stamp () {
|
||||||
|
return main_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
VM_PREFIX* topp = NULL;
|
||||||
|
|
||||||
|
void clockit(int clk1, int clk0) {
|
||||||
|
#ifdef T_CLK_2IN_VEC
|
||||||
|
topp->clks = clk1<<1 | clk0;
|
||||||
|
#else
|
||||||
|
topp->c1 = clk1;
|
||||||
|
topp->c0 = clk0;
|
||||||
|
#endif
|
||||||
|
#ifdef TEST_VERBOSE
|
||||||
|
printf("[%d] c1=%d c0=%d\n", main_time, clk1, clk0);
|
||||||
|
#endif
|
||||||
|
topp->eval();
|
||||||
|
main_time++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int argc, char *argv[]) {
|
||||||
|
topp = new VM_PREFIX;
|
||||||
|
topp->check = 0;
|
||||||
|
clockit(0,0);
|
||||||
|
|
||||||
|
Verilated::debug(0);
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
clockit(0, 0);
|
||||||
|
clockit(0, 1);
|
||||||
|
clockit(1, 1);
|
||||||
|
clockit(0, 0);
|
||||||
|
clockit(1, 1);
|
||||||
|
clockit(1, 0);
|
||||||
|
clockit(0, 0);
|
||||||
|
}
|
||||||
|
topp->check = 1;
|
||||||
|
clockit(0,0);
|
||||||
|
}
|
||||||
Executable
+20
@@ -0,0 +1,20 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||||
|
# redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
|
||||||
|
compile (
|
||||||
|
make_top_shell => 0,
|
||||||
|
make_main => 0,
|
||||||
|
v_flags2 => ["--exe $Self->{t_dir}/$Self->{name}.cpp"],
|
||||||
|
) if $Self->{v3};
|
||||||
|
|
||||||
|
execute (
|
||||||
|
check_finished=>1,
|
||||||
|
) if $Self->{v3};
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed into the Public Domain, for any use,
|
||||||
|
// without warranty, 2010 by Wilson Snyder.
|
||||||
|
|
||||||
|
module t (
|
||||||
|
`ifdef T_CLK_2IN_VEC
|
||||||
|
input [1:0] clks,
|
||||||
|
`else
|
||||||
|
input c0,
|
||||||
|
input c1,
|
||||||
|
`endif
|
||||||
|
input check
|
||||||
|
);
|
||||||
|
|
||||||
|
`ifdef T_CLK_2IN_VEC
|
||||||
|
wire c0 = clks[0];
|
||||||
|
wire c1 = clks[1];
|
||||||
|
`endif
|
||||||
|
|
||||||
|
integer p0 = 0;
|
||||||
|
integer p1 = 0;
|
||||||
|
integer p01 = 0;
|
||||||
|
integer n0 = 0;
|
||||||
|
integer n1 = 0;
|
||||||
|
integer n01 = 0;
|
||||||
|
|
||||||
|
`define display_counts(text) begin \
|
||||||
|
$write("[%0t] ",$time); \
|
||||||
|
`ifdef T_CLK_2IN_VEC $write(" 2v "); `endif \
|
||||||
|
$write(text); \
|
||||||
|
$write(": %0d %0d %0d %0d %0d %0d\n", p0, p1, p01, n0, n1, n01); \
|
||||||
|
end
|
||||||
|
|
||||||
|
always @ (posedge c0) begin
|
||||||
|
p0 = p0 + 1; // Want blocking, so don't miss clock counts
|
||||||
|
`ifdef TEST_VERBOSE `display_counts("posedge 0"); `endif
|
||||||
|
end
|
||||||
|
always @ (posedge c1) begin
|
||||||
|
p1 = p1 + 1;
|
||||||
|
`ifdef TEST_VERBOSE `display_counts("posedge 1"); `endif
|
||||||
|
end
|
||||||
|
always @ (posedge c0 or posedge c1) begin
|
||||||
|
p01 = p01 + 1;
|
||||||
|
`ifdef TEST_VERBOSE `display_counts("posedge *"); `endif
|
||||||
|
end
|
||||||
|
always @ (negedge c0) begin
|
||||||
|
n0 = n0 + 1;
|
||||||
|
`ifdef TEST_VERBOSE `display_counts("negedge 0"); `endif
|
||||||
|
end
|
||||||
|
always @ (negedge c1) begin
|
||||||
|
n1 = n1 + 1;
|
||||||
|
`ifdef TEST_VERBOSE `display_counts("negedge 1"); `endif
|
||||||
|
end
|
||||||
|
always @ (negedge c0 or negedge c1) begin
|
||||||
|
n01 = n01 + 1;
|
||||||
|
`ifdef TEST_VERBOSE `display_counts("negedge *"); `endif
|
||||||
|
end
|
||||||
|
|
||||||
|
always @ (posedge check) begin
|
||||||
|
if (p0!=4) $stop;
|
||||||
|
if (p1!=4) $stop;
|
||||||
|
if (p01!=6) $stop;
|
||||||
|
if (n0!=4) $stop;
|
||||||
|
if (n1!=4) $stop;
|
||||||
|
if (n01!=6) $stop;
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
Executable
+22
@@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||||
|
# redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
|
||||||
|
top_filename("t/t_clk_2in.v");
|
||||||
|
|
||||||
|
compile (
|
||||||
|
make_top_shell => 0,
|
||||||
|
make_main => 0,
|
||||||
|
v_flags2 => ["+define+T_CLK_2IN_VEC=1 --exe $Self->{t_dir}/t_clk_2in.cpp"],
|
||||||
|
) if $Self->{v3};
|
||||||
|
|
||||||
|
execute (
|
||||||
|
check_finished=>1,
|
||||||
|
) if $Self->{v3};
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
|||||||
# Version 2.0.
|
# Version 2.0.
|
||||||
|
|
||||||
compile (
|
compile (
|
||||||
v_flags2 => ["--stats"],
|
verilator_flags2 => ["--stats"],
|
||||||
);
|
);
|
||||||
|
|
||||||
execute (
|
execute (
|
||||||
|
|||||||
Executable
+18
@@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||||
|
# redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
|
||||||
|
compile (
|
||||||
|
);
|
||||||
|
|
||||||
|
execute (
|
||||||
|
check_finished=>1,
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed into the Public Domain, for any use,
|
||||||
|
// without warranty, 2010 by Wilson Snyder.
|
||||||
|
//
|
||||||
|
// --------------------------------------------------------
|
||||||
|
// Bug Description:
|
||||||
|
//
|
||||||
|
// Issue: The gated clock gclk_vld[0] toggles but dvld[0]
|
||||||
|
// input to the flop does not propagate to the output
|
||||||
|
// signal entry_vld[0] correctly. The value that propagates
|
||||||
|
// is the new value of dvld[0] not the one just before the
|
||||||
|
// posedge of gclk_vld[0].
|
||||||
|
// --------------------------------------------------------
|
||||||
|
|
||||||
|
// Define to see the bug with test failing with gated clock 'gclk_vld'
|
||||||
|
// Comment out the define to see the test passing with ungated clock 'clk'
|
||||||
|
`define GATED_CLK_TESTCASE 1
|
||||||
|
|
||||||
|
// A side effect of the problem is this warning, disabled by default
|
||||||
|
//verilator lint_on IMPERFECTSCH
|
||||||
|
|
||||||
|
// Test Bench
|
||||||
|
module t (/*AUTOARG*/
|
||||||
|
// Inputs
|
||||||
|
clk
|
||||||
|
);
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
integer cyc=0;
|
||||||
|
reg [63:0] crc;
|
||||||
|
|
||||||
|
// Take CRC data and apply to testblock inputs
|
||||||
|
wire [7:0] dvld = crc[7:0];
|
||||||
|
wire [7:0] ff_en_e1 = crc[15:8];
|
||||||
|
|
||||||
|
/*AUTOWIRE*/
|
||||||
|
// Beginning of automatic wires (for undeclared instantiated-module outputs)
|
||||||
|
wire [7:0] entry_vld; // From test of Test.v
|
||||||
|
wire [7:0] ff_en_vld; // From test of Test.v
|
||||||
|
// End of automatics
|
||||||
|
|
||||||
|
Test test (/*AUTOINST*/
|
||||||
|
// Outputs
|
||||||
|
.ff_en_vld (ff_en_vld[7:0]),
|
||||||
|
.entry_vld (entry_vld[7:0]),
|
||||||
|
// Inputs
|
||||||
|
.clk (clk),
|
||||||
|
.dvld (dvld[7:0]),
|
||||||
|
.ff_en_e1 (ff_en_e1[7:0]));
|
||||||
|
|
||||||
|
reg err_code;
|
||||||
|
reg ffq_clk_active;
|
||||||
|
reg [7:0] prv_dvld;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
err_code = 0;
|
||||||
|
ffq_clk_active = 0;
|
||||||
|
end
|
||||||
|
always @ (posedge clk) begin
|
||||||
|
prv_dvld = test.dvld;
|
||||||
|
end
|
||||||
|
always @ (negedge test.ff_entry_dvld_0.clk) begin
|
||||||
|
ffq_clk_active = 1;
|
||||||
|
if (test.entry_vld[0] !== prv_dvld[0]) err_code = 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
// Test loop
|
||||||
|
always @ (posedge clk) begin
|
||||||
|
`ifdef TEST_VERBOSE
|
||||||
|
$write("[%0t] cyc==%0d crc=%x ",$time, cyc, crc);
|
||||||
|
$display(" en=%b fen=%b d=%b ev=%b",
|
||||||
|
test.flop_en_vld[0], test.ff_en_vld[0],
|
||||||
|
test.dvld[0], test.entry_vld[0]);
|
||||||
|
`endif
|
||||||
|
cyc <= cyc + 1;
|
||||||
|
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
|
||||||
|
if (cyc<3) begin
|
||||||
|
crc <= 64'h5aef0c8d_d70a4497;
|
||||||
|
end
|
||||||
|
else if (cyc==99) begin
|
||||||
|
$write("[%0t] cyc==%0d crc=%x\n",$time, cyc, crc);
|
||||||
|
if (ffq_clk_active == 0) begin
|
||||||
|
$display ("----");
|
||||||
|
$display ("%%Error: TESTCASE FAILED with no Clock arriving at FFQs");
|
||||||
|
$display ("----");
|
||||||
|
$stop;
|
||||||
|
end
|
||||||
|
else if (err_code) begin
|
||||||
|
$display ("----");
|
||||||
|
$display ("%%Error: TESTCASE FAILED with invalid propagation of 'd' to 'q' of FFQs");
|
||||||
|
$display ("----");
|
||||||
|
$stop;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module llq (clk, d, q);
|
||||||
|
parameter WIDTH = 32;
|
||||||
|
input clk;
|
||||||
|
input [WIDTH-1:0] d;
|
||||||
|
output [WIDTH-1:0] q;
|
||||||
|
|
||||||
|
reg [WIDTH-1:0] qr;
|
||||||
|
|
||||||
|
/* verilator lint_off COMBDLY */
|
||||||
|
|
||||||
|
always @(clk or d)
|
||||||
|
if (clk == 1'b0)
|
||||||
|
qr <= d;
|
||||||
|
|
||||||
|
/* verilator lint_on COMBDLY */
|
||||||
|
|
||||||
|
assign q = qr;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ffq (clk, d, q);
|
||||||
|
parameter WIDTH = 32;
|
||||||
|
input clk;
|
||||||
|
input [WIDTH-1:0] d;
|
||||||
|
output [WIDTH-1:0] q;
|
||||||
|
|
||||||
|
reg [WIDTH-1:0] qr;
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
qr <= d;
|
||||||
|
|
||||||
|
assign q = qr;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
// DUT module
|
||||||
|
module Test (/*AUTOARG*/
|
||||||
|
// Outputs
|
||||||
|
ff_en_vld, entry_vld,
|
||||||
|
// Inputs
|
||||||
|
clk, dvld, ff_en_e1
|
||||||
|
);
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
input [7:0] dvld;
|
||||||
|
input [7:0] ff_en_e1;
|
||||||
|
|
||||||
|
output [7:0] ff_en_vld;
|
||||||
|
output wire [7:0] entry_vld;
|
||||||
|
|
||||||
|
wire [7:0] gclk_vld;
|
||||||
|
wire [7:0] ff_en_vld /*verilator clock_enable*/;
|
||||||
|
reg [7:0] flop_en_vld;
|
||||||
|
|
||||||
|
always @(posedge clk) flop_en_vld <= ff_en_e1;
|
||||||
|
|
||||||
|
// clock gating
|
||||||
|
`ifdef GATED_CLK_TESTCASE
|
||||||
|
assign gclk_vld = {8{clk}} & ff_en_vld;
|
||||||
|
`else
|
||||||
|
assign gclk_vld = {8{clk}};
|
||||||
|
`endif
|
||||||
|
|
||||||
|
// latch for avoiding glitch on the clock gating control
|
||||||
|
llq #(8) dp_ff_en_vld (.clk(clk), .d(flop_en_vld), .q(ff_en_vld));
|
||||||
|
|
||||||
|
// flops that use the gated clock signal
|
||||||
|
ffq #(1) ff_entry_dvld_0 (.clk(gclk_vld[0]), .d(dvld[0]), .q(entry_vld[0]));
|
||||||
|
ffq #(1) ff_entry_dvld_1 (.clk(gclk_vld[1]), .d(dvld[1]), .q(entry_vld[1]));
|
||||||
|
ffq #(1) ff_entry_dvld_2 (.clk(gclk_vld[2]), .d(dvld[2]), .q(entry_vld[2]));
|
||||||
|
ffq #(1) ff_entry_dvld_3 (.clk(gclk_vld[3]), .d(dvld[3]), .q(entry_vld[3]));
|
||||||
|
ffq #(1) ff_entry_dvld_4 (.clk(gclk_vld[4]), .d(dvld[4]), .q(entry_vld[4]));
|
||||||
|
ffq #(1) ff_entry_dvld_5 (.clk(gclk_vld[5]), .d(dvld[5]), .q(entry_vld[5]));
|
||||||
|
ffq #(1) ff_entry_dvld_6 (.clk(gclk_vld[6]), .d(dvld[6]), .q(entry_vld[6]));
|
||||||
|
ffq #(1) ff_entry_dvld_7 (.clk(gclk_vld[7]), .d(dvld[7]), .q(entry_vld[7]));
|
||||||
|
|
||||||
|
endmodule
|
||||||
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
|||||||
# Version 2.0.
|
# Version 2.0.
|
||||||
|
|
||||||
compile (
|
compile (
|
||||||
verilator_flags2 => [$Self->{v3}?'--sp --coverage-line':''],
|
verilator_flags2 => ['--sp --coverage-line'],
|
||||||
);
|
);
|
||||||
|
|
||||||
execute (
|
execute (
|
||||||
|
|||||||
@@ -48,7 +48,11 @@ module t (/*AUTOARG*/
|
|||||||
toggle <= '1;
|
toggle <= '1;
|
||||||
end
|
end
|
||||||
else if (cyc==5) begin
|
else if (cyc==5) begin
|
||||||
|
`ifdef VERILATOR
|
||||||
$c("call_task();");
|
$c("call_task();");
|
||||||
|
`else
|
||||||
|
call_task();
|
||||||
|
`endif
|
||||||
end
|
end
|
||||||
else if (cyc==10) begin
|
else if (cyc==10) begin
|
||||||
$write("*-* All Finished *-*\n");
|
$write("*-* All Finished *-*\n");
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
|||||||
# Version 2.0.
|
# Version 2.0.
|
||||||
|
|
||||||
compile (
|
compile (
|
||||||
v_flags2 => [$Self->{v3}?'--assert --sp --coverage-user':''],
|
verilator_flags2 => ['--assert --sp --coverage-user'],
|
||||||
);
|
);
|
||||||
|
|
||||||
execute (
|
execute (
|
||||||
@@ -20,7 +20,8 @@ execute (
|
|||||||
# Allow old Perl format dump, or new binary dump
|
# Allow old Perl format dump, or new binary dump
|
||||||
# Check that the hierarchy doesn't include __PVT__
|
# Check that the hierarchy doesn't include __PVT__
|
||||||
# Otherwise our coverage reports would look really ugly
|
# Otherwise our coverage reports would look really ugly
|
||||||
file_grep ($Self->{coverage_filename}, qr/(top\.v\.sub.*.cyc_eq_5)/);
|
file_grep ($Self->{coverage_filename}, qr/(top\.v\.sub.*.cyc_eq_5)/)
|
||||||
|
if $Self->{vlt};
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
|||||||
# Version 2.0.
|
# Version 2.0.
|
||||||
|
|
||||||
compile (
|
compile (
|
||||||
verilator_flags2 => [$Self->{v3}?'--sp --coverage-toggle --stats':''],
|
verilator_flags2 => ['--sp --coverage-toggle --stats'],
|
||||||
);
|
);
|
||||||
|
|
||||||
execute (
|
execute (
|
||||||
@@ -18,7 +18,8 @@ execute (
|
|||||||
# Read the input .v file and do any CHECK_COVER requests
|
# Read the input .v file and do any CHECK_COVER requests
|
||||||
inline_checks();
|
inline_checks();
|
||||||
|
|
||||||
file_grep ($Self->{stats}, qr/Coverage, Toggle points joined\s+25/i);
|
file_grep ($Self->{stats}, qr/Coverage, Toggle points joined\s+25/i)
|
||||||
|
if $Self->{vlt};
|
||||||
|
|
||||||
ok(1);
|
ok(1);
|
||||||
1;
|
1;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ if (!-r "$root/.git") {
|
|||||||
my $cmd = "cd $root && fgrep -n include $files | sort";
|
my $cmd = "cd $root && fgrep -n include $files | sort";
|
||||||
my $grep = `$cmd`;
|
my $grep = `$cmd`;
|
||||||
foreach my $line (split /\n/, $grep) {
|
foreach my $line (split /\n/, $grep) {
|
||||||
|
next if $line =~ /vpi_user.h/; # IEEE Standard file - can't change it
|
||||||
my $hit;
|
my $hit;
|
||||||
$hit = 1 if $line =~ /\bassert\.h/;
|
$hit = 1 if $line =~ /\bassert\.h/;
|
||||||
$hit = 1 if $line =~ /\bctype\.h/;
|
$hit = 1 if $line =~ /\bctype\.h/;
|
||||||
|
|||||||
Executable
+52
@@ -0,0 +1,52 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2010 by Wilson Snyder. This program is free software; you can
|
||||||
|
# redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
|
||||||
|
use Cwd;
|
||||||
|
|
||||||
|
my $root = "..";
|
||||||
|
my $Debug;
|
||||||
|
|
||||||
|
if (!-r "$root/.git") {
|
||||||
|
$Self->skip("Not in a git repository");
|
||||||
|
} else {
|
||||||
|
my $cwd = getcwd();
|
||||||
|
my $destdir = "$cwd/".$Self->{obj_dir};
|
||||||
|
# Start clean
|
||||||
|
$Self->_run(cmd=>["rm -rf $destdir && mkdir -p $destdir"],
|
||||||
|
check_finished=>0);
|
||||||
|
# Install into temp area
|
||||||
|
print "Install...\n";
|
||||||
|
$Self->_run (cmd=>["cd $root && make DESTDIR=$destdir install"],
|
||||||
|
check_finished=>0);
|
||||||
|
|
||||||
|
# Check we can run a test
|
||||||
|
# Unfortunately the prefix was hardcoded in the exec at a different place,
|
||||||
|
# so we can't do much here.
|
||||||
|
#print "Check install...\n";
|
||||||
|
|
||||||
|
# Uninstall
|
||||||
|
print "Uninstall...\n";
|
||||||
|
$Self->_run (cmd=>["cd $root && make DESTDIR=$destdir uninstall"],
|
||||||
|
check_finished=>0);
|
||||||
|
|
||||||
|
# Check empty
|
||||||
|
my @files;
|
||||||
|
$finds = `find $destdir -type f -print`;
|
||||||
|
foreach my $f (split /\n/, $finds) {
|
||||||
|
print "\tLEFT: $f\n";
|
||||||
|
$f =~ s!^$cwd!.!;
|
||||||
|
push @files, $f;
|
||||||
|
}
|
||||||
|
if ($#files >= 0) {
|
||||||
|
$Self->error("Uninstall missed files: ",join(' ',@files));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
//*************************************************************************
|
//*************************************************************************
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <svdpi.h>
|
#include "svdpi.h"
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
//*************************************************************************
|
//*************************************************************************
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <svdpi.h>
|
#include "svdpi.h"
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
//*************************************************************************
|
//*************************************************************************
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <svdpi.h>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include "svdpi.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# define T_PRI64 "I64"
|
# define T_PRI64 "I64"
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <svdpi.h>
|
#include "svdpi.h"
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
//*************************************************************************
|
//*************************************************************************
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <svdpi.h>
|
#include "svdpi.h"
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user