Compare commits

...
53 Commits
Author SHA1 Message Date
Wilson Snyder ed2fbd8f25 Version bump 2010-09-20 15:46:17 -04:00
Wilson Snyder 42199bc8e5 Fix preprocessor `` of existing base define, bug283. 2010-09-20 15:20:16 -04:00
Wilson Snyder 7c5318768c Reduce debug verbosity (match Verilog-Perl) 2010-09-20 13:13:31 -04:00
Wilson Snyder aba25aab19 On core dump, print debug suggestions. 2010-09-20 09:21:29 -04:00
Wilson Snyder f99bd33f91 Support tracing/coverage of underscore signals, bug280. 2010-08-29 19:28:46 -04:00
Wilson Snyder a6a6ce83f0 Internals: Use branch prediction in asserts 2010-08-10 11:19:45 -04:00
Wilson Snyder f4908a9758 Increase define recursions before error 2010-08-10 11:18:53 -04:00
Wilson Snyder 5e4ca4b76a Version bump 2010-07-10 18:41:23 -04:00
Wilson Snyder 1e938d0e90 Update preprocessor to match next Verilog-Perl version.
Fix preprocessor preservation of newlines across macro substitutions.
Fix preprocessor stringification of nested macros.
Fix preprocessor whitespace on define arguments
2010-07-10 18:30:16 -04:00
Wilson Snyder f3704f4c05 Tests: Rename includes to .vh extensions 2010-07-08 20:51:54 -04:00
Wilson Snyder 8800efe953 Internals: Rename incLineno to match Verilog-Perl, no functional change. 2010-07-08 20:31:41 -04:00
Wilson Snyder a320c4584e Fix do {...} while() not requiring final semicolon. 2010-07-07 19:15:51 -04:00
Wilson Snyder 3841850168 Preproc: fix pass-through of `line enter-exit codes.
Internals: Merge Verilog-Perl preproc changes through d450722.
2010-07-06 20:29:12 -04:00
Wilson Snyder beb3885840 Add t_clk_2in test 2010-06-21 20:40:34 -04:00
Wilson Snyder 06967c0c46 Fix some constant parameter functions causing crash, bug253. 2010-05-25 19:37:45 -04:00
Wilson Snyder 9a382c572c Commentary, bug251 2010-05-02 06:29:02 -04:00
Wilson Snyder 44b6c371db Version bump 2010-05-01 14:18:56 -04:00
Wilson Snyder 00970be996 Fix bit reductions on multi-packed dimensions, bug227/patch0004. 2010-04-22 09:40:53 -04:00
Wilson Snyder aca4ab015f Fix removing if assigned to unused var, bug248. 2010-04-19 19:38:22 -04:00
Wilson Snyder 68b63d5783 Increase unrollStmts, bug247, due to unreleased change. 2010-04-19 13:59:15 -04:00
Wilson Snyder 4b499f2bb1 Commentary, bug246 2010-04-19 09:44:48 -04:00
Wilson Snyder ed17581f92 Fix loop unroller out of memory; change --unroll-stmts. 2010-04-17 08:01:22 -04:00
Wilson Snyder a46c4ec912 Accelerate and reduce memory usage of V3Expand 2010-04-15 21:05:21 -04:00
Wilson Snyder 930cbeec17 Internals: Create user#Inc routines 2010-04-15 20:56:54 -04:00
Wilson Snyder 10689ffaba Fix carrage return purging, broke in pre-release only 2010-04-10 09:11:52 -04:00
Wilson Snyder 29b0ea0af9 Debug: Allow --debugi-V3PreShell to turn on flex debug 2010-04-10 08:20:28 -04:00
Wilson Snyder 57d00946be Fix MSVC compile issues 2010-04-10 06:46:24 -04:00
Wilson Snyder ef51de72c9 Fix word size to match uint64_t on -m64 systems, bug238. 2010-04-09 21:51:15 -04:00
Wilson Snyder c807bf1e0e Internals: Fix useless rule and flex warning 2010-04-09 21:06:16 -04:00
Byron Bradley 2525b3fb05 Fix bit reductions on multi-packed dimensions, bug227
Signed-off-by: Wilson Snyder <[email protected]>
2010-04-09 21:05:46 -04:00
Byron Bradley 9163ce0f6e Internals: modify AstVar::dimensions() to return a pair, bug227
Signed-off-by: Wilson Snyder <[email protected]>
2010-04-09 20:43:25 -04:00
Byron Bradley d776638f53 Internals: Mark packed dimensions in arrays, bug227
Signed-off-by: Wilson Snyder <[email protected]>
2010-04-09 20:40:41 -04:00
Wilson Snyder 83fff41312 Fix installing data files as non-executable, bug168. 2010-04-09 20:21:00 -04:00
Wilson Snyder dd7d9bc95b Fix some spelling mistakes in verilator executable & manpage, bug240 2010-04-09 19:45:46 -04:00
Wilson Snyder f8eabbc100 From Verilog-Perl: Fix parsing single files > 2GB. 2010-04-06 20:20:44 -04:00
Wilson Snyder 7ed18ac62d Internals: Track Verilog-Perl 3.240 parser changes 2010-04-06 18:55:54 -04:00
Wilson Snyder 3ac707c645 Tests: Fix vpi_user addition failure 2010-04-06 18:43:24 -04:00
Wilson Snyder 8e9a1e0bf3 Add standard vpi_user.h file 2010-04-05 20:08:13 -04:00
Wilson Snyder bc31b5d27a Commentary 2010-04-05 20:08:07 -04:00
Wilson Snyder 936738b750 Add /*verilator public_flat_rw*/ for timing-specific public access. 2010-04-05 20:01:17 -04:00
Wilson Snyder 7c3048ab9c Report errors when extra underscores used in meta-comments. 2010-03-24 22:08:59 -04:00
Wilson Snyder 64719f3ace Makefile: Add local install-cadtools rule 2010-03-24 16:09:29 -04:00
Wilson Snyder a11a5f04d5 Default Verilated::debug() to off 2010-03-23 20:31:22 -04:00
Wilson Snyder eb5c035dde Internals: Fix some missing branch prediction 2010-03-22 19:07:03 -04:00
Wilson Snyder c3887efbf3 Internals: Remove dead code 2010-03-22 19:06:30 -04:00
Wilson Snyder 495585830d Fix trace files with empty modules crashing some viewers. 2010-03-22 18:38:24 -04:00
Wilson Snyder 6715cb9880 Improve error handling on slices of arrays, bug226. 2010-03-20 21:29:16 -04:00
Wilson Snyder 41b167d23c Fix DPI display bogus error 2010-03-20 07:13:52 -04:00
Wilson Snyder 7ea8b54210 Tests: Support atsim and cleanup verilator-only tests 2010-03-18 12:03:08 -04:00
Wilson Snyder bcea39a858 Fix "make install" with configure outside srcdir. 2010-03-17 20:20:40 -04:00
Wilson Snyder fb560abac4 Commentary 2010-03-17 19:57:38 -04:00
Wilson Snyder ba93a08b40 Support runtime access to public signal names 2010-03-17 08:22:49 -04:00
Wilson Snyder 2be6b3481c Pre-version 2010-03-17 08:05:07 -04:00
144 changed files with 4752 additions and 754 deletions
+46
View File
@@ -3,6 +3,52 @@ Revision history for Verilator
The contributors that suggested a given feature are shown in []. [by ...]
indicates the contributor was also the author of the fix; Thanks!
* Verilator 3.804 2010/09/20
*** Support tracing/coverage of underscore signals, bug280. [by Jason McMullan]
**** Fix preprocessor `` of existing base define, bug283. [Usha Priyadharshini]
**** Increase define recursions before error. [Paul Liu]
**** On core dump, print debug suggestions.
* 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".
+56 -20
View File
@@ -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/*.pl src/*.pod \
test_*/.*ignore test_*/Makefile* test_*/*.cpp \
test_*/*.pl test_*/*.v test_*/*.vc test_*/vlint \
test_*/*.pl test_*/*.v test_*/*.vc test_*/*.vh \
test_verilated/vgen*.pl \
test_regress/t/*.cpp \
test_regress/t/*.h \
@@ -134,10 +134,9 @@ INST_PROJ_FILES = \
bin/verilator \
bin/verilator_includer \
bin/verilator_profcfunc \
include/verilated.[chv]* \
include/verilated.mk \
include/verilatedos.[chv]* \
include/verilated_*.[chv]* \
include/*.[chv]* \
include/vltstd/*.[chv]* \
INST_PROJ_BIN_FILES = \
verilator_bin \
@@ -245,11 +244,15 @@ VL_INST_BIN_FILES = verilator verilator_bin verilator_bin_dbg \
# See uninstall also - don't put wildcards in this variable, it might uninstall other stuff
VL_INST_MAN_FILES = verilator.1
VL_INST_INC_FILES = \
include/*.[chv]* include/verilated.mk \
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_FILES = \
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 \
@@ -267,20 +270,25 @@ installbin:
installman: $(VL_INST_MAN_FILES)
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(mandir)/man1
for p in $(VL_INST_MAN_FILES) ; do \
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(mandir)/man1/$$p; \
$(INSTALL_DATA) $$p $(DESTDIR)$(mandir)/man1/$$p; \
done
installdata:
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/include/vltstd
for p in $(VL_INST_INC_FILES) ; do \
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkgdatadir)/$$p; \
for p in $(VL_INST_INC_BLDDIR_FILES) ; do \
$(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/$$p; \
done
cd $(srcdir) \
; for p in $(VL_INST_INC_SRCDIR_FILES) ; do \
$(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/$$p; \
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
for p in $(VL_INST_DATA_FILES) ; do \
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkgdatadir)/examples/$$p; \
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
@@ -288,8 +296,9 @@ 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_FILES)
-cd $(DESTDIR)$(pkgdatadir)/examples && rm -f $(VL_INST_DATA_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
@@ -306,6 +315,7 @@ install-here: installman ftp
ifeq ($(VERILATOR_AUTHOR_SITE),1) # Local... Else don't burden users
DIRPROJECT := $(shell project_dir --project)
VERILATOR_CAD_DIR = $(CAD_DIR)/verilator/$(DISTNAMEREV)/$(DIRPROJECT_ARCH)
INST_PROJ_CVS = cp_if_cvs_diff
install-project: dist
@@ -313,7 +323,7 @@ install-project: dist
strip verilator_bin*
$(MAKE) install-project-quick
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
$(INST_PROJ_CVS) $(DISTNAME).tgz $(DIRPROJECT)/hw/utils/verilator/verilator.tgz
rm $(DISTNAME).tgz
@@ -330,6 +340,34 @@ endif
for p in $(INST_PROJ_BIN_FILES) ; do \
$(INST_PROJ_CVS) $$p $(DIRPROJECT)/hw/utils/verilator/$$p-$(DIRPROJECT_ARCH); \
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
ftp: info
@@ -337,11 +375,8 @@ ftp: info
install-msg:
@echo "Installed!"
@echo
@echo "Add to your startup file (for bash or csh, as appropriate):"
@echo " export VERILATOR_ROOT="`pwd`
@echo " setenv VERILATOR_ROOT "`pwd` " ; export VERILATOR_ROOT "
@echo
@echo "See 'verilator.txt' for documentation."
@echo "Fod documentation see 'man verilator' or 'verilator --help'"
@echo "For forums and to report bugs see http://www.veripool.org/verilator"
@echo
IN_WILD := ${srcdir}/*.in ${srcdir}/*/*.in
@@ -402,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))
DISTNAME := $(shell sed -e '/DTVERSION/!d' -e 's/[^0-9]*\([0-9.a-z]*\).*/verilator-\1/' -e q $(DISTCONFIG))
DISTDATEPRE := $(shell sed -e '/DTVERSION/!d' -e 's/.*\([1-2][0-9][0-9][0-9].[0-9]*[0-9].[0-9]*[0-9]\).*/\1/' -e q $(DISTCONFIG))
DISTNAMEREV := $(shell sed -e '/DTVERSION/!d' -e 's/.*verilator_\([^"]*\).*/\1/' -e q src/config_rev.h)
DISTTAGNAME := $(subst .,_,$(subst -,_,$(DISTNAME)))
DISTDATE := $(subst /,-,$(DISTDATEPRE))
+60 -18
View File
@@ -137,6 +137,15 @@ sub run {
warn "%Error: export VERILATOR_ROOT=".($ENV{VERILATOR_ROOT}||"")."\n";
warn "%Error: $command\n";
}
if ($status & 255) {
if (($status & 255) == 8 || ($status & 255) == 11) { # SIGFPA or SIGSEGV
warn "%Error: Verilator internal fault, sorry. Consider trying --debug --gdbbt\n" if !$Debug;
} elsif (($status & 255) == 6) { # SIGABRT
warn "%Error: Verilator aborted. Consider trying --debug --gdbbt\n" if !$Debug;
} else {
warn "%Error: Verilator threw signal $status. Consider trying --debug --gdbbt\n" if !$Debug;
}
}
die "%Error: Command Failed $command\n";
}
}
@@ -207,6 +216,7 @@ descriptions in the next sections for more information.
--coverage-line Enable line coverage
--coverage-toggle Enable toggle coverage
--coverage-user Enable PSL/SVL user coverage
--coverage-underscore Enable covarge of _signals
-D<var>[=<value>] Set preprocessor define
--debug Enable debugging
--debug-check Enable debugging assertions
@@ -256,6 +266,7 @@ descriptions in the next sections for more information.
--top-module <topname> Name of top level input module
--trace Enable waveform creation
--trace-depth <levels> Depth of tracing
--trace-underscore Enable tracing of _signals
-U<var> Undefine preprocessor define
--unroll-count <loops> Tune maximum loop iterations
--unroll-stmts <stmts> Tune maximum loop body size
@@ -426,6 +437,11 @@ counting such behavior.
A /*verilator coverage_off/on */ comment pair can be used around signals
that do not need toggle analysis, such as RAMs and register files.
=item --coverage-underscore
Enable coverage of signals that start with an underscore. Normally, these
signals are not covered. See also --trace-underscore.
=item --coverage-user
Enables user inserted functional coverage. Currently, all functional
@@ -750,6 +766,11 @@ Specify the number of levels deep to enable tracing, for example
entire model. Using a small number will decrease visibility, but greatly
improve runtime and trace file size.
=item --trace-underscore
Enable tracing of signals that start with an underscore. Normally, these
signals are not output during tracing. See also --coverage-underscore.
=item -UI<var>
Undefines the given preprocessor symbol.
@@ -1389,20 +1410,20 @@ Verilator configuration commands.
=item coverage_off [-file "<filename>" [-lines <line> [ - <line> ]]]
Disable coverage for the specified filename (or all files if ommitted) and
range of line numbers (or all lines if ommitted). Often used to ignore an
Disable coverage for the specified filename (or all files if omitted) and
range of line numbers (or all lines if omitted). Often used to ignore an
entire module for coverage analysis purposes.
=item lint_off -msg <message> [-file "<filename>" [-lines <line> [ - <line>]]]
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> ]]]
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
if ommitted).
filename (or all files if omitted) and range of line numbers (or all lines
if omitted).
=back
@@ -1644,7 +1665,7 @@ Often used to ignore an entire module for coverage analysis purposes.
=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
/*verilator coverage_off*/.
@@ -1770,6 +1791,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
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*/
Used after a module statement to indicate the module should not be inlined
@@ -1819,14 +1852,17 @@ program will find for you.
Verilator supports only the Synthesis subset with a few minor additions
such as $stop, $finish and $display. That is, you cannot use hierarchical
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;
will recompute y when there is a change in x or a change in z, which is
what Design Compiler will synthesize. A compliant simulator would only
calculate y if x changes. (Use verilog-mode's /*AS*/ or Verilog 2001's
always @* to prevent these issues.)
This will recompute y when there is even a potential for change in x or a
change in z, that is when the flops computing x or z evaluate (which is
what Design Compiler will synthesize.) A compliant simulator would only
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
@@ -2597,8 +2633,8 @@ allows you to modify Verilator for internal use without distributing the
modified version. But please contribute back to the community!
One limit is that you cannot under either license release a commercial
simulation product incorporating Verilator without making the source code
available.
Verilog simulation product incorporating Verilator without making the
source code available.
=item Why is Verilation so slow?
@@ -2620,8 +2656,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
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
is done for you if using the Verilator --exe flag.
You also need to compile verilated_vcd_c.cpp and add it 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
trace file if you want all data to land in the same output file.
@@ -2658,8 +2696,10 @@ Alternatively you may use the C++ trace mechanism described in the previous
question, however the timescale and timeprecision will not inherited from
your SystemC settings.
You also need to compile verilated_vcd_sc.cpp and add it to your link.
This is done for you if using the Verilator --exe flag.
You also need to compile verilated_vcd_sc.cpp and verilated_vcd_c.cpp and
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
trace file if you want all data to land in the same output file.
@@ -2765,7 +2805,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::...'"?
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?
+76 -6
View File
@@ -38,7 +38,7 @@ int Verilated::s_randReset = 0;
VerilatedVoidCb Verilated::s_flushCb = NULL;
// Keep below together in one cache line
int Verilated::s_debug = 1;
int Verilated::s_debug = 0;
bool Verilated::s_calcUnusedSigs = false;
bool Verilated::s_gotFinish = false;
bool Verilated::s_assertOn = true;
@@ -833,7 +833,7 @@ void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
} else {
needinc = true;
//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");
} else {
int entry = addr - array_lsb;
@@ -861,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);
datap[0] |= value;
}
if (value>=(1<<shift)) {
if (VL_UNLIKELY(value>=(1<<shift))) {
vl_fatal (ofilenamez, linenum, "", "$readmemb (binary) file contains hex characters");
}
}
@@ -878,7 +878,7 @@ void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
// Final checks
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");
}
}
@@ -995,6 +995,10 @@ void Verilated::scopesDump() {
VerilatedImp::scopesDump();
}
const VerilatedScope* Verilated::scopeFind(const char* namep) {
return VerilatedImp::scopeFind(namep);
}
int Verilated::exportFuncNum(const char* namep) {
return VerilatedImp::exportFind(namep);
}
@@ -1010,6 +1014,23 @@ VerilatedModule::~VerilatedModule() {
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
@@ -1017,12 +1038,14 @@ VerilatedScope::VerilatedScope() {
m_callbacksp = NULL;
m_namep = NULL;
m_funcnumMax = 0;
m_varsp = NULL;
}
VerilatedScope::~VerilatedScope() {
VerilatedImp::scopeErase(this);
if (m_namep) { delete [] m_namep; m_namep = 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
}
@@ -1047,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.
if (funcnum >= m_funcnumMax) { m_funcnumMax = funcnum+1; }
} else {
if (funcnum >= m_funcnumMax) {
if (VL_UNLIKELY(funcnum >= m_funcnumMax)) {
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];
memset(m_callbacksp, 0, m_funcnumMax*sizeof(void*));
}
@@ -1058,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 {
// Slowpath - Called only when find has failed
string msg = (string("Testbench C called '")
@@ -1085,6 +1149,12 @@ void VerilatedScope::scopeDump() const {
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);
}
}
}
//===========================================================================
+34
View File
@@ -66,9 +66,33 @@ typedef void (*VerilatedVoidCb)(void);
class SpTraceVcd;
class SpTraceVcdCFile;
class VerilatedVar;
class VerilatedVarNameMap;
class VerilatedVcd;
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
@@ -138,6 +162,9 @@ public:
#ifndef VL_PRINTF
# define VL_PRINTF printf ///< Print ala printf; may redefine if desired
#endif
#ifndef VL_VPRINTF
# define VL_VPRINTF vprintf ///< Print ala vprintf; may redefine if desired
#endif
//===========================================================================
/// Verilator symbol table base class
@@ -155,6 +182,7 @@ class VerilatedScope {
void** m_callbacksp; ///< Callback table pointer (Fastpath)
int m_funcnumMax; ///< Maxium function number stored (Fastpath)
// 4 bytes padding (on -m64), for rent.
VerilatedVarNameMap* m_varsp; ///< Variable map
const char* m_namep; ///< Scope name (Slowpath)
public: // But internals only - called from VerilatedModule's
@@ -162,9 +190,13 @@ public: // But internals only - called from VerilatedModule's
~VerilatedScope();
void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp);
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
const char* name() const { return m_namep; }
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* exportFindNullError(int funcnum) const;
void scopeDump() const;
@@ -247,6 +279,8 @@ public:
// METHODS - INTERNAL USE ONLY
// Internal: Create a new module name by concatenating two strings
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
static const VerilatedScope* dpiScope() { return t_dpiScopep; }
static void dpiScope(const VerilatedScope* scopep) { t_dpiScopep=scopep; }
+1 -7
View File
@@ -31,6 +31,7 @@
#include "verilatedos.h"
#include "verilated.h"
#include "verilated_heavy.h"
#include "verilated_syms.h"
#include <map>
#include <vector>
@@ -41,13 +42,6 @@ class VerilatedScope;
//======================================================================
// 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 {
// Whole class is internal use only - Global information shared between verilated*.cpp files.
+100
View File
@@ -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
+39 -12
View File
@@ -154,6 +154,39 @@ void VerilatedVcd::openNext (bool incFilename) {
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() {
close();
if (m_wrBufp) { delete[] m_wrBufp; m_wrBufp=NULL; }
@@ -201,7 +234,7 @@ void VerilatedVcd::printStr (const char* str) {
void VerilatedVcd::printQuad (vluint64_t n) {
char buf [100];
sprintf(buf,"%" VL_PRI64 "u",(long long unsigned)n);
sprintf(buf,"%" VL_PRI64 "u", n);
printStr(buf);
}
@@ -227,10 +260,10 @@ void VerilatedVcd::bufferFlush () {
if (VL_UNLIKELY(!isOpen())) return;
char* wp = m_wrBufp;
while (1) {
size_t remaining = (m_writep - wp);
ssize_t remaining = (m_writep - wp);
if (remaining==0) break;
errno = 0;
int got = write (m_fd, wp, remaining);
ssize_t got = write (m_fd, wp, remaining);
if (got>0) {
wp += got;
m_wroteBytes += got;
@@ -314,13 +347,7 @@ void VerilatedVcd::dumpHeader () {
printStr(doubleToTimescale(m_timeRes).c_str());
printStr(" $end\n");
// 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);
}
makeNameMap();
// Signal header
assert (m_modDepth==0);
@@ -346,7 +373,7 @@ void VerilatedVcd::dumpHeader () {
// Skip common prefix, it must break at a space or tab
for (; *np && (*np == *lp); 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
bool first = true;
@@ -394,7 +421,7 @@ void VerilatedVcd::module (string name) {
}
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"); }
int bits = ((msb>lsb)?(msb-lsb):(lsb-msb))+1;
+1
View File
@@ -99,6 +99,7 @@ private:
void closePrev();
void closeErr();
void openNext();
void makeNameMap();
void printIndent (int levelchange);
void printStr (const char* str);
void printQuad (vluint64_t n);
+24 -2
View File
@@ -126,8 +126,13 @@ typedef unsigned long uint32_t; ///< 32-bit unsigned type (backward compatibili
typedef long vlsint32_t; ///< 32-bit signed type
typedef unsigned long vluint32_t; ///< 32-bit unsigned type
# 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 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)
@@ -141,6 +146,14 @@ typedef unsigned __int32 vluint32_t; ///< 32-bit unsigned type
typedef signed __int64 vlsint64_t; ///< 64-bit signed 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
# 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 int vlsint32_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 unsigned long long vluint64_t; ///< 64-bit unsigned type
# endif
#endif
//=========================================================================
@@ -160,7 +178,11 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
#ifdef _WIN32
# define VL_PRI64 "I64"
#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
//=========================================================================
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -59,9 +59,9 @@ sub test {
my $bin1 = $prefix."/bin";
my $bin2 = $prefix."/share/bin";
IO::File->new(">$testdir/foo.v")->print('module t; initial begin $display("HELLO WORLD"); end endmodule'."\n");
run("cd $testdir && PATH=$bin1:$bin2:\$PATH verilator --cc --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");
#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");
}
}
+59
View File
@@ -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:
+1
View File
@@ -126,6 +126,7 @@ sub prep {
#
$wholefile =~ s/\b(uint[0-9]+_t)/vl$1/g;
$wholefile =~ s/%ll/%" VL_PRI64 "/g;
$wholefile =~ s/\(long long unsigned\)n/ n/g; # printQuad
#
$wholefile =~ s/\bSP_SC_BV/VL_SC_BV/g;
$wholefile =~ s/\bSP_UNLIKELY/VL_UNLIKELY/g;
+29 -23
View File
@@ -197,7 +197,6 @@ private:
// STATE
ActiveNamer m_namer; // Tracking of active names
AstCFunc* m_scopeFinalp; // Final function for this scope
AstAlways* m_alwaysp; // Under always
bool m_itemCombo; // Found a SenItem combo
bool m_itemSequent; // Found a SenItem sequential
@@ -264,32 +263,22 @@ private:
}
// METHODS
virtual void visit(AstAlways* nodep, AstNUser*) {
void visitAlways(AstNode* nodep, AstSenTree* oldsensesp) {
// 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;
}
if (nodep->sensesp()
&& nodep->sensesp()->sensesp()
&& nodep->sensesp()->sensesp()->castSenItem()
&& nodep->sensesp()->sensesp()->castSenItem()->isNever()) {
if (oldsensesp
&& oldsensesp->sensesp()
&& oldsensesp->sensesp()->castSenItem()
&& oldsensesp->sensesp()->castSenItem()->isNever()) {
// 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;
return;
}
// Read sensitivitues
m_alwaysp = nodep;
m_itemCombo = false;
m_itemSequent = false;
nodep->sensesp()->iterateAndNext(*this);
m_alwaysp = NULL;
oldsensesp->iterateAndNext(*this);
bool combo = m_itemCombo;
bool sequent = m_itemSequent;
@@ -311,15 +300,15 @@ private:
// always (posedge RESET) { if (RESET).... } we know RESET is true.
// Summarize a long list of combo inputs as just "combo"
#ifndef __COVERITY__ // Else dead code on next line.
if (combo) nodep->sensesp()->addSensesp
if (combo) oldsensesp->addSensesp
(new AstSenItem(nodep->fileline(),AstSenItem::Combo()));
#endif
wantactivep = m_namer.getActive(nodep->fileline(), nodep->sensesp());
wantactivep = m_namer.getActive(nodep->fileline(), oldsensesp);
}
// Delete sensitivity list
if (AstNode* oldsense = nodep->sensesp()) {
oldsense->unlinkFrBackWithNext()->deleteTree(); oldsense=NULL;
if (oldsensesp) {
oldsensesp->unlinkFrBackWithNext()->deleteTree(); oldsensesp=NULL;
}
// Move node to new active
@@ -331,6 +320,24 @@ private:
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*) {
AstSenItem* subitemp = nodep->sensesp();
if (subitemp->edgeType() != AstEdgeType::ET_ANYEDGE
@@ -366,7 +373,6 @@ public:
// CONSTUCTORS
ActiveVisitor(AstNetlist* nodep) {
m_scopeFinalp = NULL;
m_alwaysp = NULL;
m_itemCombo = false;
m_itemSequent = false;
nodep->accept(*this);
+3
View File
@@ -133,6 +133,9 @@ private:
virtual void visit(AstAlways* nodep, AstNUser*) {
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*) {
nodep->v3fatalSrc("Node should have been deleted");
}
+1 -2
View File
@@ -177,8 +177,7 @@ private:
// VISITORS //========== Case assertions
virtual void visit(AstCase* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (!nodep->user1()) {
nodep->user1(true);
if (!nodep->user1Inc()) {
bool has_default=false;
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
if (itemp->isDefault()) has_default=true;
+9 -1
View File
@@ -179,6 +179,8 @@ public:
VAR_CLOCK_ENABLE, // V3LinkParse moves to AstVar::attrClockEn
VAR_PUBLIC, // 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_SFORMAT // V3LinkParse moves to AstVar::attrSFormat
};
@@ -186,7 +188,8 @@ public:
const char* ascii() const {
static const char* names[] = {
"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"
};
return names[m_e];
@@ -819,6 +822,7 @@ public:
void user1p(void* userp) { m_user1p=(AstNUser*)(userp); m_user1Cnt=AstUser1InUse::s_userCntGbl; }
int user1() const { return user1p()->castInt(); }
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
AstNUser* user2p() const {
@@ -827,6 +831,7 @@ public:
void user2p(void* userp) { m_user2p=(AstNUser*)(userp); m_user2Cnt=AstUser2InUse::s_userCntGbl; }
int user2() const { return user2p()->castInt(); }
void user2(int val) { user2p(AstNUser::fromInt(val)); }
int user2Inc() { int v=user2(); user2(v+1); return v; }
static void user2ClearTree() { AstUser2InUse::clear(); }
AstNUser* user3p() const {
@@ -835,6 +840,7 @@ public:
void user3p(void* userp) { m_user3p=(AstNUser*)(userp); m_user3Cnt=AstUser3InUse::s_userCntGbl; }
int user3() const { return user3p()->castInt(); }
void user3(int val) { user3p(AstNUser::fromInt(val)); }
int user3Inc() { int v=user3(); user3(v+1); return v; }
static void user3ClearTree() { AstUser3InUse::clear(); }
AstNUser* user4p() const {
@@ -843,6 +849,7 @@ public:
void user4p(void* userp) { m_user4p=(AstNUser*)(userp); m_user4Cnt=AstUser4InUse::s_userCntGbl; }
int user4() const { return user4p()->castInt(); }
void user4(int val) { user4p(AstNUser::fromInt(val)); }
int user4Inc() { int v=user4(); user4(v+1); return v; }
static void user4ClearTree() { AstUser4InUse::clear(); }
AstNUser* user5p() const {
@@ -851,6 +858,7 @@ public:
void user5p(void* userp) { m_user5p=(AstNUser*)(userp); m_user5Cnt=AstUser5InUse::s_userCntGbl; }
int user5() const { return user5p()->castInt(); }
void user5(int val) { user5p(AstNUser::fromInt(val)); }
int user5Inc() { int v=user5(); user5(v+1); return v; }
static void user5ClearTree() { AstUser5InUse::clear(); }
vluint64_t editCount() const { return m_editCount; }
+50 -5
View File
@@ -137,6 +137,43 @@ string AstVar::vlArgType(bool named, bool forReturn) const {
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 {
if (forReturn) named=false;
string arg;
@@ -258,13 +295,15 @@ uint32_t AstVar::arrayElements() const {
return entries;
}
uint32_t AstVar::dimensions() const {
// How many array dimensions does this Var have?
uint32_t dim = 0;
pair<uint32_t,uint32_t> AstVar::dimensions() const {
// How many array dimensions (packed,unpacked) does this Var have?
uint32_t packed = 0;
uint32_t unpacked = 0;
for (AstNodeDType* dtypep=this->dtypep(); dtypep; ) {
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
if (AstArrayDType* adtypep = dtypep->castArrayDType()) {
dim += 1;
if (adtypep->isPacked()) packed += 1;
else unpacked += 1;
dtypep = adtypep->dtypep();
}
else {
@@ -272,7 +311,7 @@ uint32_t AstVar::dimensions() const {
break;
}
}
return dim;
return make_pair(packed, unpacked);
}
// Special operators
@@ -348,6 +387,8 @@ string AstScopeName::scopeSymName() const {
out += textp->text();
}
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;
while ((pos=out.find(".")) != string::npos) {
out.replace(pos, 1, "__");
@@ -464,6 +505,10 @@ void AstNode::dump(ostream& os) {
if (name()!="") os<<" "<<AstNode::quoteName(name());
}
void AstArrayDType::dump(ostream& str) {
this->AstNode::dump(str);
if (isPacked()) str<<" [PACKED]";
}
void AstArraySel::dump(ostream& str) {
this->AstNode::dump(str);
str<<" [start:"<<start()<<"] [length:"<<length()<<"]";
+38 -5
View File
@@ -204,13 +204,17 @@ public:
struct AstArrayDType : public AstNodeDType {
// Array data type, ie "some_dtype var_name [2:0]"
AstArrayDType(FileLine* fl, AstNodeDType* dtypep, AstRange* rangep)
: AstNodeDType(fl) {
private:
bool m_packed;
public:
AstArrayDType(FileLine* fl, AstNodeDType* dtypep, AstRange* rangep, bool isPacked=false)
: AstNodeDType(fl), m_packed(isPacked) {
setOp1p(dtypep);
setOp2p(rangep);
widthSignedFrom(dtypep);
}
ASTNODE_NODE_FUNCS(ArrayDType, ARRAYDTYPE)
virtual void dump(ostream& str);
AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable
void dtypep(AstNodeDType* nodep) { setOp1p(nodep); }
@@ -225,6 +229,7 @@ struct AstArrayDType : public AstNodeDType {
int lsb() const { return arrayp()->lsbConst(); }
int elementsConst() const { return arrayp()->elementsConst(); }
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 {
@@ -542,8 +547,10 @@ private:
bool m_sc:1; // SystemC variable
bool m_scClocked:1; // SystemC sc_clk<> 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_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_usedParam:1; // Parameter is referenced (on link; later signals not setup)
bool m_funcLocal:1; // Local variable for a function
@@ -561,7 +568,7 @@ private:
m_primaryIO=false;
m_sc=false; m_scClocked=false; m_scSensitive=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_attrClockEn=false; m_attrIsolateAssign=false; m_attrSFormat=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 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 vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc
string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc
void combineType(AstVarType type);
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)
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;
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)
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); }
@@ -628,6 +637,8 @@ public:
void usedParam(bool flag) { m_usedParam = flag; }
void sigPublic(bool flag) { m_sigPublic = 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 scSensitive(bool flag) { m_scSensitive = flag; }
void primaryIO(bool flag) { m_primaryIO = flag; }
@@ -670,6 +681,8 @@ public:
bool isScSensitive() const { return m_scSensitive; }
bool isSigPublic() const;
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 isConst() const { return m_isConst; }
bool isStatic() const { return m_isStatic; }
@@ -699,6 +712,8 @@ public:
combineType(typevarp->varType());
if (typevarp->isSigPublic()) sigPublic(true);
if (typevarp->isSigModPublic()) sigModPublic(true);
if (typevarp->isSigUserRdPublic()) sigUserRdPublic(true);
if (typevarp->isSigUserRWPublic()) sigUserRWPublic(true);
if (typevarp->attrScClocked()) attrScClocked(true);
}
void inlineAttrReset(const string& name) {
@@ -1265,6 +1280,24 @@ struct AstAlways : public AstNode {
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 {
// Like always but post assignments for memory assignment IFs
AstAlwaysPost(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp)
+3
View File
@@ -642,6 +642,9 @@ private:
virtual void visit(AstAlways* nodep, AstNUser*) {
iterateNewStmt(nodep);
}
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
// CDC doesn't care about public variables
}
virtual void visit(AstCFunc* nodep, AstNUser*) {
iterateNewStmt(nodep);
}
+1 -2
View File
@@ -128,8 +128,7 @@ private:
virtual void visit(AstVarScope* nodep, AstNUser*) {
if (nodep->isCircular()) {
UINFO(8," CIRC "<<nodep<<endl);
if (!nodep->user1()) {
nodep->user1(true);
if (!nodep->user1Inc()) {
genChangeDet(nodep);
}
}
+1 -2
View File
@@ -704,8 +704,7 @@ class GaterVisitor : public GaterBaseVisitor {
virtual void visit(AstAlways* nodep, AstNUser*) {
if (debug()>=9) cout<<endl<<endl<<endl;
UINFO(5, "Gater: ALWAYS: "<<nodep<<endl);
if (nodep->user4()) return;
nodep->user4(1);
if (nodep->user4Inc()) return;
clear();
+6 -4
View File
@@ -81,10 +81,12 @@ private:
string prettyName = nodep->prettyName();
if (!nodep->isToggleCoverable())
return "Not relevant signal type";
if (prettyName.c_str()[0] == '_')
return "Leading underscore";
if (prettyName.find("._") != string::npos)
return "Inlined leading underscore";
if (!v3Global.opt.coverageUnderscore()) {
if (prettyName.c_str()[0] == '_')
return "Leading underscore";
if (prettyName.find("._") != string::npos)
return "Inlined leading underscore";
}
if ((nodep->width()*nodep->arrayElements()) > 256) return "Wide bus/array > 256 bits";
// We allow this, though tracing doesn't
// if (nodep->arrayp(1)) return "Unsupported: Multi-dimensional array";
+8 -11
View File
@@ -95,31 +95,31 @@ private:
// VISITORS
virtual void visit(AstCell* nodep, AstNUser*) {
nodep->iterateChildren(*this);
nodep->modp()->user1(nodep->modp()->user1() + 1);
nodep->modp()->user1Inc();
}
virtual void visit(AstNodeVarRef* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (nodep->varScopep()) {
nodep->varScopep()->user1(nodep->varScopep()->user1() + 1);
nodep->varScopep()->varp()->user1(nodep->varScopep()->varp()->user1() + 1);
nodep->varScopep()->user1Inc();
nodep->varScopep()->varp()->user1Inc();
}
if (nodep->varp()) {
nodep->varp()->user1(nodep->varp()->user1() + 1);
nodep->varp()->user1Inc();
}
if (nodep->packagep()) {
nodep->packagep()->user1(nodep->packagep()->user1() + 1);
nodep->packagep()->user1Inc();
}
}
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (nodep->packagep()) {
nodep->packagep()->user1(nodep->packagep()->user1() + 1);
nodep->packagep()->user1Inc();
}
}
virtual void visit(AstRefDType* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (nodep->packagep()) {
nodep->packagep()->user1(nodep->packagep()->user1() + 1);
nodep->packagep()->user1Inc();
}
}
virtual void visit(AstVarScope* nodep, AstNUser*) {
@@ -145,13 +145,10 @@ private:
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*) {
if (nodep->isOutputter()) m_sideEffect=true;
nodep->iterateChildren(*this);
}
+8 -5
View File
@@ -149,6 +149,8 @@ public:
if (decind) ofp()->blockDec();
if (!m_suppressSemi) puts(";\n");
}
virtual void visit(AstAlwaysPublic*, AstNUser*) {
}
virtual void visit(AstCCall* nodep, AstNUser*) {
puts(nodep->hiername());
puts(nodep->funcp()->name());
@@ -541,17 +543,18 @@ public:
}
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
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()) {
vluint64_t num = nodep->toUQuad();
if (num<10) ofp()->printf("VL_ULL(%" VL_PRI64 "d)", (long long)num);
else ofp()->printf("VL_ULL(0x%" VL_PRI64 "x)", (long long)num);
if (num<10) ofp()->printf("VL_ULL(%" VL_PRI64 "d)", num);
else ofp()->printf("VL_ULL(0x%" VL_PRI64 "x)", num);
} else {
uint32_t num = nodep->toUInt();
// Only 32 bits - llx + long long here just to appease CPP format warning
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:
// if (!nodep->num().isSigned() && (num & (1UL<<31))) puts("U");
}
+134 -6
View File
@@ -45,13 +45,24 @@ class EmitCSyms : EmitCBaseVisitor {
AstUser1InUse m_inuser1;
// 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;
ScopeFuncData(AstScopeName* scopep, AstCFunc* funcp, AstNodeModule* 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,AstScopeName*> ScopeNames;
typedef map<string,ScopeVarData> ScopeVars;
typedef map<string,ScopeNameData> ScopeNames;
typedef pair<AstScope*,AstNodeModule*> ScopeModPair;
typedef pair<AstNodeModule*,AstVar*> ModVarPair;
struct CmpName {
inline bool operator () (const ScopeModPair& lhsp, const ScopeModPair& rhsp) const {
return lhsp.first->name() < rhsp.first->name();
@@ -71,8 +82,10 @@ class EmitCSyms : EmitCBaseVisitor {
AstNodeModule* m_modp; // Current module
vector<ScopeModPair> m_scopes; // Every scope by module
vector<AstCFunc*> m_dpis; // DPI functions
vector<ModVarPair> m_modVars; // Each public {mod,var}
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
int m_coverBins; // Coverage bin number
int m_labelNum; // Next label number
@@ -95,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
virtual void visit(AstNetlist* nodep, AstNUser*) {
// Collect list of scopes
nodep->iterateChildren(*this);
varsExpand();
// Sort by names, so line/process order matters less
sort(m_scopes.begin(), m_scopes.end(), CmpName());
@@ -125,8 +193,9 @@ class EmitCSyms : EmitCBaseVisitor {
}
virtual void visit(AstScopeName* nodep, AstNUser*) {
string name = nodep->scopeSymName();
//UINFO(9,"scnameins sp "<<nodep->name()<<" sp "<<nodep->scopePrettyName()<<" ss "<<name<<endl);
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 (!m_funcp) nodep->v3fatalSrc("ScopeName not under DPI function");
@@ -134,6 +203,12 @@ class EmitCSyms : EmitCBaseVisitor {
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*) {
// 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
@@ -255,7 +330,7 @@ void EmitCSyms::emitSymHdr() {
puts("\n// SCOPE NAMES\n");
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");
@@ -345,8 +420,8 @@ void EmitCSyms::emitSymImp() {
puts("// Setup scope names\n");
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
puts("__Vscope_"+it->second->scopeSymName()+".configure(this,name(),");
putsQuoted(it->second->scopePrettyName());
puts("__Vscope_"+it->second.m_symName+".configure(this,name(),");
putsQuoted(it->second.m_prettyName);
puts(");\n");
}
@@ -367,6 +442,59 @@ void EmitCSyms::emitSymImp() {
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");
}
+8
View File
@@ -109,6 +109,14 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
nodep->bodysp()->iterateAndNext(*this);
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*) {
nodep->lhsp()->iterateAndNext(*this);
putfs(nodep," "+nodep->verilogKwd()+" ");
+13 -1
View File
@@ -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
// Skip `line
while (*textp && isspace(*textp)) textp++;
@@ -102,6 +108,12 @@ void FileLine::lineDirective(const char* textp) {
strfn = strfn.substr(0, textp-fn);
this->filename(strfn);
}
// Grab level
while (*textp && (isspace(*textp) || *textp=='"')) textp++;
if (isdigit(*textp)) enterExitRef = atoi(textp);
else enterExitRef = 0;
//printf ("PPLINE %d '%s'\n", s_lineno, s_filename.c_str());
}
+12 -6
View File
@@ -196,13 +196,13 @@ inline void v3errorEnd(ostringstream& sstr) { V3Error::v3errorEnd(sstr); }
// Use this instead of fatal() to mention the source code line.
#define v3fatalSrc(msg) v3warn(EC_FATALSRC,__FILE__<<":"<<dec<<__LINE__<<": "<<msg)
#define UINFO(level,stmsg) {if(debug()>=(level)) { cout<<"- "<<V3Error::lineStr(__FILE__,__LINE__)<<stmsg; }}
#define UINFONL(level,stmsg) {if(debug()>=(level)) { cout<<stmsg; } }
#define UINFO(level,stmsg) {if(VL_UNLIKELY(debug()>=(level))) { cout<<"- "<<V3Error::lineStr(__FILE__,__LINE__)<<stmsg; }}
#define UINFONL(level,stmsg) {if(VL_UNLIKELY(debug()>=(level))) { cout<<stmsg; } }
#define UDEBUGONLY(stmts) {stmts}
#define UASSERT(condition,stmsg) { if (!(condition)) { v3fatalSrc(stmsg); }}
#define UASSERT(condition,stmsg) { if (VL_UNLIKELY(!(condition))) { v3fatalSrc(stmsg); }}
// For use in V3Ast static functions only
#define UASSERT_STATIC(condition,stmsg) { if (!(condition)) { cerr<<"Internal Error: "<<__FILE__<<":"<<dec<<__LINE__<<":"<<(stmsg)<<endl; abort(); } }
#define UASSERT_STATIC(condition,stmsg) { if (VL_UNLIKELY(!(condition))) { cerr<<"Internal Error: "<<__FILE__<<":"<<dec<<__LINE__<<":"<<(stmsg)<<endl; abort(); } }
#define V3ERROR_NA { v3error("Internal: Unexpected Call"); v3fatalSrc("Unexpected Call"); }
@@ -234,26 +234,32 @@ protected:
// We are storing pointers, so we CAN'T change them after initial reading.
friend class V3ParseImp;
friend class V3PreLex;
friend class V3PreProcImp;
void lineno(int num) { m_lineno = num; }
void filename(const string& name) { m_filename = name; }
void lineDirective(const char* textp);
void incLineno() { m_lineno++; }
void lineDirective(const char* textp, int& enterExitRef);
void linenoInc() { m_lineno++; }
void linenoIncInPlace() { m_lineno++; }
FileLine* copyOrSameFileLine();
public:
FileLine (const string& filename, int lineno) { m_lineno=lineno; m_filename = filename; m_warnOn=s_defaultFileLine.m_warnOn; }
FileLine (FileLine* fromp) { m_lineno=fromp->lineno(); m_filename = fromp->filename(); m_warnOn=fromp->m_warnOn; }
FileLine (EmptySecret);
~FileLine() { }
FileLine* create(const string& filename, int lineno) { return new FileLine(filename,lineno); }
FileLine* create(int lineno) { return create(filename(), lineno); }
static void deleteAllRemaining();
#ifdef VL_LEAK_CHECKS
static void* operator new(size_t size);
static void operator delete(void* obj, size_t size);
#endif
int lineno () const { return m_lineno; }
string ascii() const;
const string filename () const { return m_filename; }
const string filebasename () 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 warnOff(V3ErrorCode code, bool flag) { warnOn(code,!flag); }
bool warnOff(const string& code, bool flag); // Returns 1 if ok
+16
View File
@@ -47,6 +47,8 @@
class ExpandVisitor : public AstNVisitor {
private:
// NODE STATE
// AstNode::user1() -> bool. Processed
AstUser1InUse m_inuser1;
// STATE
AstNode* m_stmtp; // Current statement
@@ -76,12 +78,14 @@ private:
}
void insertBefore (AstNode* placep, AstNode* newp) {
newp->user1(1); // Already processed, don't need to re-iterate
AstNRelinker linker;
placep->unlinkFrBack(&linker);
newp->addNext(placep);
linker.relink(newp);
}
void replaceWithDelete (AstNode* nodep, AstNode* newp) {
newp->user1(1); // Already processed, don't need to re-iterate
nodep->replaceWith(newp);
nodep->deleteTree(); nodep=NULL;
}
@@ -306,6 +310,7 @@ private:
// VISITORS
virtual void visit(AstExtend* nodep, AstNUser*) {
if (nodep->user1Inc()) return; // Process once
nodep->iterateChildren(*this);
if (nodep->isWide()) {
// See under ASSIGN(EXTEND)
@@ -344,6 +349,7 @@ private:
}
virtual void visit(AstSel* nodep, AstNUser*) {
if (nodep->user1Inc()) return; // Process once
nodep->iterateChildren(*this);
// Remember, Sel's may have non-integer rhs, so need to optimize for that!
if (nodep->widthMin()!=(int)nodep->widthConst()) nodep->v3fatalSrc("Width mismatch");
@@ -640,6 +646,7 @@ private:
}
virtual void visit(AstConcat* nodep, AstNUser*) {
if (nodep->user1Inc()) return; // Process once
nodep->iterateChildren(*this);
if (nodep->isWide()) {
// See under ASSIGN(WIDE)
@@ -679,6 +686,7 @@ private:
}
virtual void visit(AstReplicate* nodep, AstNUser*) {
if (nodep->user1Inc()) return; // Process once
nodep->iterateChildren(*this);
if (nodep->isWide()) {
// See under ASSIGN(WIDE)
@@ -740,6 +748,7 @@ private:
}
virtual void visit(AstChangeXor* nodep, AstNUser*) {
if (nodep->user1Inc()) return; // Process once
nodep->iterateChildren(*this);
UINFO(8," Wordize ChangeXor "<<nodep<<endl);
// -> (0=={or{for each_word{WORDSEL(lhs,#)^WORDSEL(rhs,#)}}}
@@ -754,6 +763,7 @@ private:
}
void visitEqNeq(AstNodeBiop* nodep) {
if (nodep->user1Inc()) return; // Process once
nodep->iterateChildren(*this);
if (nodep->lhsp()->isWide()) {
UINFO(8," Wordize EQ/NEQ "<<nodep<<endl);
@@ -779,6 +789,7 @@ private:
virtual void visit(AstNeq* nodep, AstNUser*) { visitEqNeq (nodep); }
virtual void visit(AstRedOr* nodep, AstNUser*) {
if (nodep->user1Inc()) return; // Process once
nodep->iterateChildren(*this);
if (nodep->lhsp()->isWide()) {
UINFO(8," Wordize REDOR "<<nodep<<endl);
@@ -802,6 +813,7 @@ private:
}
}
virtual void visit(AstRedAnd* nodep, AstNUser*) {
if (nodep->user1Inc()) return; // Process once
nodep->iterateChildren(*this);
if (nodep->lhsp()->isWide()) {
UINFO(8," Wordize REDAND "<<nodep<<endl);
@@ -830,6 +842,7 @@ private:
}
}
virtual void visit(AstRedXor* nodep, AstNUser*) {
if (nodep->user1Inc()) return; // Process once
nodep->iterateChildren(*this);
if (nodep->lhsp()->isWide()) {
UINFO(8," Wordize REDXOR "<<nodep<<endl);
@@ -840,6 +853,7 @@ private:
newp = (newp==NULL) ? eqp : (new AstXor (nodep->fileline(), newp, eqp));
}
newp = new AstRedXor (nodep->fileline(), newp);
UINFO(8," Wordize REDXORnew "<<newp<<endl);
replaceWithDelete(nodep, newp); nodep=NULL;
}
// 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*) {
if (nodep->user1Inc()) return; // Process once
m_stmtp = nodep;
nodep->iterateChildren(*this);
m_stmtp = NULL;
}
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
if (nodep->user1Inc()) return; // Process once
m_stmtp = nodep;
nodep->iterateChildren(*this);
bool did = false;
+47 -24
View File
@@ -44,6 +44,8 @@
#include "V3PreShell.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_CACHE_MAX 64*1024 // Maximum bytes to cache if same file read twice
@@ -271,6 +273,7 @@ void V3File::createMakeDir() {
class V3InFilterImp {
typedef map<string,string> FileContentsMap;
typedef V3InFilter::StrList StrList;
FileContentsMap m_contentsMap; // Cache of file contents
bool m_readEof; // Received EOF on read
@@ -292,27 +295,27 @@ private:
return level;
}
bool readContents(const string& filename, string& out) {
if (m_pid) return readContentsFilter(filename,out);
else return readContentsFile(filename,out);
bool readContents(const string& filename, StrList& outl) {
if (m_pid) return readContentsFilter(filename,outl);
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);
if (!fd) return false;
m_readEof = false;
out = readBlocks(fd, -1);
readBlocks(fd, -1, outl);
close(fd);
return true;
}
bool readContentsFilter(const string& filename, string& out) {
if (filename!="" || out!="") {} // Prevent unused
bool readContentsFilter(const string& filename, StrList& outl) {
if (filename!="" || outl.empty()) {} // Prevent unused
#ifdef INFILTER_PIPE
writeFilter("read \""+filename+"\"\n");
string line = readFilterLine();
if (line.find("Content-Length") != string::npos) {
int len = 0;
sscanf(line.c_str(), "Content-Length: %d\n", &len);
out = readBlocks(m_readFd, len);
readBlocks(m_readFd, len, outl);
return true;
} else {
if (line!="") v3error("--pipe-filter protocol error, unexpected: "<<line);
@@ -334,15 +337,19 @@ private:
#endif
}
string readBlocks(int fd, int size=-1) {
string readBlocks(int fd, int size, StrList& outl) {
string out;
char buf[INFILTER_IPC_BUFSIZ];
while (!m_readEof && (size<0 || size>(int)out.length())) {
int todo = INFILTER_IPC_BUFSIZ;
if (size>0 && size<INFILTER_IPC_BUFSIZ) todo = size;
int got = read (fd, buf, todo);
ssize_t sizegot = 0;
while (!m_readEof && (size<0 || size>sizegot)) {
ssize_t todo = INFILTER_IPC_BUFSIZ;
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);
if (got>0) out.append(buf, got);
if (got>0) {
outl.push_back(string(buf, got));
sizegot += got;
}
else if (errno == EINTR || errno == EAGAIN
#ifdef EWOULDBLOCK
|| errno == EWOULDBLOCK
@@ -358,9 +365,11 @@ private:
UINFO(9,"readFilterLine\n");
string line;
while (!m_readEof) {
string c = readBlocks(m_readFd, 1);
line += c;
if (c == "\n") {
StrList outl;
readBlocks(m_readFd, 1, outl);
string onechar = listString(outl);
line += onechar;
if (onechar == "\n") {
if (line == "\n") { line=""; continue; }
else break;
}
@@ -477,21 +486,35 @@ private:
protected:
friend class V3InFilter;
// 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);
if (it != m_contentsMap.end()) {
out = it->second;
outl.push_back(it->second);
return true;
}
if (!readContents(filename, out)) return false;
if (out.length() < INFILTER_CACHE_MAX) {
if (!readContents(filename, outl)) return false;
if (listSize(outl) < INFILTER_CACHE_MAX) {
// Cache small files (only to save space)
// 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
m_contentsMap.insert(make_pair(filename,out));
m_contentsMap.insert(make_pair(filename,listString(outl)));
}
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
V3InFilterImp(const string& command) {
m_readEof = false;
@@ -512,9 +535,9 @@ protected:
V3InFilter::V3InFilter(const string& command) { m_impp = new V3InFilterImp(command); }
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");
return m_impp->readWholefile(filename, out);
return m_impp->readWholefile(filename, outl);
}
//######################################################################
+5 -1
View File
@@ -28,6 +28,7 @@
#include <cstdio>
#include <stack>
#include <set>
#include <list>
#include <fstream>
//============================================================================
@@ -79,9 +80,12 @@ class V3InFilterImp;
class V3InFilter {
V3InFilterImp* m_impp;
public:
// TYPES
typedef list<string> StrList;
// METHODS
// 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
V3InFilter(const string& command);
+6
View File
@@ -357,6 +357,12 @@ private:
virtual void visit(AstAlways* nodep, AstNUser*) {
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*) {
iterateNewStmt(nodep, "User C Function", "User C Function");
}
+19 -3
View File
@@ -57,6 +57,7 @@ private:
// AstNodeModule::user1p() // bool. True to inline this module (from InlineMarkVisitor)
// Cleared each cell
// 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
AstNodeModule* m_modp; // Current module
@@ -151,6 +152,10 @@ private:
UINFO(6,"One-to-one "<<connectRefp<<endl);
UINFO(6," -to "<<pinNewVarp<<endl);
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
m_cellp = nodep;
@@ -175,6 +180,7 @@ private:
// user2p is either a const or a var.
AstConst* exprconstp = nodep->user2p()->castNode()->castConst();
AstVarRef* exprvarrefp = nodep->user2p()->castNode()->castVarRef();
UINFO(1,"connectto: "<<nodep->user2p()->castNode()<<endl);
if (!exprconstp && !exprvarrefp) {
nodep->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up\n");
}
@@ -182,6 +188,15 @@ private:
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, 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 {
m_modp->addStmtp(new AstAssignAlias(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
@@ -216,8 +231,9 @@ private:
}
virtual void visit(AstVarRef* nodep, AstNUser*) {
if (m_cellp) {
if (nodep->varp()->user2p() // It's being converted to a alias.
&& !nodep->backp()->castAssignAlias()) { // Don't constant propagate aliases
if (nodep->varp()->user2p() // It's being converted to an alias.
&& !nodep->varp()->user3()
&& !nodep->backp()->castAssignAlias()) { // Don't constant propagate aliases (we just made)
AstConst* exprconstp = nodep->varp()->user2p()->castNode()->castConst();
AstVarRef* exprvarrefp = nodep->varp()->user2p()->castNode()->castVarRef();
if (exprconstp) {
@@ -355,7 +371,7 @@ private:
m_modp = NULL;
}
virtual void visit(AstCell* nodep, AstNUser*) {
nodep->modp()->user3( nodep->modp()->user3() + 1);
nodep->modp()->user3Inc();
nodep->iterateChildren(*this);
}
virtual void visit(AstPragma* nodep, AstNUser*) {
+1 -2
View File
@@ -89,8 +89,7 @@ private:
if (nodep->modVarp()->isOutOnly() && nodep->exprp()->castConst())
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
if (!nodep->user1()) {
nodep->user1(1);
if (!nodep->user1Inc()) {
// Simplify it
V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp);
// Make a ASSIGNW (expr, pin)
+30 -10
View File
@@ -77,8 +77,7 @@ private:
// VISITs
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
if (!nodep->user1()) {
nodep->user1(true); // Process only once.
if (!nodep->user1Inc()) { // Process only once.
UINFO(5," "<<nodep<<endl);
checkExpected(nodep);
// Due to a need to get the arguments, the ParseRefs are under here,
@@ -165,8 +164,7 @@ private:
}
}
virtual void visit(AstSelBit* nodep, AstNUser*) {
if (!nodep->user1()) {
nodep->user1(true); // Process only once.
if (!nodep->user1Inc()) { // Process only once.
if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart}
m_dotText = "";
nodep->lhsp()->iterateAndNext(*this);
@@ -194,8 +192,7 @@ private:
}
virtual void visit(AstNodePreSel* nodep, AstNUser*) {
// Excludes simple AstSel, see above
if (!nodep->user1()) {
nodep->user1(true); // Process only once.
if (!nodep->user1Inc()) { // Process only once.
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");
} else if (m_exp==AstParseRefExp::PX_FUNC) {
@@ -217,8 +214,7 @@ private:
}
}
virtual void visit(AstText* nodep, AstNUser*) {
if (!nodep->user1()) {
nodep->user1(true); // Process only once.
if (!nodep->user1Inc()) { // Process only once.
if (m_exp != AstParseRefExp::PX_NONE) {
UINFO(7," "<<nodep<<endl);
if (m_inModDot) { // Dotted part, just pass up
@@ -274,12 +270,22 @@ private:
}
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC) {
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;
}
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT) {
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;
}
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*) {
UINFO(8," DEFIMPLICIT "<<nodep<<endl);
// Must remember what names we've already created, and combine duplicates
+1 -2
View File
@@ -109,8 +109,7 @@ private:
}
}
virtual void visit(AstScope* nodep, AstNUser*) {
if (!nodep->user1()) {
nodep->user1(1);
if (!nodep->user1Inc()) {
if (nodep->aboveScopep()) nodep->aboveScopep()->iterate(*this);
if (nodep->aboveCellp()) nodep->aboveCellp()->iterate(*this);
// Always recompute name (as many level above scope may have changed)
+7 -1
View File
@@ -611,9 +611,12 @@ void V3Options::parseOptsList(FileLine* fl, int argc, char** argv) {
else if ( onoff (sw, "-coverage", flag/*ref*/) ) { coverage(flag); }
else if ( onoff (sw, "-coverage-line", flag/*ref*/) ){ m_coverageLine = flag; }
else if ( onoff (sw, "-coverage-toggle", flag/*ref*/) ){ m_coverageToggle = flag; }
else if ( onoff (sw, "-coverage-underscore", flag/*ref*/) ){ m_coverageUnderscore = flag; }
else if ( onoff (sw, "-coverage-user", flag/*ref*/) ){ m_coverageUser = flag; }
else if ( onoff (sw, "-covsp", flag/*ref*/) ) { } // TBD
else if ( !strcmp (sw, "-debug-abort") ) { abort(); } // Undocumented, see also --debug-core-dump
else if ( onoff (sw, "-debug-check", flag/*ref*/) ){ m_debugCheck = flag; }
else if ( !strcmp (sw, "-debug-core-dump") ) { char* zp=NULL; *zp=0; } // Undocumented, see also --debug-abort
else if ( onoff (sw, "-dump-tree", flag/*ref*/) ) { m_dumpTree = flag; }
else if ( onoff (sw, "-exe", flag/*ref*/) ) { m_exe = flag; }
else if ( onoff (sw, "-ignc", flag/*ref*/) ) { m_ignc = flag; }
@@ -634,6 +637,7 @@ void V3Options::parseOptsList(FileLine* fl, int argc, char** argv) {
else if ( !strcmp (sw, "-sv") ) { m_language = V3LangCode::L1800_2005; }
else if ( onoff (sw, "-trace", flag/*ref*/) ) { m_trace = flag; }
else if ( onoff (sw, "-trace-dups", flag/*ref*/) ) { m_traceDups = flag; }
else if ( onoff (sw, "-trace-underscore", flag/*ref*/) ) { m_traceUnderscore = flag; }
else if ( onoff (sw, "-underline-zero", flag/*ref*/) ) { m_underlineZero = flag; } // Undocumented, old Verilator-2
// Optimization
else if ( !strncmp (sw, "-O", 2) ) {
@@ -993,6 +997,7 @@ V3Options::V3Options() {
m_autoflush = false;
m_coverageLine = false;
m_coverageToggle = false;
m_coverageUnderscore = false;
m_coverageUser = false;
m_debugCheck = false;
m_dumpTree = false;
@@ -1014,6 +1019,7 @@ V3Options::V3Options() {
m_systemPerl = false;
m_trace = false;
m_traceDups = false;
m_traceUnderscore = false;
m_underlineZero = false;
m_errorLimit = 50;
@@ -1023,7 +1029,7 @@ V3Options::V3Options() {
m_outputSplitCTrace = 0;
m_traceDepth = 0;
m_unrollCount = 64;
m_unrollStmts = 100;
m_unrollStmts = 30000;
m_compLimitParens = 0;
m_compLimitBlocks = 0;
+4
View File
@@ -103,6 +103,7 @@ class V3Options {
bool m_cdc; // main switch: --cdc
bool m_coverageLine; // main switch: --coverage-block
bool m_coverageToggle;// main switch: --coverage-toggle
bool m_coverageUnderscore;// main switch: --coverage-underscore
bool m_coverageUser; // main switch: --coverage-func
bool m_debugCheck; // main switch: --debug-check
bool m_dumpTree; // main switch: --dump-tree
@@ -122,6 +123,7 @@ class V3Options {
bool m_stats; // main switch: --stats
bool m_trace; // main switch: --trace
bool m_traceDups; // main switch: --trace-dups
bool m_traceUnderscore;// main switch: --trace-underscore
bool m_underlineZero;// main switch: --underline-zero; undocumented old Verilator 2
int m_errorLimit; // main switch: --error-limit
@@ -222,12 +224,14 @@ class V3Options {
bool coverage() const { return m_coverageLine || m_coverageToggle || m_coverageUser; }
bool coverageLine() const { return m_coverageLine; }
bool coverageToggle() const { return m_coverageToggle; }
bool coverageUnderscore() const { return m_coverageUnderscore; }
bool coverageUser() const { return m_coverageUser; }
bool debugCheck() const { return m_debugCheck; }
bool dumpTree() const { return m_dumpTree; }
bool exe() const { return m_exe; }
bool trace() const { return m_trace; }
bool traceDups() const { return m_traceDups; }
bool traceUnderscore() const { return m_traceUnderscore; }
bool outFormatOk() const { return m_outFormatOk; }
bool keepTempFiles() const { return (V3Error::debugDefault()!=0); }
bool pinsUint8() const { return m_pinsUint8; }
+4 -1
View File
@@ -375,7 +375,7 @@ private:
OrderLoopId processMoveLoopCurrent();
string cfuncName(AstNodeModule* modp, AstSenTree* domainp, AstScope* scopep, AstNode* forWhatp) {
modp->user3(1+modp->user3());
modp->user3Inc();
int funcnum = modp->user3();
string name = (domainp->hasCombo() ? "_combo"
: (domainp->hasInitial() ? "_initial"
@@ -666,6 +666,9 @@ private:
iterateNewStmt(nodep);
m_inPost = false;
}
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
iterateNewStmt(nodep);
}
virtual void visit(AstAssignAlias* nodep, AstNUser*) {
iterateNewStmt(nodep);
}
+4 -3
View File
@@ -52,10 +52,11 @@
class ParamVisitor : public AstNVisitor {
private:
// 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)
// // (0=not processed, 1=iterated, but no number, 65+ parameter numbered)
AstUser4InUse m_inuser4;
AstUser5InUse m_inuser5;
// User1/2/3 used by constant function simulations
// STATE
@@ -130,8 +131,8 @@ private:
// Make sure all parameters are constantified
virtual void visit(AstVar* nodep, AstNUser*) {
if (!nodep->user4()) {
nodep->user4(1); // Mark done - Note values >1 used for letter numbering
if (!nodep->user5()) {
nodep->user5(1); // Mark done
nodep->iterateChildren(*this);
if (nodep->isParam()) {
if (!nodep->hasSimpleInit()) { nodep->v3fatalSrc("Parameter without initial value"); }
+3 -3
View File
@@ -66,12 +66,12 @@ V3ParseImp::~V3ParseImp() {
if (debug()>=9) { UINFO(0,"~V3ParseImp\n"); symp()->dump(cout, "-vpi: "); }
}
int V3ParseImp::ppInputToLex(char* buf, int max_size) {
int got = 0;
size_t V3ParseImp::ppInputToLex(char* buf, size_t max_size) {
size_t got = 0;
while (got < max_size // Haven't got enough
&& !m_ppBuffers.empty()) { // And something buffered
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
string remainder = front.substr(max_size-got);
front = front.substr(0, max_size-got);
+4 -4
View File
@@ -249,7 +249,7 @@ public:
static bool optFuture(const string& flag) { return v3Global.opt.isFuture(flag); }
void ppline (const char* text);
void incLineno() { fileline()->incLineno(); }
void linenoInc() { fileline()->linenoInc(); }
void verilatorCmtLint(const char* text, bool on);
void verilatorCmtLintSave();
void verilatorCmtLintRestore();
@@ -260,7 +260,7 @@ public:
static const char* tokenName(int tok);
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; }
@@ -278,7 +278,7 @@ public:
m_stringps.push_back(strp);
return strp;
}
string* newString(const char* text, int length) {
string* newString(const char* text, size_t length) {
string* strp = new string (text, length);
m_stringps.push_back(strp);
return strp;
@@ -307,7 +307,7 @@ public:
void statePushVlg(); // Parser -> lexer communication
void statePop(); // 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
V3ParseSym* symp() { return &m_sym; }
+72 -17
View File
@@ -27,12 +27,17 @@
#ifndef _VPREPROCLEX_H_ // Guard
#define _VPREPROCLEX_H_ 1
#include <deque>
#include <stack>
#include "V3Error.h"
//======================================================================
class V3PreProcImp;
// Token codes
// If changing, see V3Pre.cpp's V3PreImp::tokenName()
// If changing, see V3PreProc.cpp's V3PreProcImp::tokenName()
#define VP_EOF 0
#define VP_INCLUDE 256
@@ -56,10 +61,13 @@
#define VP_DEFARG 307
#define VP_ERROR 308
#define VP_DEFFORM 309
#define VP_STRIFY 310
#define VP_BACKQUOTE 311
#define VP_SYMBOL_JOIN 312
#define VP_DEFREF_JOIN 313
#define VP_PSL 350
//======================================================================
// Externs created by flex
// We add a prefix so that other lexers/flexers in the same program won't collide.
@@ -110,21 +118,41 @@ void yy_delete_buffer( YY_BUFFER_STATE b );
//======================================================================
#define KEEPCMT_SUB 2
#define KEEPCMT_EXP 3
//======================================================================
// Class entry for each per-lexter state
// 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 {
public: // Used only by V3PreLex.cpp and V3PreProc.cpp
FileLine* m_curFilelinep; // Current processing point
// Parse state
stack<YY_BUFFER_STATE> m_bufferStack; // Stack of inserted text above current point
V3PreProcImp* m_preimpp; // Preprocessor lexor belongs to
stack<VPreStream*> m_streampStack; // Stack of processing files
YY_BUFFER_STATE m_bufferState; // Flex state
FileLine* m_tokFilelinep; // Starting position of current token
// State to lexer
static V3PreLex* s_currentLexp; // Current lexing point
int m_keepComments; // Emit comments in output text
bool m_pedantic; // Obey standard; don't Substitute `error
static V3PreLex* s_currentLexp; ///< Current lexing point
int m_keepComments; ///< Emit comments in output text
int m_keepWhitespace; ///< Emit all whitespace in output text
bool m_pedantic; ///< Obey standard; don't Substitute `error
// State from lexer
int m_formalLevel; // Parenthesis counting inside def formals
@@ -133,35 +161,62 @@ class V3PreLex {
bool m_pslMoreNeeded;// Next // comment is really psl
bool m_defCmtSlash; // /*...*/ comment in define had \ ending
string m_defValue; // Definition value being built.
int m_enterExit; // For VL_LINE, the enter/exit level
// CONSTRUCTORS
V3PreLex() {
V3PreLex(V3PreProcImp* preimpp, FileLine* filelinep) {
m_preimpp = preimpp;
m_keepComments = 0;
m_keepWhitespace = 1;
m_pedantic = false;
m_formalLevel = 0;
m_parenLevel = 0;
m_defCmtSlash = false;
m_tokFilelinep = filelinep;
m_enterExit = 0;
m_pslParenLevel = 0;
m_pslMoreNeeded = false;
initFirstBuffer(filelinep);
}
~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
void appendDefValue(const char* text, int len);
void lineDirective(const char* text);
void incLineno() { m_curFilelinep->incLineno(); }
VPreStream* curStreamp() { return m_streampStack.top(); } // Can't be empty, "EOF" is on top
FileLine* curFilelinep() { return curStreamp()->m_curFilelinep; }
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
void pushStateDefArg(int level);
void pushStateDefForm();
void pushStateDefValue();
void pushStateIncFilename();
void scanBytes(const string& strg);
/// Called by VPreproc.cpp to get data from lexer
void scanNewFile(FileLine* filelinep);
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();
int lex();
int currentStartState();
void dumpSummary();
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
+251 -35
View File
@@ -1,3 +1,8 @@
%option noyywrap align interactive
%option stack
%option noc++
%option prefix="V3PreLex"
%{
/**************************************************************************
* DESCRIPTION: Verilator: Flex verilog preprocessor
*
@@ -20,12 +25,6 @@
* lost characters.
**************************************************************************/
%option noyywrap align interactive
%option stack
%option noc++
%option prefix="V3PreLex"
%{
#include "V3PreProc.h"
#include "V3PreLex.h"
@@ -33,18 +32,21 @@ V3PreLex* V3PreLex::s_currentLexp = NULL; // Current lexing point
#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
static void linenoInc() {LEXP->incLineno();}
static void linenoInc() {LEXP->linenoInc();}
static bool optPsl() { return V3PreProc::optPsl(); }
static bool pedantic() { return LEXP->m_pedantic; }
static void yyerror(char* msg) { LEXP->m_curFilelinep->v3error(msg); }
static void yyerrorf(const char* msg) { LEXP->m_curFilelinep->v3error(msg); }
static void appendDefValue(const char* t,int l) { LEXP->appendDefValue(t,l); }
static void yyerror(char* msg) { LEXP->curFilelinep()->v3error(msg); }
static void yyerrorf(const char* msg) { LEXP->curFilelinep()->v3error(msg); }
static void appendDefValue(const char* t, size_t l) { LEXP->appendDefValue(t,l); }
static int pslParenLevel() { return LEXP->m_pslParenLevel; }
static void pslParenLevelInc() { LEXP->m_pslParenLevel++; }
static void pslParenLevelDec() { if (pslParenLevel()) LEXP->m_pslParenLevel--; }
@@ -76,8 +78,12 @@ ws [ \t\f\r]
wsn [ \t\f]
crnl [\r]*[\n]
quote [\"]
tickquote [`][\"]
backslash [\\]
/* Where we use symb/symbdef, we must also look for a `` join */
symb ([a-zA-Z_][a-zA-Z0-9_$]*|\\[^ \t\f\r\n]+)
symbdef ([a-zA-Z_][a-zA-Z0-9_$]*|\\[^ \t\f\r\n`]+)
word [a-zA-Z0-9_]+
drop [\032]
psl [p]sl
@@ -100,11 +106,11 @@ psl [p]sl
/* Optional directives we recognize */
<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();
return (VP_STRING); }
<INITIAL>"`__LINE__" { static char buf[10];
sprintf(buf, "%d",LEXP->m_curFilelinep->lineno());
sprintf(buf, "%d",LEXP->curFilelinep()->lineno());
yytext = buf; yyleng = strlen(yytext);
return (VP_TEXT); }
<INITIAL>"`error" { if (!pedantic()) return (VP_ERROR); else return(VP_DEFREF); }
@@ -113,6 +119,7 @@ psl [p]sl
<INITIAL,PSLMULM,PSLONEM>{quote} { yy_push_state(STRMODE); yymore(); }
<STRMODE><<EOF>> { linenoInc(); yyerrorf("EOF in unterminated string"); yyleng=0; yyterminate(); }
<STRMODE>{crnl} { linenoInc(); yyerrorf("Unterminated string"); BEGIN(INITIAL); }
<STRMODE>{word} { yymore(); }
<STRMODE>[^\"\\] { yymore(); }
<STRMODE>{backslash}{crnl} { linenoInc(); yymore(); }
<STRMODE>{backslash}. { yymore(); }
@@ -120,6 +127,10 @@ psl [p]sl
if (LEXP->m_parenLevel || LEXP->m_formalLevel) { appendDefValue(yytext,yyleng); yyleng=0; }
else return (VP_STRING); }
/* Stringification */
<INITIAL>{tickquote} { return VP_STRIFY; }
<INITIAL>"`\\`\"" { return VP_BACKQUOTE; }
/* Protected blocks */
<INITIAL>"`protected" { yy_push_state(PRTMODE); yymore(); }
<PRTMODE><<EOF>> { linenoInc(); yyerrorf("EOF in `protected"); yyleng=0; yyterminate(); }
@@ -141,7 +152,7 @@ psl [p]sl
<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 */
/* 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; if ((--LEXP->m_formalLevel)==0) { yy_pop_state(); return VP_DEFFORM; } }
<DEFFORM>"/*" { yy_push_state(CMTMODE); yymore(); }
@@ -149,22 +160,24 @@ psl [p]sl
<DEFFORM>{drop} { }
<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>{quote} { yy_push_state(STRMODE); yymore(); }
<DEFFORM>[\\]{crnl} { linenoInc(); appendDefValue((char*)"\\\n",2); } /* Include return so can maintain output line count */
<DEFFORM>{quote} { yy_push_state(STRMODE); yymore(); } /* Legal only in default values */
<DEFFORM>"`\\`\"" { 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>[^\/\*\n\r\\(){}\[\]\"]+ |
<DEFFORM>[\\][^\n\r] |
<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>"//"[^\n\r]*[\\]{crnl} { linenoInc(); appendDefValue((char*)"\n",1); } /* Spec says // not part of define value */
<DEFVAL>"//"[^\n\r]* { return (VP_COMMENT);}
<DEFVAL>{drop} { }
<DEFVAL><<EOF>> { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); } /* Technically illegal, but people complained */
<DEFVAL>{crnl} { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); }
<DEFVAL>[\\]{crnl} { linenoInc(); appendDefValue((char*)"\n",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>. { appendDefValue(yytext,yyleng); }
@@ -177,16 +190,19 @@ psl [p]sl
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");
BEGIN(CMTMODE); }
<DEFCMT>{word} { yymore(); }
<DEFCMT>. { yymore(); }
<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>"//"[^\n\r]* { return (VP_COMMENT);}
<ARGMODE>{drop} { }
<ARGMODE><<EOF>> { yyerrorf("EOF in define argument list\n"); yyleng = 0; yyterminate(); }
<ARGMODE>{crnl} { linenoInc(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); }
<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++;
@@ -209,7 +225,8 @@ psl [p]sl
} else {
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>"`"{symbdef}`` { appendDefValue(yytext,yyleng); } /* defref in defref - outer macro expands first */
<ARGMODE>[^\/\*\n\r\\(,){}\[\]\"`]+ |
<ARGMODE>. { appendDefValue(yytext,yyleng); }
@@ -241,6 +258,7 @@ psl [p]sl
<CMTBEGM,CMTMODE>"*/" { yy_pop_state(); return(VP_COMMENT); }
<CMTBEGM,CMTMODE>{crnl} { linenoInc(); yymore(); }
<CMTBEGM,CMTMODE><<EOF>> { yyerrorf("EOF in '/* ... */' block comment\n"); yyleng=0; yyterminate(); }
<CMTMODE>{word} { yymore(); }
<CMTBEGM>. { BEGIN CMTMODE; yymore(); } /* Non 'psl' beginning in comment */
<CMTMODE>. { yymore(); }
@@ -251,12 +269,15 @@ psl [p]sl
<PSLMULM>"//"[^\n\r]* { return (VP_COMMENT); } /* Comments inside block comments get literal inclusion (later removal) */
/* Define calls */
<INITIAL,PSLMULM,PSLONEM>"`"{symb} { return (VP_DEFREF); }
/* symbdef prevents normal lex rules from making `\`"foo a symbol {`"foo} instead of a BACKQUOTE */
<INITIAL,PSLMULM,PSLONEM>"`"{symbdef} { return (VP_DEFREF); }
<INITIAL,PSLMULM,PSLONEM>"`"{symbdef}`` { yyleng-=2; return (VP_DEFREF_JOIN); }
/* Generics */
<INITIAL,PSLMULM>{crnl} { linenoInc(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); }
<INITIAL,PSLMULM,PSLONEM><<EOF>> { yyterminate(); } /* A "normal" EOF */
<INITIAL,PSLMULM,PSLONEM>{symb} { return (VP_SYMBOL); }
<INITIAL,PSLMULM,PSLONEM><<EOF>> { yyterminate(); } /* A "normal" EOF */
<INITIAL,PSLMULM,PSLONEM>{symb} { return (VP_SYMBOL); }
<INITIAL,PSLMULM,PSLONEM>{symb}`` { yyleng-=2; return (VP_SYMBOL_JOIN); }
<INITIAL,PSLMULM,PSLONEM>{wsn}+ { return (VP_WHITE); }
<INITIAL,PSLMULM,PSLONEM>{drop} { }
<INITIAL,PSLMULM,PSLONEM>[\r] { }
@@ -290,14 +311,177 @@ void V3PreLex::pushStateIncFilename() {
yymore();
}
void V3PreLex::scanBytes(const string& strg) {
yy_scan_bytes(strg.c_str(), strg.length());
m_bufferStack.push(currentBuffer()); // yy_scan_bytes makes new buffer
void V3PreLex::debug(int level) { yy_flex_debug=level; }
int V3PreLex::debug() { return yy_flex_debug; }
int V3PreLex::lex() {
V3PreLex::s_currentLexp = this; // Tell parser where to get/put data
m_tokFilelinep = curFilelinep(); // Remember token start location, may be updated by the lexer later
return yylex();
}
void V3PreLex::appendDefValue(const char* textp, int len) {
// Append given text to current definition value being formed
m_defValue.append(textp,len);
size_t V3PreLex::inputToLex(char* buf, size_t max_size) {
// We need a custom YY_INPUT because we can't use flex buffers.
// 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() {
@@ -309,22 +493,54 @@ int V3PreLex::currentStartState() {
}
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
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() {
// For debug use
stack<YY_BUFFER_STATE> tmpstack = m_bufferStack;
printf(" bufferStack[%p]:",this);
dumpSummary();
stack<VPreStream*> tmpstack = LEXP->m_streampStack;
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();
}
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:
* mode: C++
+513 -231
View File
File diff suppressed because it is too large Load Diff
+15 -6
View File
@@ -29,8 +29,12 @@
#include <string>
#include <map>
#include <list>
#include <iostream>
// Compatibility with Verilog-Perl's preprocessor
#define fatalSrc(msg) v3fatalSrc(msg)
class V3InFilter;
class V3PreProc {
@@ -39,14 +43,14 @@ class V3PreProc {
protected:
// STATE
FileLine* m_fileline; // Last token's starting point
int m_debug; // Debugging
public:
// CONSTANTS
enum MiscConsts {
DEFINE_RECURSION_LEVEL_MAX = 50, // How many `def substitutions before an error
INCLUDE_DEPTH_MAX = 500 // How many `includes deep before an error
DEFINE_RECURSION_LEVEL_MAX = 1000, // How many `def substitutions 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
@@ -59,11 +63,12 @@ public:
int debug() const { return m_debug; }
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
// These options control how the parsing proceeds
int keepComments() { return 2; } // Return comments, 0=no, 1=yes, 2=callback
bool keepWhitespace() { return false; }
bool lineDirectives() { return true; } // Insert `line directives
bool pedantic() { return false; } // Obey standard; Don't substitute `error
static bool optPsl();
@@ -82,12 +87,16 @@ public:
}
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:
// CONSTUCTORS
V3PreProc(FileLine* fl) {
m_fileline=fl;
V3PreProc() {
m_debug=0;
};
void configure(FileLine* fl);
public:
static V3PreProc* createPreProc(FileLine* fileline);
virtual ~V3PreProc() {}
+7 -2
View File
@@ -48,9 +48,12 @@ protected:
//---------------------------------------
// METHODS
static int debug() {
static int debug(bool reset=false) {
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;
}
@@ -72,6 +75,8 @@ protected:
}
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
UINFONL(1," Preprocessing "<<modname<<endl);
+1 -2
View File
@@ -196,9 +196,8 @@ private:
}
void visitShift (AstNodeBiop* nodep) {
// 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);
nodep->user2(true);
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
&& nodep->width() < (1LL<<nodep->rhsp()->widthMin())) {
+11
View File
@@ -165,6 +165,14 @@ private:
m_scopep->addActivep(clonep);
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*) {
// Add to list of blocks under this scope
UINFO(4," Move "<<nodep<<endl);
@@ -291,6 +299,9 @@ private:
virtual void visit(AstAlways* nodep, AstNUser*) {
movedDeleteOrIterate(nodep);
}
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
movedDeleteOrIterate(nodep);
}
virtual void visit(AstCoverToggle* nodep, AstNUser*) {
movedDeleteOrIterate(nodep);
}
+176 -34
View File
@@ -54,6 +54,14 @@ class SliceCloneVisitor : public AstNVisitor {
// AstArraySel::user1p() -> AstVarRef. The VarRef that the final ArraySel points to
// 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
vector<vector<unsigned> > m_selBits; // Indexes of the ArraySel we are expanding
int m_vecIdx; // Current vector index
@@ -76,8 +84,9 @@ class SliceCloneVisitor : public AstNVisitor {
if (m_vecIdx == (int)m_selBits.size()) {
m_selBits.push_back(vector<unsigned>());
AstVar* varp = m_refp->varp();
int dimensions = varp->dimensions();
for (int i = 0; i < dimensions; ++i) {
pair<uint32_t,uint32_t> arrDim = varp->dimensions();
uint32_t dimensions = arrDim.first + arrDim.second;
for (uint32_t i = 0; i < dimensions; ++i) {
m_selBits[m_vecIdx].push_back(0);
}
}
@@ -112,6 +121,7 @@ class SliceCloneVisitor : public AstNVisitor {
}
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
if (nodep->user2() < 2) return; // Don't need clones
m_selBits.clear();
UINFO(4, "Cloning "<<nodep->user2()<<" times: "<<nodep<<endl);
for (int i = 0; i < nodep->user2(); ++i) {
@@ -124,13 +134,77 @@ class SliceCloneVisitor : public AstNVisitor {
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*) {
// Default: Just iterate
nodep->iterateChildren(*this);
}
public:
// CONSTUCTORS
SliceCloneVisitor(AstNodeAssign* assignp) {
SliceCloneVisitor(AstNode* assignp) {
assignp->accept(*this);
}
virtual ~SliceCloneVisitor() {}
@@ -142,15 +216,20 @@ class SliceVisitor : public AstNVisitor {
// NODE STATE
// Cleared on netlist
// 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
// AstNode::user2() -> int. The number of clones needed for this node
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
// TYPEDEFS
typedef pair<uint32_t, uint32_t> ArrayDimensions; // Array Dimensions (packed, unpacked)
// STATE
AstNode* m_assignp; // Assignment we are under
AstNodeVarRef* m_lhsVarRefp; // Var on the LHS
bool m_extend; // We have found an extend node
bool m_assignError; // True if the current assign already has an error
// METHODS
static int debug() {
@@ -178,15 +257,13 @@ class SliceVisitor : public AstNVisitor {
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).
// Return a new pointer to replace fromp() in the ArraySel.
AstVarRef* fromp = nodep;
if (!fromp) nodep->v3fatalSrc("NULL VarRef passed to insertImplicit");
AstVar* varp = fromp->varp();
// Get the DType and insert a new ArraySel
AstArraySel* topp = NULL;
AstArraySel* bottomp = NULL;
// Return a new pointer to replace nodep() in the ArraySel.
AstVarRef* refp = nodep->user1p()->castNode()->castVarRef();
if (!refp) nodep->v3fatalSrc("No VarRef in user1 of node "<<nodep);
AstVar* varp = refp->varp();
AstNode* topp = nodep;
for (unsigned i = start; i < start + count; ++i) {
AstNodeDType* dtypep = varp->dtypeDimensionp(i-1);
AstArrayDType* adtypep = dtypep->castArrayDType();
@@ -197,17 +274,13 @@ class SliceVisitor : public AstNVisitor {
// Below code assumes big bit endian; just works out if we swap
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->length(msb - lsb + 1);
if (!topp) topp = newp;
fromp = newp->fromp()->unlinkFrBack()->castVarRef();
if (bottomp) bottomp->fromp(newp);
bottomp = newp;
topp = newp->castNode();
}
bottomp->fromp(fromp);
return topp;
return topp->castArraySel();
}
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
// case we need to create a slice accross the entire Var
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) {
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;
newp->accept(*this);
}
@@ -239,8 +315,18 @@ class SliceVisitor : public AstNVisitor {
virtual void visit(AstExtend* nodep, AstNUser*) {
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_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);
}
@@ -249,22 +335,24 @@ class SliceVisitor : public AstNVisitor {
if (!m_assignp) return;
unsigned dim = explicitDimensions(nodep);
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) {
AstNode* backp = refp->backp();
AstNode* newp = insertImplicit(refp->cloneTree(false), dim+1, implicit);
backp->castArraySel()->fromp()->replaceWith(newp);
AstArraySel* newp = insertImplicit(nodep->cloneTree(false), dim+1, implicit);
nodep->replaceWith(newp); nodep = newp;
}
int clones = countClones(nodep);
if (m_assignp->user2() > 0 && m_assignp->user2() != clones) {
m_assignp->v3error("Slices of arrays in assignments must have the same unpacked dimensions");
} else if (m_assignp->user2() == 0) {
} else if (m_assignp->user2() == 0 && !m_assignError) {
if (m_extend && clones > 1) {
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()) {
// 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_assignError = true;
}
m_assignp->user2(clones);
}
@@ -272,8 +360,9 @@ class SliceVisitor : public AstNVisitor {
virtual void visit(AstSel* nodep, AstNUser*) {
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_assignError = true;
}
nodep->iterateChildren(*this);
}
@@ -314,6 +403,7 @@ class SliceVisitor : public AstNVisitor {
void findImplicit(AstNodeAssign* nodep) {
if (m_assignp) nodep->v3fatalSrc("Found a NodeAssign under another NodeAssign");
m_assignp = nodep;
m_assignError = false;
m_extend = false;
nodep->user1(true);
// 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
// in the array so we know how many times we need to clone this assignment.
nodep->iterateChildren(*this);
if (nodep->user2() > 1) {
SliceCloneVisitor scv(nodep);
}
if (nodep->user2() > 1) SliceCloneVisitor scv(nodep);
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*) {
// Default: Just iterate
nodep->iterateChildren(*this);
@@ -354,6 +496,6 @@ public:
// Link class functions
void V3Slice::sliceAll(AstNetlist* rootp) {
UINFO(4,__FUNCTION__<<": "<<endl);
UINFO(2,__FUNCTION__<<": "<<endl);
SliceVisitor visitor(rootp);
}
+2 -3
View File
@@ -1034,6 +1034,7 @@ private:
AstNodeFTask* funcp = nodep->taskp();
if (!funcp) nodep->v3fatalSrc("unlinked");
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
iterateIntoFTask(funcp);
// Create output variable
@@ -1066,10 +1067,8 @@ private:
AstNode* prevInsStmtp = m_insStmtp;
m_insMode = IM_BEFORE;
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
nodep->user1(true);
int modes = 0;
if (nodep->dpiImport()) modes++;
if (nodep->dpiExport()) modes++;
+6 -4
View File
@@ -69,10 +69,12 @@ private:
string prettyName = nodep->prettyName();
if (!nodep->isTrace())
return "Verilator trace_off";
if (prettyName.c_str()[0] == '_')
return "Leading underscore";
if (prettyName.find("._") != string::npos)
return "Inlined leading underscore";
if (!v3Global.opt.traceUnderscore()) {
if (prettyName.c_str()[0] == '_')
return "Leading underscore";
if (prettyName.find("._") != string::npos)
return "Inlined leading underscore";
}
if (nodep->width() > 256) return "Wide bus > 256 bits";
if (nodep->arrayElements() > 32) return "Wide memory > 32 ents";
if (!(nodep->dtypeSkipRefp()->castBasicDType()
+2 -4
View File
@@ -322,8 +322,7 @@ private:
void visit(AstSel* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (!nodep->user1()) {
nodep->user1(1);
if (!nodep->user1Inc()) {
// Guard against reading/writing past end of bit vector array
int maxmsb = 0;
bool lvalue = false;
@@ -373,8 +372,7 @@ private:
virtual void visit(AstArraySel* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (!nodep->user1()) {
nodep->user1(1);
if (!nodep->user1Inc()) {
if (debug()==9) nodep->dumpTree(cout,"-in: ");
// Guard against reading/writing past end of arrays
AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp());
+23 -12
View File
@@ -82,6 +82,20 @@ private:
: 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,
AstNode* initp, // Maybe under nodep (no nextp), or standalone (ignore nextp)
AstNode* precondsp, AstNode* condp,
@@ -174,22 +188,19 @@ private:
//
if (!m_generate) {
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");
// Less than 10 statements in the body?
int bodySize = 0;
for (AstNode* bodp = precondsp; bodp; bodp=bodp->nextp()) {
bodySize++;
}
for (AstNode* bodp = bodysp; bodp; bodp=bodp->nextp()) {
bodySize++;
}
for (AstNode* bodp = incp; bodp; bodp=bodp->nextp()) {
bodySize++;
}
if (bodySize > v3Global.opt.unrollStmts())
int bodyLimit = v3Global.opt.unrollStmts();
if (loops>0) bodyLimit = v3Global.opt.unrollStmts() / loops;
if (bodySizeOverRecurse(precondsp, bodySize/*ref*/, bodyLimit)
|| bodySizeOverRecurse(bodysp, bodySize/*ref*/, bodyLimit)
|| bodySizeOverRecurse(incp, bodySize/*ref*/, bodyLimit)) {
return cantUnroll(nodep, "too many statements");
}
}
//
// Now, make sure there's no assignment to this variable in the loop
@@ -349,7 +360,7 @@ private:
nodep->incsp(), nodep->bodysp())) {
pushDeletep(nodep); nodep=NULL; // Did replacement
} 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");
}
}
}
+3 -2
View File
@@ -990,8 +990,9 @@ private:
lastloop = true; // so exit early; next loop will correct it
}
else if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::STRING
&& !pinp->castCvtPackString()
&& !(pinp->castVarRef() && pinp->castVarRef()->varp()->basicp()->keyword()==AstBasicDTypeKwd::STRING)) {
&& !pinp->castCvtPackString()
&& !pinp->castSFormatF() // Already generates a string
&& !(pinp->castVarRef() && pinp->castVarRef()->varp()->basicp()->keyword()==AstBasicDTypeKwd::STRING)) {
UINFO(4," Add CvtPackString: "<<pinp<<endl);
AstNRelinker handle;
pinp->unlinkFrBack(&handle); // No next, that's the next pin
+1 -1
View File
@@ -25,7 +25,7 @@
//**********************************************************************
//**** Version and host name
#define DTVERSION "Verilator 3.801 2010/03/17"
#define DTVERSION "Verilator 3.804 2010/07/10"
//**********************************************************************
//**** Functions
+10 -3
View File
@@ -42,7 +42,7 @@ extern void yyerrorf(const char* format, ...);
//======================================================================
#define NEXTLINE() {PARSEP->incLineno();}
#define NEXTLINE() {PARSEP->linenoInc();}
#define CRELINE() (PARSEP->copyOrSameFileLine())
#define FL { yylval.fl = CRELINE(); }
@@ -53,7 +53,8 @@ extern void yyerrorf(const char* format, ...);
void V3ParseImp::ppline (const char* textp) {
// Handle `line directive
fileline()->lineDirective(textp);
int enterExit;
fileline()->lineDirective(textp, enterExit/*ref*/);
}
void V3ParseImp::verilatorCmtLint(const char* textp, bool warnOff) {
@@ -144,6 +145,7 @@ crnl [\r]*[\n]
id [a-zA-Z_][a-zA-Z0-9_$]*
/* escaped identifier */
escid \\[^ \t\f\r\n]+
word [a-zA-Z0-9_]+
%%
@@ -632,6 +634,8 @@ escid \\[^ \t\f\r\n]+
"/*verilator parallel_case*/" { FL; return yVL_PARALLEL_CASE; }
"/*verilator public*/" { FL; return yVL_PUBLIC; }
"/*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 sc_clock*/" { FL; return yVL_CLOCK; }
"/*verilator sformat*/" { FL; return yVL_SFORMAT; }
@@ -645,7 +649,8 @@ escid \\[^ \t\f\r\n]+
"/*verilator lint_restore*/" {PARSEP->verilatorCmtLintRestore(); }
"/*verilator lint_save*/" {PARSEP->verilatorCmtLintSave(); }
"/*"[^*]*"*/" {PARSEP->verilatorCmtBad(yytext); }
"/**/" { }
"/*"[^*]+"*/" {PARSEP->verilatorCmtBad(yytext); }
}
/************************************************************************/
@@ -829,12 +834,14 @@ escid \\[^ \t\f\r\n]+
<STRING>\" { yy_pop_state();
FL; yylval.strp = PARSEP->newString(yytext+1,yyleng-2);
return yaSTRING; }
<STRING>{word} { yymore(); }
<STRING>. { yymore(); }
/************************************************************************/
/* Attributes */
<ATTRMODE>{crnl} { yymore(); NEXTLINE(); }
<ATTRMODE>"*)" { yy_pop_state(); }
<ATTRMODE>{word} { yymore(); }
<ATTRMODE>. { yymore(); }
<ATTRMODE><<EOF>> { yyerrorf("EOF in (*");
yyleng = 0; yy_pop_state(); }
+41 -27
View File
@@ -84,7 +84,7 @@ public:
}
// 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);
AstNode* createSupplyExpr(FileLine* fileline, string name, int value);
AstText* createTextQuoted(FileLine* fileline, string text) {
@@ -113,7 +113,7 @@ public:
}
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 (!rangesp) {
return dtypep;
@@ -134,7 +134,7 @@ public:
dtypep->rangep(finalp);
dtypep->implicit(false);
}
return createArray(dtypep, rangearraysp);
return createArray(dtypep, rangearraysp, isPacked);
}
}
string deQuote(FileLine* fileline, string text);
@@ -434,6 +434,8 @@ class AstSenTree;
%token<fl> yVL_PARALLEL_CASE "/*verilator parallel_case*/"
%token<fl> yVL_PUBLIC "/*verilator public*/"
%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> yP_TICK "'"
@@ -817,7 +819,7 @@ port<nodep>: // ==IEEE: port
| portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE
{ $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); }
| 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
{ $$=$2; /*VARDTYPE-same*/ $$->addNextNull(VARDONEP($$,$3,$4)); }
//
@@ -1029,7 +1031,7 @@ port_declaration<nodep>: // ==IEEE: port_declaration
list_of_variable_decl_assignments { $$ = $6; }
| port_directionReset port_declNetE yVAR implicit_typeE { VARDTYPE($4); }
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; }
| port_directionReset port_declNetE signing { VARDTYPE(new AstBasicDType($<fl>3, LOGIC_IMPLICIT, $3)); }
list_of_variable_decl_assignments { $$ = $5; }
@@ -1079,7 +1081,7 @@ data_type<dtypep>: // ==IEEE: data_type
// // This expansion also replicated elsewhere, IE data_type__AndID
data_typeNoRef { $$ = $1; }
// // 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 }
// // IEEE: class_type
//UNSUP class_typeWithoutId { $$ = $1; }
@@ -1088,7 +1090,7 @@ data_type<dtypep>: // ==IEEE: 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; }
//UNSUP non_integer_type { UNSUP }
;
@@ -1190,12 +1192,12 @@ enum_base_typeE<dtypep>: // IEEE: enum_base_type
/* empty */ { $$ = new AstBasicDType(CRELINE(),AstBasicDTypeKwd::INT); }
// // Not in spec, but obviously "enum [1:0]" should work
// // 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); }
//
| integer_atom_type signingE { $1->setSignedState($2); $$ = $1; }
| integer_vector_type signingE rangeListE { $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3); }
| yaID__aTYPE rangeListE { $$ = GRAMMARP->createArray(new AstRefDType($<fl>1, *$1), $2); }
| integer_vector_type signingE rangeListE { $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3,false); }
| yaID__aTYPE rangeListE { $$ = GRAMMARP->createArray(new AstRefDType($<fl>1, *$1), $2, false); }
;
enum_nameList<nodep>:
@@ -1244,7 +1246,7 @@ data_declarationVarFront: // IEEE: part of data_declaration
// // implicit_type expanded into /*empty*/ or "signingE rangeList"
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 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"
| /**/ data_type { /*VARRESET-in-ddVar*/ VARDTYPE($1); }
@@ -1261,13 +1263,13 @@ constE: // IEEE: part of data_declaration
implicit_typeE<dtypep>: // IEEE: part of *data_type_or_implicit
// // Also expanded in data_declaration
/* 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); }
;
type_declaration<nodep>: // ==IEEE: type_declaration
// // 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
// // 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
@@ -1541,6 +1543,10 @@ sigAttr<nodep>:
| yVL_CLOCK_ENABLE { $$ = new AstAttrOf($1,AstAttrType::VAR_CLOCK_ENABLE); }
| yVL_PUBLIC { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC); }
| 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_SFORMAT { $$ = new AstAttrOf($1,AstAttrType::VAR_SFORMAT); }
;
@@ -1557,7 +1563,7 @@ rangeList<rangep>: // IEEE: {packed_dimension}
wirerangeE<dtypep>:
/* 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
@@ -1665,13 +1671,18 @@ cellpinItemE<pinp>: // IEEE: named_port_connection + named_parameter_assignment
| '.' idSVKwd { $$ = NULL; PINNUMINC(); }
| '.' idAny { $$ = new AstPin($1,PINNUMINC(),*$2,new AstVarRef($1,*$2,false)); $$->svImplicit(true);}
| '.' idAny '(' ')' { $$ = NULL; PINNUMINC(); }
// // mintypmax is expanded here, as it might be a UDP or gate primitive
| '.' idAny '(' expr ')' { $$ = new AstPin($1,PINNUMINC(),*$2,$4); }
//UNSUP '.' idAny '(' expr ':' expr ')' { }
//UNSUP '.' idAny '(' expr ':' expr ':' expr ')' { }
// // For parameters
//UNSUP '.' idAny '(' data_type ')' { PINDONE($1,$2,$4); GRAMMARP->pinNumInc(); }
// // For parameters
//UNSUP data_type { PINDONE($1->fileline(),"",$1); GRAMMARP->pinNumInc(); }
//
| 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
| yaFLOATNUM { $$ = new AstPin($<fl>1,PINNUMINC(),"",new AstConst($<fl>1,AstConst::Unsized32(),(int)(($1<0)?($1-0.5):($1+0.5)))); }
;
@@ -1679,6 +1690,12 @@ cellpinItemE<pinp>: // IEEE: named_port_connection + named_parameter_assignment
//************************************************
// EventControl lists
attr_event_control<sentreep>: // ==IEEE: event_control
'@' '(' event_expression ')' { $$ = new AstSenTree($1,$3); }
| '@' '(' '*' ')' { $$ = NULL; }
| '@' '*' { $$ = NULL; }
;
event_controlE<sentreep>:
/* empty */ { $$ = NULL; }
| event_control { $$ = $1; }
@@ -1847,7 +1864,7 @@ statement_item<nodep>: // IEEE: statement_item
// // for's first ';' is in for_initalization
| yFOR '(' for_initialization expr ';' for_stepE ')' stmtBlock
{ $$ = 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 }
//
// // IEEE: jump_statement
@@ -2145,7 +2162,7 @@ funcId<ftaskp>: // IEEE: function_data_type_or_implicit + part of function_bod
SYMP->pushNewUnder($$, NULL); }
| signingE rangeList tfIdScoped
{ $$ = 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); }
| signing tfIdScoped
{ $$ = new AstFunc ($<fl>2,*$<strp>2,NULL,
@@ -2215,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
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)); }
| yVAR data_type { VARDTYPE($2); }
| yVAR implicit_typeE { VARDTYPE($2); }
//
| tf_port_itemDir /*implicit*/ { VARDTYPE(NULL); /*default_nettype-see spec*/ }
| 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 yVAR data_type { VARDTYPE($3); }
| tf_port_itemDir yVAR implicit_typeE { VARDTYPE($3); }
@@ -2891,16 +2908,13 @@ concurrent_assertion_statement<nodep>: // ==IEEE: concurrent_assertion_statement
property_spec<nodep>: // IEEE: property_spec
//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); }
| 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); }
;
property_specDisable<nodep>: // IEEE: part of property_spec
yDISABLE yIFF '(' expr ')' { $$ = $4; }
;
immediate_assert_statement<nodep>: // ==IEEE: immediate_assert_statement
// // action_block expanded here, for compatibility with AstVAssert
yASSERT '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE { $$ = new AstVAssert($1,$3,$5, GRAMMARP->createDisplayError($1)); }
@@ -3054,7 +3068,7 @@ AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, string name, int v
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)
AstNodeDType* arrayp = basep;
if (rangep) { // Maybe no range - return unmodified base type
@@ -3062,7 +3076,7 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstRange* rangep)
while (rangep) {
AstRange* prevp = rangep->backp()->castRange();
if (prevp) rangep->unlinkFrBack();
arrayp = new AstArrayDType(rangep->fileline(), arrayp, rangep);
arrayp = new AstArrayDType(rangep->fileline(), arrayp, rangep, isPacked);
rangep = prevp;
}
}
@@ -3094,7 +3108,7 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, string name, AstRange
}
// 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);
nodep->addAttrsp(attrsp);
+39 -3
View File
@@ -40,6 +40,7 @@ our @Orig_ARGV = @ARGV;
our @Orig_ARGV_Sw; foreach (@Orig_ARGV) { push @Orig_ARGV_Sw, $_ if /^-/ && !/^-j/; }
$Debug = 0;
my $opt_atsim;
my $opt_benchmark;
my @opt_tests;
my $opt_gdb;
@@ -61,6 +62,7 @@ Getopt::Long::config ("pass_through");
if (! GetOptions (
"benchmark:i" => sub { $opt_benchmark = $_[1] ? $_[1] : 1; },
"debug" => \&debug,
"atsim|athdl!"=> \$opt_atsim,
"gdb!" => \$opt_gdb,
"gdbbt!" => \$opt_gdbbt,
"gdbsim!" => \$opt_gdbsim,
@@ -86,7 +88,7 @@ $opt_jobs = calc_jobs() if defined $opt_jobs && $opt_jobs==0;
$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;
}
@@ -101,6 +103,7 @@ my $leftcnt=0; my $okcnt=0; my $failcnt=0; my $skcnt=0;
my @fails;
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, nc=>1) if $opt_nc;
one_test(pl_filename => $testpl, vcs=>1) if $opt_vcs;
@@ -261,6 +264,12 @@ sub new {
v_flags2 => [], # Overridden in some sim files
v_other_filenames => [], # After the filename so we can spec multiple files
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 => 0,
iv_flags => [split(/\s+/,"+define+iverilog -o $self->{obj_dir}/simiv")],
@@ -288,6 +297,7 @@ sub new {
%$self};
bless $self, $class;
$self->{mode} ||= "atsim" if $self->{atsim};
$self->{mode} ||= "vcs" if $self->{vcs};
$self->{mode} ||= "vlt" if $self->{vlt};
$self->{mode} ||= "nc" if $self->{nc};
@@ -387,6 +397,20 @@ sub compile {
$self->{trace} = 1 if ($opt_trace || $checkflags =~ /-trace\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}) {
$self->_make_top();
$self->_run(logfile=>"$self->{obj_dir}/vcs_compile.log",
@@ -511,6 +535,14 @@ sub execute {
my $run_env = $param{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}) {
$self->_run(logfile=>"$self->{obj_dir}/iv_sim.log",
fails=>$param{fails},
@@ -522,7 +554,7 @@ sub execute {
if ($param{nc}) {
$self->_run(logfile=>"$self->{obj_dir}/nc_sim.log",
fails=>$param{fails},
cmd=>[$run_env.($ENV{VERILATOR_NCVERILOG}||"ncverilog"),
cmd=>["echo q | ".$run_env.($ENV{VERILATOR_NCVERILOG}||"ncverilog"),
@{$param{ncrun_flags}},
@{$param{all_run_flags}},
]);
@@ -531,7 +563,7 @@ sub execute {
#my $fh = IO::File->new(">simv.key") or die "%Error: $! simv.key,";
#$fh->print("quit\n"); $fh->close;
$self->_run(logfile=>"$self->{obj_dir}/vcs_sim.log",
cmd=>[$run_env."./simv",
cmd=>["echo q | ".$run_env."./simv",
@{$param{all_run_flags}},
],
%param,
@@ -1166,6 +1198,10 @@ driver.pl invokes Verilator or another simulator on each little test file.
=over 4
=item --atsim
Run using ATSIM.
=item --benchmark [<cycles>]
Show execution times of each step. If an optional number is given,
+1 -1
View File
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Version 2.0.
compile (
v_flags2 => ["--stats"],
verilator_flags2 => ["--stats"],
);
if ($Self->{v3}) {
+1 -1
View File
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Version 2.0.
compile (
v_flags2 => ["--stats"],
verilator_flags2 => ["--stats"],
);
if ($Self->{v3}) {
+1 -1
View File
@@ -16,7 +16,7 @@ compile (
);
execute (
fails => 1,
fails => $Self->{vlt},
);
ok(1);
+1 -1
View File
@@ -16,7 +16,7 @@ compile (
execute (
check_finished=>0,
fails=>1,
fails=> $Self->{vlt},
expect=>
'%Error: t_assert_synth.v:\d+: Assertion failed in top.v: synthesis full_case'
);
+1 -1
View File
@@ -16,7 +16,7 @@ compile (
execute (
check_finished=>0,
fails=>1,
fails => $Self->{v3},
expect=>
'%Error: t_assert_synth.v:\d+: Assertion failed in top.v: synthesis parallel_case'
);
+1 -1
View File
@@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
$Self->{golden_out} ||= "t/$Self->{name}.out";
compile (
v_flags2 => [$Self->{v3}?"--stats --O3 -x-assign fast":""],
verilator_flags2 => ["--stats --O3 -x-assign fast"],
);
execute (
+1 -1
View File
@@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
$Self->{golden_out} ||= "t/$Self->{name}.out";
compile (
v_flags2 => [$Self->{v3}?"--stats --O3 -x-assign fast":""],
verilator_flags2 => ["--stats --O3 -x-assign fast"],
);
execute (
+1 -1
View File
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Version 2.0.
compile (
v_flags2 => ["--x-assign 0"],
verilator_flags2 => ["--x-assign 0"],
);
execute (
+53
View File
@@ -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);
}
+20
View File
@@ -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;
+70
View File
@@ -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
+22
View File
@@ -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;
+1 -1
View File
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Version 2.0.
compile (
v_flags2 => ["--stats"],
verilator_flags2 => ["--stats"],
);
execute (
+1 -1
View File
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Version 2.0.
compile (
verilator_flags2 => [$Self->{v3}?'--sp --coverage-line':''],
verilator_flags2 => ['--sp --coverage-line'],
);
execute (
+4
View File
@@ -48,7 +48,11 @@ module t (/*AUTOARG*/
toggle <= '1;
end
else if (cyc==5) begin
`ifdef VERILATOR
$c("call_task();");
`else
call_task();
`endif
end
else if (cyc==10) begin
$write("*-* All Finished *-*\n");
+3 -2
View File
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Version 2.0.
compile (
v_flags2 => [$Self->{v3}?'--assert --sp --coverage-user':''],
verilator_flags2 => ['--assert --sp --coverage-user'],
);
execute (
@@ -20,7 +20,8 @@ execute (
# Allow old Perl format dump, or new binary dump
# Check that the hierarchy doesn't include __PVT__
# 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);
1;
+3 -2
View File
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Version 2.0.
compile (
verilator_flags2 => [$Self->{v3}?'--sp --coverage-toggle --stats':''],
verilator_flags2 => ['--sp --coverage-toggle --stats'],
);
execute (
@@ -18,7 +18,8 @@ execute (
# Read the input .v file and do any CHECK_COVER requests
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);
1;
+21
View File
@@ -0,0 +1,21 @@
#!/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.
$Self->{vlt} or $Self->skip("Verilator only test");
compile (
v_flags2 => ["--debug-core-dump"],
fails=>$Self->{v3},
expect=>
'%Error: Verilator internal fault, sorry. Consider trying --debug --gdbbt
%Error: Command Failed.*',
);
ok(1);
1;
+1
View File
@@ -22,6 +22,7 @@ if (!-r "$root/.git") {
my $cmd = "cd $root && fgrep -n include $files | sort";
my $grep = `$cmd`;
foreach my $line (split /\n/, $grep) {
next if $line =~ /vpi_user.h/; # IEEE Standard file - can't change it
my $hit;
$hit = 1 if $line =~ /\bassert\.h/;
$hit = 1 if $line =~ /\bctype\.h/;
+1 -1
View File
@@ -14,7 +14,7 @@
//*************************************************************************
#include <cstdio>
#include <svdpi.h>
#include "svdpi.h"
//======================================================================
+1 -1
View File
@@ -14,7 +14,7 @@
//*************************************************************************
#include <cstdio>
#include <svdpi.h>
#include "svdpi.h"
//======================================================================
+1 -1
View File
@@ -14,8 +14,8 @@
//*************************************************************************
#include <cstdio>
#include <svdpi.h>
#include <cstring>
#include "svdpi.h"
#ifdef _WIN32
# define T_PRI64 "I64"
+1 -1
View File
@@ -15,7 +15,7 @@
#include <cstdio>
#include <cstring>
#include <svdpi.h>
#include "svdpi.h"
//======================================================================
+1 -1
View File
@@ -14,7 +14,7 @@
//*************************************************************************
#include <cstdio>
#include <svdpi.h>
#include "svdpi.h"
//======================================================================
+147
View File
@@ -0,0 +1,147 @@
// -*- C++ -*-
//*************************************************************************
//
// Copyright 2010-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.
//
//*************************************************************************
#include "Vt_dpi_var.h"
#include "verilated.h"
#include "svdpi.h"
#include "verilated_syms.h"
//======================================================================
struct MyMon {
vluint32_t* sigsp[2];
MyMon() { sigsp[0]=NULL; sigsp[1]=NULL; }
};
MyMon mons[2];
void mon_register_a(const char* namep, void* sigp, bool isOut) {
// Callback from initial block in monitor
#ifdef TEST_VERBOSE
VL_PRINTF("- mon_register_a(\"%s\", %p, %d);\n", namep, sigp, isOut);
#endif
mons[0].sigsp[isOut] = (vluint32_t*)sigp;
}
void mon_do(MyMon* monp) {
if (!monp->sigsp[0]) vl_fatal(__FILE__,__LINE__,"","never registered");
if (!monp->sigsp[1]) vl_fatal(__FILE__,__LINE__,"","never registered");
*monp->sigsp[1] = (*(monp->sigsp[0]))+1;
#ifdef TEST_VERBOSE
VL_PRINTF("- mon_do(%08x(&%p) -> %08x(&%p));\n",
*(monp->sigsp[0]), monp->sigsp[0], *(monp->sigsp[1]), monp->sigsp[1]);
#endif
}
void mon_class_name(const char* namep) {
#ifdef TEST_VERBOSE
VL_PRINTF("- mon_class_name(\"%s\");\n", namep);
#endif
// Check the C's calling name of "" doesn't lead to extra dots in the name()
if (namep && namep[0]=='.') vl_fatal(__FILE__,__LINE__,"", (string("Unexp class name ")+namep).c_str());
}
extern "C" void mon_scope_name(const char* namep);
void mon_scope_name(const char* namep) {
const char* modp = svGetNameFromScope(svGetScope());
#ifdef TEST_VERBOSE
VL_PRINTF("- mon_scope_name('%s', \"%s\");\n", modp, namep);
#endif
if (strcmp(namep,"t.sub")) vl_fatal(__FILE__,__LINE__,"", (string("Unexp scope name ")+namep).c_str());
if (strcmp(modp,"t.sub")) vl_fatal(__FILE__,__LINE__,"", (string("Unexp dpiscope name ")+modp).c_str());
}
extern "C" void mon_register_b(const char* namep, int isOut);
void mon_register_b(const char* namep, int isOut) {
const char* modp = svGetNameFromScope(svGetScope());
#ifdef TEST_VERBOSE
VL_PRINTF("- mon_register_b('%s', \"%s\", %d);\n", modp, namep, isOut);
#endif
// Use scope to get pointer and size of signal
const VerilatedScope* scopep = Verilated::dpiScope();
const VerilatedVar* varp = scopep->varFind(namep);
if (!varp) {
VL_PRINTF("%%Warning: mon_register_b signal not found: \"%s\"\n", namep);
} else if (varp->vltype() != VLVT_UINT32) {
VL_PRINTF("%%Warning: wrong type for signal: \"%s\"\n", namep);
} else {
vluint32_t* datap = (vluint32_t*)(varp->datap());
VL_PRINTF("- mon_register_b('%s', \"%s\", %p, %d);\n", modp, namep, datap, isOut);
mons[1].sigsp[isOut] = (vluint32_t*)(varp->datap());
}
}
extern "C" void mon_register_done();
void mon_register_done() {
const char* modp = svGetNameFromScope(svGetScope());
#ifdef TEST_VERBOSE
VL_PRINTF("- mon_register_done('%s');\n", modp);
#endif
// Print list of all signals - if we didn't register2 anything we'd pick them off here
const VerilatedScope* scopep = Verilated::dpiScope();
if (VerilatedVarNameMap* varsp = scopep->varsp()) {
for (VerilatedVarNameMap::const_iterator it = varsp->begin();
it != varsp->end(); ++it) {
VL_PRINTF("- mon2: %s\n", it->first);
}
}
}
extern "C" void mon_eval();
void mon_eval() {
// Callback from always@ negedge
mon_do(&mons[0]);
mon_do(&mons[1]);
}
//======================================================================
unsigned int main_time = false;
double sc_time_stamp () {
return main_time;
}
int main(int argc, char **argv, char **env) {
double sim_time = 1100;
Verilated::commandArgs(argc, argv);
Verilated::debug(0);
VM_PREFIX* topp = new VM_PREFIX (""); // Note null name - we're flattening it out
#ifdef VERILATOR
# ifdef TEST_VERBOSE
Verilated::scopesDump();
# endif
#endif
topp->eval();
topp->clk = 0;
main_time += 10;
while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) {
main_time += 1;
topp->eval();
topp->clk = !topp->clk;
//mon_do();
}
if (!Verilated::gotFinish()) {
vl_fatal(__FILE__,__LINE__,"main", "%Error: Timeout; never got a $finish");
}
topp->final();
delete topp; topp=NULL;
exit(0L);
}
+21
View File
@@ -0,0 +1,21 @@
#!/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,
verilator_flags2 => ["--exe --no-l2name $Self->{t_dir}/t_dpi_var.cpp"],
);
execute (
check_finished=>1,
);
ok(1);
1;
+91
View File
@@ -0,0 +1,91 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// 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.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=0;
wire monclk = ~clk;
int in;
int fr_a;
int fr_b;
int fr_chk;
sub sub (.*);
// Test loop
always @ (posedge clk) begin
`ifdef TEST_VERBOSE
$write("[%0t] cyc==%0d in=%x fr_a=%x b=%x fr_chk=%x\n",$time, cyc, in, fr_a, fr_b, fr_chk);
`endif
cyc <= cyc + 1;
in <= {in[30:0], in[31]^in[2]^in[0]};
if (cyc==0) begin
// Setup
in <= 32'hd70a4497;
end
else if (cyc<3) begin
end
else if (cyc<10) begin
if (fr_chk != fr_a) $stop;
if (fr_chk != fr_b) $stop;
end
else if (cyc==10) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
always @(posedge t.monclk) begin
mon_eval();
end
endmodule
import "DPI-C" context function void mon_scope_name (input string formatted /*verilator sformat*/ );
import "DPI-C" context function void mon_register_b(string name, int isOut);
import "DPI-C" context function void mon_register_done();
import "DPI-C" context function void mon_eval();
module sub (/*AUTOARG*/
// Outputs
fr_a, fr_b, fr_chk,
// Inputs
in
);
`systemc_imp_header
void mon_class_name(const char* namep);
void mon_register_a(const char* namep, void* sigp, bool isOut);
`verilog
input int in /*verilator public_flat_rd*/;
output int fr_a /*verilator public_flat_rw @(posedge t.monclk)*/;
output int fr_b /*verilator public_flat_rw @(posedge t.monclk)*/;
output int fr_chk;
always @* fr_chk = in + 1;
initial begin
// Test the naming
$c("mon_class_name(name());");
mon_scope_name("%m");
// Scheme A - pass pointer directly
$c("mon_register_a(\"in\",&",in,",false);");
$c("mon_register_a(\"fr_a\",&",fr_a,",true);");
// Scheme B - use VPIish callbacks to see what signals exist
mon_register_b("in", 0);
mon_register_b("fr_b", 1);
mon_register_done();
end
endmodule
+2
View File
@@ -7,6 +7,8 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$Self->{vlt} or $Self->skip("Verilator only test");
$Self->_run (cmd=>["cd $Self->{obj_dir}"
." && g++ -c ../../t/t_flag_ldflags_a.cpp"
." && ar r t_flag_ldflags_a.a t_flag_ldflags_a.o"
+1 -1
View File
@@ -14,7 +14,7 @@
//*************************************************************************
#include <cstdio>
#include <svdpi.h>
#include "svdpi.h"
//======================================================================
+1 -1
View File
@@ -12,7 +12,7 @@ module t (
chk chk (.clk (clk),
.rst_l (1'b1),
.expr (|crc),
.expr (|crc)
);
always @ (posedge clk) begin
+1 -1
View File
@@ -3,7 +3,7 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2003 by Wilson Snyder.
module t_task (/*AUTOARG*/
module t (/*AUTOARG*/
// Inputs
clk
);
+4
View File
@@ -37,10 +37,14 @@ module t (clk);
if ( cyc >= 4 ) begin
dindex = dindex + 2; //*** Error line
$display("%m: DIndex increment %d", cyc);
`ifdef VERILATOR
$c("VL_PRINTF(\"Hello1?\\n\");");
`endif
end
`ifdef VERILATOR
$c("VL_PRINTF(\"Hello2?\\n\");");
$c("VL_PRINTF(\"Hello3?\\n\");");
`endif
end
end
endtask
+1 -1
View File
@@ -3,7 +3,7 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2003 by Wilson Snyder.
module t_func (/*AUTOARG*/
module t (/*AUTOARG*/
// Inputs
clk
);
+2
View File
@@ -7,6 +7,8 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$Self->{vlt} or $Self->skip("Verilator only test");
compile (
);
# No execute
+1 -1
View File
@@ -12,7 +12,7 @@ my $pubtask = ($Self->{v3} && verilator_version() =~ /\(public_tasks\)/); # TBD
top_filename("t/t_func_public.v");
compile (
v_flags2 => [($pubtask?'-DVERILATOR_PUBLIC_TASKS':''), "--trace"],
verilator_flags2 => [($pubtask?'-DVERILATOR_PUBLIC_TASKS':''), "--trace"],
fails => $fail,
);
+3 -1
View File
@@ -7,12 +7,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$Self->{vlt} or $Self->skip("Verilator only test");
$Self->_run(fails=>1,
cmd=>["perl","../bin/verilator",
"--help"],
logfile=>"$Self->{obj_dir}/t_help.log",
tee=>0,
) if $Self->{v3};
);
file_grep ("$Self->{obj_dir}/t_help.log", qr/DISTRIBUTION/i);
+2 -2
View File
@@ -3,14 +3,14 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2003 by Wilson Snyder.
module t_initial (/*AUTOARG*/
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
reg _ranit;
`include "t_initial_inc.v"
`include "t_initial_inc.vh"
// surefire lint_off STMINI
initial assign user_loaded_value = 1;
+1 -1
View File
@@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
top_filename("t/t_inst_tree.v");
compile (
v_flags2 => ['+define+NOUSE_INLINE', '+define+USE_PUBLIC', '--stats'],
verilator_flags2 => ['+define+NOUSE_INLINE', '+define+USE_PUBLIC', '--stats'],
);
if ($Self->{v3}) {

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