mirror of
https://github.com/verilator/verilator.git
synced 2026-10-06 01:54:01 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ef44a6fbb | ||
|
|
2afe40a0b5 | ||
|
|
e57d004718 | ||
|
|
d780d0aabb | ||
|
|
0f9e3f0767 | ||
|
|
381972c923 | ||
|
|
845d7ad718 | ||
|
|
f1b6c0c559 | ||
|
|
e39eddf3fe | ||
|
|
72218fb475 | ||
|
|
9a3e497c22 | ||
|
|
85d510cd48 | ||
|
|
786c65ea5f | ||
|
|
10e6f61125 | ||
|
|
cdd06e7236 | ||
|
|
48603c0ee2 | ||
|
|
63f30492be | ||
|
|
0e8772290d | ||
|
|
6cfc5798b0 | ||
|
|
6be275f5d4 |
@@ -3,6 +3,24 @@ Revision history for Verilator
|
|||||||
The contributors that suggested a given feature are shown in []. [by ...]
|
The contributors that suggested a given feature are shown in []. [by ...]
|
||||||
indicates the contributor was also the author of the fix; Thanks!
|
indicates the contributor was also the author of the fix; Thanks!
|
||||||
|
|
||||||
|
* Verilator 3.801 2010/03/17
|
||||||
|
|
||||||
|
*** Support "break", "continue", "return".
|
||||||
|
|
||||||
|
*** Support "`default_nettype none|wire". [Dominic Plunkett]
|
||||||
|
|
||||||
|
**** Skip SystemC tests if not installed. [Iztok Jeras]
|
||||||
|
|
||||||
|
**** Fix clock-gates with non-AND complex logic, bug220. [Ashutosh Das]
|
||||||
|
|
||||||
|
**** Fix flushing VCD buffers on $stop. [Ashutosh Das]
|
||||||
|
|
||||||
|
**** Fix Mac OS-X compile issues, bug217. [Joshua Wise, Trevor Williams]
|
||||||
|
|
||||||
|
**** Fix make uninstall, bug216. [Iztok Jeras]
|
||||||
|
|
||||||
|
**** Fix parametrized defines with empty arguments.
|
||||||
|
|
||||||
* Verilator 3.800 2010/02/07
|
* Verilator 3.800 2010/02/07
|
||||||
|
|
||||||
Application visible changes:
|
Application visible changes:
|
||||||
|
|||||||
+49
-29
@@ -145,8 +145,6 @@ INST_PROJ_BIN_FILES = \
|
|||||||
|
|
||||||
DISTFILES := $(DISTFILES_INC)
|
DISTFILES := $(DISTFILES_INC)
|
||||||
|
|
||||||
VL_INST_MAN_FILES = verilator.1
|
|
||||||
|
|
||||||
ifeq ($(OBJCACHE_JOBS),)
|
ifeq ($(OBJCACHE_JOBS),)
|
||||||
ifneq ($(OBJCACHE_HOSTS),)
|
ifneq ($(OBJCACHE_HOSTS),)
|
||||||
export OBJCACHE_JOBS := -j $(shell objcache --jobs "$(OBJCACHE_HOSTS)")
|
export OBJCACHE_JOBS := -j $(shell objcache --jobs "$(OBJCACHE_HOSTS)")
|
||||||
@@ -238,11 +236,25 @@ internals.txt: internals.pod
|
|||||||
-rm -f $@
|
-rm -f $@
|
||||||
$(POD2TEXT) --loose $< > $@
|
$(POD2TEXT) --loose $< > $@
|
||||||
|
|
||||||
# See uninstall also
|
# See uninstall also - don't put wildcards in this variable, it might uninstall other stuff
|
||||||
VL_INST_BIN_FILES = verilator verilator_bin verilator_bin_dbg \
|
VL_INST_BIN_FILES = verilator verilator_bin verilator_bin_dbg \
|
||||||
verilator_includer verilator_profcfunc
|
verilator_includer verilator_profcfunc
|
||||||
# Some scripts go into both the search path and pkgdatadir,
|
# Some scripts go into both the search path and pkgdatadir,
|
||||||
# so they can be found by the user, and under $VERILATOR_ROOT.
|
# so they can be found by the user, and under $VERILATOR_ROOT.
|
||||||
|
|
||||||
|
# See uninstall also - don't put wildcards in this variable, it might uninstall other stuff
|
||||||
|
VL_INST_MAN_FILES = verilator.1
|
||||||
|
|
||||||
|
VL_INST_INC_FILES = \
|
||||||
|
include/*.[chv]* include/verilated.mk \
|
||||||
|
include/vltstd/*.[chv]* \
|
||||||
|
|
||||||
|
VL_INST_DATA_FILES = \
|
||||||
|
test_v/*.[chv]* \
|
||||||
|
test_c/*.[chv]* test_c/Makefile test_c/Makefile_obj \
|
||||||
|
test_sc/*.[chv]* test_sc/Makefile test_sc/Makefile_obj \
|
||||||
|
test_sp/*.[chv]* test_sp/Makefile test_sp/Makefile_obj \
|
||||||
|
|
||||||
installbin:
|
installbin:
|
||||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(bindir)
|
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(bindir)
|
||||||
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator $(DESTDIR)$(bindir)/verilator )
|
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator $(DESTDIR)$(bindir)/verilator )
|
||||||
@@ -259,16 +271,35 @@ installman: $(VL_INST_MAN_FILES)
|
|||||||
done
|
done
|
||||||
|
|
||||||
installdata:
|
installdata:
|
||||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/include/vltstd $(DESTDIR)$(pkgdatadir)/examples
|
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/include/vltstd
|
||||||
cp -r include/*.* $(DESTDIR)$(pkgdatadir)/include
|
for p in $(VL_INST_INC_FILES) ; do \
|
||||||
cp -r ${srcdir}/include/*.* $(DESTDIR)$(pkgdatadir)/include
|
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkgdatadir)/$$p; \
|
||||||
cp -r ${srcdir}/include/vltstd/*.* $(DESTDIR)$(pkgdatadir)/include/vltstd
|
done
|
||||||
cp -r ${srcdir}/test_c $(DESTDIR)$(pkgdatadir)/examples
|
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_c
|
||||||
cp -r ${srcdir}/test_sc $(DESTDIR)$(pkgdatadir)/examples
|
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_sc
|
||||||
cp -r ${srcdir}/test_sp $(DESTDIR)$(pkgdatadir)/examples
|
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_sp
|
||||||
cp -r ${srcdir}/test_v $(DESTDIR)$(pkgdatadir)/examples
|
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_v
|
||||||
|
for p in $(VL_INST_DATA_FILES) ; do \
|
||||||
|
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkgdatadir)/examples/$$p; \
|
||||||
|
done
|
||||||
|
|
||||||
|
# We don't trust rm -rf, so rmdir instead as it will fail if user put in other files
|
||||||
|
uninstall:
|
||||||
|
-cd $(DESTDIR)$(bindir) && rm -f $(VL_INST_BIN_FILES)
|
||||||
|
-cd $(DESTDIR)$(pkgdatadir)/bin && rm -f $(VL_INST_BIN_FILES)
|
||||||
|
-cd $(DESTDIR)$(mandir)/man1 && rm -f $(VL_INST_MAN_FILES)
|
||||||
|
-cd $(DESTDIR)$(pkgdatadir) && rm -f $(VL_INST_INC_FILES)
|
||||||
|
-cd $(DESTDIR)$(pkgdatadir)/examples && rm -f $(VL_INST_DATA_FILES)
|
||||||
|
-rmdir $(DESTDIR)$(pkgdatadir)/bin
|
||||||
|
-rmdir $(DESTDIR)$(pkgdatadir)/include/vltstd
|
||||||
|
-rmdir $(DESTDIR)$(pkgdatadir)/include
|
||||||
|
-rmdir $(DESTDIR)$(pkgdatadir)/examples/test_c
|
||||||
|
-rmdir $(DESTDIR)$(pkgdatadir)/examples/test_sc
|
||||||
|
-rmdir $(DESTDIR)$(pkgdatadir)/examples/test_sp
|
||||||
|
-rmdir $(DESTDIR)$(pkgdatadir)/examples/test_v
|
||||||
|
-rmdir $(DESTDIR)$(pkgdatadir)/examples
|
||||||
|
-rmdir $(DESTDIR)$(pkgdatadir)
|
||||||
|
|
||||||
VL_INST_DATA_FILES = verilator.1
|
|
||||||
install: all_nomsg installbin installman installdata install-msg
|
install: all_nomsg installbin installman installdata install-msg
|
||||||
|
|
||||||
install-here: installman ftp
|
install-here: installman ftp
|
||||||
@@ -313,26 +344,15 @@ install-msg:
|
|||||||
@echo "See 'verilator.txt' for documentation."
|
@echo "See 'verilator.txt' for documentation."
|
||||||
@echo
|
@echo
|
||||||
|
|
||||||
uninstall:
|
IN_WILD := ${srcdir}/*.in ${srcdir}/*/*.in
|
||||||
-cd $(DESTDIR)$(mandir)/man1 && rm -f $(VL_INST_MAN_FILES)
|
|
||||||
-cd $(DESTDIR)$(bindir) && rm -f $(VL_INST_BIN_FILES)
|
|
||||||
-rm -f $(DESTDIR)$(pkgdatadir)
|
|
||||||
|
|
||||||
# autoheader might not change config_build.h.in, so touch a stamp file.
|
# autoheader might not change config_build.h.in, so touch it
|
||||||
IN_WILD := ${srcdir}/*.in ${srcdir}/*/*.in ${srcdir}/*/*/*.in \
|
${srcdir}/config_build.h: ${srcdir}/config_build.h.in configure
|
||||||
*.in */*.in */*.in
|
|
||||||
|
|
||||||
${srcdir}/config_build.h.in: stamp-h.in
|
|
||||||
${srcdir}/stamp-h.in: configure.ac $(wildcard $(IN_WILD))
|
|
||||||
cd ${srcdir} && autoheader
|
cd ${srcdir} && autoheader
|
||||||
echo timestamp > ${srcdir}/stamp-h.in
|
touch $@
|
||||||
config_build.h: stamp-h
|
Makefile: Makefile.in config.status $(IN_WILD)
|
||||||
stamp-h: config_build.h.in config.status
|
|
||||||
./config.status
|
|
||||||
Makefile: Makefile.in config.status
|
|
||||||
./config.status
|
|
||||||
src/Makefile: src/Makefile.in config.status
|
|
||||||
./config.status
|
./config.status
|
||||||
|
src/Makefile: src/Makefile.in Makefile
|
||||||
config.status: configure
|
config.status: configure
|
||||||
./config.status --recheck
|
./config.status --recheck
|
||||||
configure: configure.ac
|
configure: configure.ac
|
||||||
|
|||||||
@@ -6,129 +6,134 @@
|
|||||||
// Version 2.0.
|
// Version 2.0.
|
||||||
|
|
||||||
|
|
||||||
Features:
|
Language support:
|
||||||
Latch optimizations {Need here}
|
* Fix ordering of each bit separately in a signal (mips)
|
||||||
Task I/Os connecting to non-simple variables.
|
|
||||||
Fix ordering of each bit separately in a signal (mips)
|
|
||||||
assign b[3:0] = b[7:4]; assign b[7:4] = in;
|
assign b[3:0] = b[7:4]; assign b[7:4] = in;
|
||||||
Support gate primitives/ cell libraries from xilinx, etc
|
* Support UDP gate primitives/ cell libraries
|
||||||
Assign dont_care value to an 1'bzzz assignment
|
(have code for combos - problem is sequential udps)
|
||||||
Function to eval combo logic after /*verilator public*/ functions [gwaters]
|
* Function to eval combo logic after /*verilator public*/ functions [gwaters]
|
||||||
Support generated clocks (correctness)
|
* Support generated clocks (correctness)
|
||||||
?gcov coverage
|
* Real numbers
|
||||||
Selectable SystemC types based on widths (see notes below)
|
* Recursive functions
|
||||||
Coverage
|
* Verilog configuration files
|
||||||
Points should be per-scope like everything else rather then per-module
|
* Structs/unions (have starting point)
|
||||||
Expression coverage (see notes)
|
* DPI to define C/C++ calls from Verilog
|
||||||
Constant functions for widths, etc, IE "input [log2(PARAM):0] xx;"
|
* Expression coverage (see notes)
|
||||||
More Verilog 2001 Support
|
* Better tristate support
|
||||||
(* *) Attributes (just ignore -- preprocessor?)
|
|
||||||
Real numbers (NEVER)
|
|
||||||
Recursive functions (NEVER)
|
|
||||||
Verilog configuration files (NEVER)
|
|
||||||
DPI to define C/C++ calls from Verilog
|
|
||||||
|
|
||||||
Long-term Features
|
Long-term Features
|
||||||
Assertions
|
* Assertions
|
||||||
VHDL parser [Philips]
|
* Tristate support
|
||||||
Tristate support
|
* Multithreaded execution
|
||||||
SystemPerl integration
|
|
||||||
Multithreaded execution
|
Configure/Make/Install
|
||||||
|
* Full MSVC++ compilation (does scons support this?) (4.000?)
|
||||||
|
* Distribute with flex/bison already expanded?
|
||||||
|
Flex library not needed. Probably too difficult to be worth it.
|
||||||
|
* Integrate SystemPerl coverage
|
||||||
|
(Note in /usr/include there are no upper cased include files.)
|
||||||
|
Coverage.pm -- Need all functionality, but in C?
|
||||||
|
Coverage/Item.pm -- Need all functionality, but in C?
|
||||||
|
Coverage/ItemKey.pm -- Need all functionality, but in C?
|
||||||
|
sp_preproc -- Some steps in here need to be moved to generated C
|
||||||
|
src/Sp.cpp -- n/a
|
||||||
|
src/SpCommon.h -- mostly overlaps verilatedos.h
|
||||||
|
src/SpCoverage.cpp/h -- All needed
|
||||||
|
src/SpFunctor.cpp/h -- No longer used
|
||||||
|
src/SpTraceVcd.cpp/h -- MOVED
|
||||||
|
src/SpTraceVcdC.cpp/h -- MOVED
|
||||||
|
src/sp_log.cpp/h -- Not needed
|
||||||
|
src/systemperl.h -- some stuff may be cut
|
||||||
|
vcoverage -- Need all functionality, but in C?
|
||||||
|
|
||||||
Testing:
|
Testing:
|
||||||
Capture all inputs into global "rerun it" file
|
* Move test_c/sp/v/verilated into test_regress format (4.000?)
|
||||||
Code to make wrapper that sets signals, so can do comparison checks
|
* Capture all inputs into global "rerun it" file
|
||||||
New random program generator
|
* Code to make wrapper that sets signals, so can do comparison checks
|
||||||
Better graph viewer with search and zoom
|
* New random program generator
|
||||||
Port and test against opencores.org code
|
* Better graph viewer with search and zoom
|
||||||
|
* Port and test against opencores.org code
|
||||||
|
|
||||||
Usability:
|
Usability:
|
||||||
Better reporting of unopt problems, including what lines of code
|
* Detect and pre-remove most UNOPTFLATs (4.000)
|
||||||
Report more errors (all of them?) before exiting [Eugene Weber]
|
* Better reporting of unopt problems, including what lines of code
|
||||||
|
* Report more errors (all of them?) before exiting [Eugene Weber]
|
||||||
|
* Auto-create scons config files
|
||||||
|
* Print version/etc message at runtime. (4.000?)
|
||||||
|
Include number of lines of code, percent comments, code complexity measurement
|
||||||
|
<-80chars------------------------------------------------------------------->
|
||||||
|
Verilator 3.600 - fast, free, open-sourced. Copyright 2001-2010.
|
||||||
|
Verilated #### modules, #### instances, ##### sigs,
|
||||||
|
#### non-comment lines, ##### ops, ### KB model size
|
||||||
|
* Default the --l2name to remove extra "v" level of hierarchy (flag to make "top")
|
||||||
|
|
||||||
Internal Code:
|
Internal Code:
|
||||||
Eliminate the AstNUser* passed to all visitors; its only needed in V3Width,
|
* Eliminate the AstNUser* passed to all visitors; its only needed in V3Width,
|
||||||
and removing it will speed up and simplify all the other code.
|
and removing it will speed up and simplify all the other code.
|
||||||
V3Graph should be templated container type, taking in Vertex + Edge types
|
* V3Graph should be templated container type, taking in Vertex + Edge types
|
||||||
|
* Rename V3PreLex etc to match VerilogPerl filenames
|
||||||
|
* Instead of string, have an VEncodedString/VIdString which contains __DOT__ish
|
||||||
|
things, to reduce bugs. Also add _20 trailing space to \ encoded names. (4.000)
|
||||||
|
|
||||||
|
Runtime:
|
||||||
|
* New evalulation loop ~/src/verilator/notes/event_loop.txt (4.000?)
|
||||||
|
* Remove all private internal functions from top level wrapper header, move
|
||||||
|
to new level (4.000?)
|
||||||
|
* Completely standalone simulation (4.000)
|
||||||
|
main() records arguments for $test$plusvars
|
||||||
|
instantiates top,
|
||||||
|
does tracing (support $dump?)
|
||||||
|
calls top->simulateForever()
|
||||||
|
exits
|
||||||
|
|
||||||
Performance:
|
Performance:
|
||||||
Constant propagation
|
* Latch optimizations
|
||||||
|
* Constant propagation
|
||||||
Extra cleaning AND: 1 & ((VARREF >> 1) | ((&VARREF >> 1) & VARREF))
|
Extra cleaning AND: 1 & ((VARREF >> 1) | ((&VARREF >> 1) & VARREF))
|
||||||
Extra shift (perhaps due to clean): if (1 & CAST (VARREF >> #))
|
Extra shift (perhaps due to clean): if (1 & CAST (VARREF >> #))
|
||||||
Gated clock and latch conversion to flops. [JeanPaul Vanitegem]
|
* Gated clock and latch conversion to flops. [JeanPaul Vanitegem]
|
||||||
Could propagate the AND into pos/negedges and let domaining optimize.
|
Could propagate the AND into pos/negedges and let domaining optimize.
|
||||||
Negedge reset
|
* Negedge reset
|
||||||
Switch to remove negedges that don't matter
|
Switch to remove negedges that don't matter
|
||||||
Can't remove async resets from control flops (like in syncronizers)
|
Can't remove async resets from control flops (like in syncronizers)
|
||||||
If all references to array have a constant index, blow up into separate signals-per-index
|
* If all references to array have a constant index, blow up into separate signals-per-index
|
||||||
Multithreaded execution
|
* Bit-multiply for faster bit swapping and a=b[1,3,2] random bit reorderings.
|
||||||
Bit-multiply for faster bit swapping and a=b[1,3,2] random bit reorderings.
|
* Move _last sets and all other combo logic inside master
|
||||||
Move _last sets and all other combo logic inside master
|
|
||||||
if() that triggers on all possible sense items
|
if() that triggers on all possible sense items
|
||||||
Rewrite and combine V3Life, V3Subst
|
* Rewrite and combine V3Life, V3Subst
|
||||||
If block temp only ever set in one place to constant, propagate it
|
If block temp only ever set in one place to constant, propagate it
|
||||||
Used in t_mem for array delayed assignments
|
Used in t_mem for array delayed assignments
|
||||||
Replace variables if set later in same cfunc branch
|
Replace variables if set later in same cfunc branch
|
||||||
See for example duplicate sets of _narrow in cycle 90/91 of t_select_plusloop
|
See for example duplicate sets of _narrow in cycle 90/91 of t_select_plusloop
|
||||||
Same assignment on both if branches
|
* Same assignment on both if branches
|
||||||
"if (a) { ... b=2; } else { ... b=2;}" -> "b=2; if ..."
|
"if (a) { ... b=2; } else { ... b=2;}" -> "b=2; if ..."
|
||||||
Careful though, as b could appear in the statement or multiple times in statement
|
Careful though, as b could appear in the statement or multiple times in statement
|
||||||
(Could just require exatly two 'b's in statement)
|
(Could just require exatly two 'b's in statement)
|
||||||
Simplify XOR/XNOR/AND/OR bit selection trees
|
* Simplify XOR/XNOR/AND/OR bit selection trees
|
||||||
Foo = A[1] ^ A[2] ^ A[3] etc are better as ^ ( A & 32'b...1110 )
|
Foo = A[1] ^ A[2] ^ A[3] etc are better as ^ ( A & 32'b...1110 )
|
||||||
Combine variables into wider elements
|
* Combine variables into wider elements
|
||||||
Parallel statements on different bits should become single signal
|
Parallel statements on different bits should become single signal
|
||||||
Variables that are always consumed in "parallel" can be joined
|
Variables that are always consumed in "parallel" can be joined
|
||||||
Duplicate assignments in gate optimization
|
* Duplicate assignments in gate optimization
|
||||||
Common to have many separate posedge blocks, each with identical
|
Common to have many separate posedge blocks, each with identical
|
||||||
reset_r <= rst_in
|
reset_r <= rst_in
|
||||||
*If signal is used only once (not counting trace), always gate substitute
|
* If signal is used only once (not counting trace), always gate substitute
|
||||||
Don't merge if any combining would form circ logic (out goes back to in)
|
Don't merge if any combining would form circ logic (out goes back to in)
|
||||||
Multiple assignments each bit can become single assign with concat
|
* Multiple assignments each bit can become single assign with concat
|
||||||
Make sure a SEL of a CONCAT can get the single bit back.
|
Make sure a SEL of a CONCAT can get the single bit back.
|
||||||
Usually blocks/values
|
* Usually blocks/values
|
||||||
Enable only after certain time, so VL_TIME_I(32) > 0x1e gets eliminated out
|
Enable only after certain time, so VL_TIME_I(32) > 0x1e gets eliminated out
|
||||||
Better ordering of a<=b, b<=c, put all refs to 'b' next to each other to optimize caching
|
* Better ordering of a<=b, b<=c, put all refs to 'b' next to each other to optimize caching
|
||||||
Allow Split of case statements without a $display/$stop
|
* Allow Split of case statements without a $display/$stop
|
||||||
I-cache packing improvements (what/how?)
|
* I-cache packing improvements (what/how?)
|
||||||
Data cache organization (order of vars in class)
|
* Data cache organization (order of vars in class)
|
||||||
First have clocks,
|
First have clocks,
|
||||||
then bools instead of uint32_t's
|
then bools instead of uint32_t's
|
||||||
then based on what sense list they come from, all outputs, then all inputs
|
then based on what sense list they come from, all outputs, then all inputs
|
||||||
finally have any signals part of a "usually" block, or constant.
|
finally have any signals part of a "usually" block, or constant.
|
||||||
Rather then tracking widths, have a MSB...LSB of this expression
|
* Rather then tracking widths, have a MSB...LSB of this expression
|
||||||
(or better, a bitmask of bits relevant in this expression)
|
(or better, a bitmask of bits relevant in this expression)
|
||||||
Track recirculation and convert into clock-enables
|
* Track recirculation and convert into clock-enables
|
||||||
Clock enables should become new clocking domains for speed
|
* Clock enables should become new clocking domains for speed
|
||||||
If floped(a) & flopped(b) and no other a&b, then instead flop(a&b).
|
* If floped(a) & flopped(b) and no other a&b, then instead flop(a&b).
|
||||||
Sort by output bitselects so can combine more assignments (see DDP example dx_dm signal)
|
* Sort by output bitselects so can combine more assignments (see DDP example dx_dm signal)
|
||||||
|
|
||||||
All of the temp vars that get set, exp pre_ vars and never feedback
|
|
||||||
(not flops) don't need to be stored in the structs, but instead can
|
|
||||||
be per-invocation, and even better register-colored-like to reuse
|
|
||||||
the space. This will greatly reduce the data footprint.
|
|
||||||
|
|
||||||
|
|
||||||
//**********************************************************************
|
|
||||||
//* Eventual tristate bus Stuff allowed (old verilator)
|
|
||||||
|
|
||||||
1) Tristate assignments must be continuous assignments
|
|
||||||
The RHS of a tristate assignment can be the following
|
|
||||||
a) a node (tristate or non-tristate)
|
|
||||||
b) a constant (must be all or no z's)
|
|
||||||
x'b0, x'bz, x{x'bz}, x{x'b0} -> are allowed
|
|
||||||
c) a conditional whose possible values are (a) or (b)
|
|
||||||
|
|
||||||
2) One can lose that fact that a node is a tristate node. This happens
|
|
||||||
if a tristate node is assigned to a 'standard' node, or is used on
|
|
||||||
RHS of a conditional. The following infer tristate signals:
|
|
||||||
a) inout <SIGNAL>
|
|
||||||
b) tri <SIGNAL>
|
|
||||||
c) assigning to 'Z' (maybe through a conditional)
|
|
||||||
Note: tristate-ness of an output port determined only by
|
|
||||||
statements in the module (not the instances it calls)
|
|
||||||
|
|
||||||
4) Tristate variables can't be multidimensional arrays
|
|
||||||
5) Only check tristate contention between modules (not within!)
|
|
||||||
6) Only simple compares with 'Z' are allowed (===)
|
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -878,7 +878,7 @@ section below for descriptions of some of the files that were created.
|
|||||||
We then can compile it
|
We then can compile it
|
||||||
|
|
||||||
cd obj_dir
|
cd obj_dir
|
||||||
make -f Vour.mk Vour
|
make -j -f Vour.mk Vour
|
||||||
|
|
||||||
(Verilator included a default compile rule and link rule, since we used
|
(Verilator included a default compile rule and link rule, since we used
|
||||||
--exe and passed a .cpp file on the Verilator command line. You can also
|
--exe and passed a .cpp file on the Verilator command line. You can also
|
||||||
@@ -944,9 +944,8 @@ Verilator by replacing the verilator --sp flag in the previous step with
|
|||||||
|
|
||||||
We then can compile it
|
We then can compile it
|
||||||
|
|
||||||
make -f Vour.mk Vour__ALL.a
|
make -j -f Vour.mk Vour__ALL.a
|
||||||
make -f Vour.mk ../sc_main.o
|
make -j -f Vour.mk ../sc_main.o verilated.o
|
||||||
make -f Vour.mk verilated.o
|
|
||||||
|
|
||||||
And link with SystemC. Note your path to the libraries may vary,
|
And link with SystemC. Note your path to the libraries may vary,
|
||||||
depending on the operating system.
|
depending on the operating system.
|
||||||
@@ -1630,7 +1629,8 @@ Used after a signal declaration to indicate the signal is used to gate a
|
|||||||
clock, and the user takes responsibility for insuring there are no races
|
clock, and the user takes responsibility for insuring there are no races
|
||||||
related to it. (Typically by adding a latch, and running static timing
|
related to it. (Typically by adding a latch, and running static timing
|
||||||
analysis.) This will cause the clock gate to be ignored in the scheduling
|
analysis.) This will cause the clock gate to be ignored in the scheduling
|
||||||
algorithm, improving performance.
|
algorithm, improving performance. It's also a good idea to enable the
|
||||||
|
IMPERFECTSCH warning, to insure all clock enables are properly recognized.
|
||||||
|
|
||||||
=item /*verilator coverage_block_off*/
|
=item /*verilator coverage_block_off*/
|
||||||
|
|
||||||
|
|||||||
+25
-4
@@ -33,7 +33,11 @@
|
|||||||
//===========================================================================
|
//===========================================================================
|
||||||
// Global variables
|
// Global variables
|
||||||
|
|
||||||
|
// Slow path variables
|
||||||
int Verilated::s_randReset = 0;
|
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 = 1;
|
||||||
bool Verilated::s_calcUnusedSigs = false;
|
bool Verilated::s_calcUnusedSigs = false;
|
||||||
bool Verilated::s_gotFinish = false;
|
bool Verilated::s_gotFinish = false;
|
||||||
@@ -53,6 +57,7 @@ void vl_finish (const char* filename, int linenum, const char* hier) {
|
|||||||
VL_PRINTF("- %s:%d: Verilog $finish\n", filename, linenum);
|
VL_PRINTF("- %s:%d: Verilog $finish\n", filename, linenum);
|
||||||
if (Verilated::gotFinish()) {
|
if (Verilated::gotFinish()) {
|
||||||
VL_PRINTF("- %s:%d: Second verilog $finish, exiting\n", filename, linenum);
|
VL_PRINTF("- %s:%d: Second verilog $finish, exiting\n", filename, linenum);
|
||||||
|
Verilated::flushCall();
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
Verilated::gotFinish(true);
|
Verilated::gotFinish(true);
|
||||||
@@ -62,6 +67,7 @@ void vl_finish (const char* filename, int linenum, const char* hier) {
|
|||||||
#ifndef VL_USER_STOP // Define this to override this function
|
#ifndef VL_USER_STOP // Define this to override this function
|
||||||
void vl_stop (const char* filename, int linenum, const char* hier) {
|
void vl_stop (const char* filename, int linenum, const char* hier) {
|
||||||
Verilated::gotFinish(true);
|
Verilated::gotFinish(true);
|
||||||
|
Verilated::flushCall();
|
||||||
vl_fatal (filename,linenum,hier,"Verilog $stop");
|
vl_fatal (filename,linenum,hier,"Verilog $stop");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -71,6 +77,7 @@ void vl_fatal (const char* filename, int linenum, const char* hier, const char*
|
|||||||
if (0 && hier) {}
|
if (0 && hier) {}
|
||||||
Verilated::gotFinish(true);
|
Verilated::gotFinish(true);
|
||||||
VL_PRINTF("%%Error: %s:%d: %s\n", filename, linenum, msg);
|
VL_PRINTF("%%Error: %s:%d: %s\n", filename, linenum, msg);
|
||||||
|
Verilated::flushCall();
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -920,8 +927,12 @@ IData VL_VALUEPLUSARGS_IW(int rbits, const char* prefixp, char fmt, WDataOutP rw
|
|||||||
|
|
||||||
const char* vl_mc_scan_plusargs(const char* prefixp) {
|
const char* vl_mc_scan_plusargs(const char* prefixp) {
|
||||||
string match = VerilatedImp::argPlusMatch(prefixp);
|
string match = VerilatedImp::argPlusMatch(prefixp);
|
||||||
if (match == "") return 0;
|
static VL_THREAD char outstr[VL_VALUE_STRING_MAX_WIDTH];
|
||||||
else return match.c_str()+strlen(prefixp)+1; // +1 to skip the "+"
|
if (match == "") return NULL;
|
||||||
|
strncpy(outstr, match.c_str()+strlen(prefixp)+1, // +1 to skip the "+"
|
||||||
|
VL_VALUE_STRING_MAX_WIDTH);
|
||||||
|
outstr[VL_VALUE_STRING_MAX_WIDTH-1] = '\0';
|
||||||
|
return outstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
@@ -967,6 +978,15 @@ const char* Verilated::catName(const char* n1, const char* n2) {
|
|||||||
return strp;
|
return strp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Verilated::flushCb(VerilatedVoidCb cb) {
|
||||||
|
if (s_flushCb == cb) {} // Ok - don't duplicate
|
||||||
|
else if (!s_flushCb) { s_flushCb=cb; }
|
||||||
|
else {
|
||||||
|
// Someday we may allow multiple callbacks ala atexit(), but until then
|
||||||
|
vl_fatal("unknown",0,"", "Verilated::flushCb called twice with different callbacks");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Verilated::commandArgs(int argc, const char** argv) {
|
void Verilated::commandArgs(int argc, const char** argv) {
|
||||||
VerilatedImp::commandArgs(argc,argv);
|
VerilatedImp::commandArgs(argc,argv);
|
||||||
}
|
}
|
||||||
@@ -1058,10 +1078,11 @@ void* VerilatedScope::exportFindError(int funcnum) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VerilatedScope::scopeDump() const {
|
void VerilatedScope::scopeDump() const {
|
||||||
VL_PRINTF(" SCOPE: %s\n", name());
|
VL_PRINTF(" SCOPE %p: %s\n", this, name());
|
||||||
for (int i=0; i<m_funcnumMax; i++) {
|
for (int i=0; i<m_funcnumMax; i++) {
|
||||||
if (m_callbacksp && m_callbacksp[i]) {
|
if (m_callbacksp && m_callbacksp[i]) {
|
||||||
VL_PRINTF(" DPI-EXPORT: %s\n", VerilatedImp::exportName(i));
|
VL_PRINTF(" DPI-EXPORT %p: %s\n",
|
||||||
|
m_callbacksp[i], VerilatedImp::exportName(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-4
@@ -62,6 +62,8 @@ typedef vluint32_t WData; ///< Verilated pack data, >64 bits, as an array
|
|||||||
typedef const WData* WDataInP; ///< Array input to a function
|
typedef const WData* WDataInP; ///< Array input to a function
|
||||||
typedef WData* WDataOutP; ///< Array output from a function
|
typedef WData* WDataOutP; ///< Array output from a function
|
||||||
|
|
||||||
|
typedef void (*VerilatedVoidCb)(void);
|
||||||
|
|
||||||
class SpTraceVcd;
|
class SpTraceVcd;
|
||||||
class SpTraceVcdCFile;
|
class SpTraceVcdCFile;
|
||||||
class VerilatedVcd;
|
class VerilatedVcd;
|
||||||
@@ -149,11 +151,12 @@ class VerilatedSyms {
|
|||||||
|
|
||||||
class VerilatedScope {
|
class VerilatedScope {
|
||||||
// Fastpath:
|
// Fastpath:
|
||||||
VerilatedSyms* m_symsp; ///< Symbol table
|
VerilatedSyms* m_symsp; ///< Symbol table
|
||||||
void** m_callbacksp; ///< Callback table pointer (Fastpath)
|
void** m_callbacksp; ///< Callback table pointer (Fastpath)
|
||||||
int m_funcnumMax; ///< Maxium function number stored (Fastpath)
|
int m_funcnumMax; ///< Maxium function number stored (Fastpath)
|
||||||
// 4 bytes padding (on -m64), for rent.
|
// 4 bytes padding (on -m64), for rent.
|
||||||
const char* m_namep; ///< Scope name (Slowpath)
|
const char* m_namep; ///< Scope name (Slowpath)
|
||||||
|
|
||||||
public: // But internals only - called from VerilatedModule's
|
public: // But internals only - called from VerilatedModule's
|
||||||
VerilatedScope();
|
VerilatedScope();
|
||||||
~VerilatedScope();
|
~VerilatedScope();
|
||||||
@@ -182,7 +185,11 @@ public: // But internals only - called from VerilatedModule's
|
|||||||
struct Verilated {
|
struct Verilated {
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
private:
|
private:
|
||||||
|
// Slow path variables
|
||||||
static int s_randReset; ///< Random reset: 0=all 0s, 1=all 1s, 2=random
|
static int s_randReset; ///< Random reset: 0=all 0s, 1=all 1s, 2=random
|
||||||
|
static VerilatedVoidCb s_flushCb; ///< Flush callback function
|
||||||
|
|
||||||
|
// Fast path
|
||||||
static int s_debug; ///< See accessors... only when VL_DEBUG set
|
static int s_debug; ///< See accessors... only when VL_DEBUG set
|
||||||
static bool s_calcUnusedSigs; ///< Waves file on, need all signals calculated
|
static bool s_calcUnusedSigs; ///< Waves file on, need all signals calculated
|
||||||
static bool s_gotFinish; ///< A $finish statement executed
|
static bool s_gotFinish; ///< A $finish statement executed
|
||||||
@@ -224,6 +231,9 @@ public:
|
|||||||
/// Enable/disable assertions
|
/// Enable/disable assertions
|
||||||
static void assertOn(bool flag) { s_assertOn=flag; }
|
static void assertOn(bool flag) { s_assertOn=flag; }
|
||||||
static bool assertOn() { return s_assertOn; }
|
static bool assertOn() { return s_assertOn; }
|
||||||
|
/// Flush callback for VCD waves
|
||||||
|
static void flushCb(VerilatedVoidCb cb);
|
||||||
|
static void flushCall() { if (s_flushCb) (*s_flushCb)(); }
|
||||||
|
|
||||||
/// Record command line arguments, for retrieval by $test$plusargs/$value$plusargs
|
/// Record command line arguments, for retrieval by $test$plusargs/$value$plusargs
|
||||||
static void commandArgs(int argc, const char** argv);
|
static void commandArgs(int argc, const char** argv);
|
||||||
|
|||||||
@@ -88,6 +88,11 @@ void VerilatedVcd::open (const char* filename) {
|
|||||||
m_filename = filename;
|
m_filename = filename;
|
||||||
s_vcdVecp.push_back(this);
|
s_vcdVecp.push_back(this);
|
||||||
|
|
||||||
|
// SPDIFF_OFF
|
||||||
|
// Set callback so an early exit will flush us
|
||||||
|
Verilated::flushCb(&flush_all);
|
||||||
|
|
||||||
|
// SPDIFF_ON
|
||||||
openNext (m_rolloverMB!=0);
|
openNext (m_rolloverMB!=0);
|
||||||
if (!isOpen()) return;
|
if (!isOpen()) return;
|
||||||
|
|
||||||
|
|||||||
+143
-54
@@ -40,7 +40,148 @@ Modify the later visitor functions to process the new feature as needed.
|
|||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head1 DEBUG OUTPUT/ TREE FILES
|
=head1 CODE FLOWS
|
||||||
|
|
||||||
|
=head2 Verilator Flow
|
||||||
|
|
||||||
|
The main flow of Verilator can be followed by reading the Verilator.cpp
|
||||||
|
process() function:
|
||||||
|
|
||||||
|
First, the files specified on the command line are read. Reading involves
|
||||||
|
preprocessing, then lexical analysis with Flex and parsing with Bison.
|
||||||
|
This produces an abstract syntax tree (AST) representation of the design,
|
||||||
|
which is what is visible in the .tree files described below.
|
||||||
|
|
||||||
|
Cells are then linked, which will read and parse additional files as above.
|
||||||
|
|
||||||
|
Functions, variable and other references are linked to their definitions.
|
||||||
|
|
||||||
|
Parameters are resolved and the design is elaborated.
|
||||||
|
|
||||||
|
Verilator then performs many additional edits and optimizations on the
|
||||||
|
hierarchical design. This includes coverage, assertions, X elimination,
|
||||||
|
inlining, constant propagation, and dead code elimination.
|
||||||
|
|
||||||
|
References in the design are then psudo-flattened. Each module's variables
|
||||||
|
and functions get "Scope" references. A scope reference is an occurrence of
|
||||||
|
that un-flattened variable in the flattened hierarchy. A module that occurs
|
||||||
|
only once in the hierarchy will have a single scope and single VarScope for
|
||||||
|
each variable. A module that occurs twice will have a scope for each
|
||||||
|
occurrence, and two VarScopes for each variable. This allows optimizations
|
||||||
|
to proceed across the flattened design, while still preserving the
|
||||||
|
hierarchy.
|
||||||
|
|
||||||
|
Additional edits and optimizations proceed on the psudo-flat design. These
|
||||||
|
include module references, function inlining, loop unrolling, variable
|
||||||
|
lifetime analysis, lookup table creation, always splitting, and logic gate
|
||||||
|
simplifications (pushing inverters, etc).
|
||||||
|
|
||||||
|
Verilator orders the code. Best case, this results in a single "eval"
|
||||||
|
function which has all always statements flowing from top to bottom with no
|
||||||
|
loops.
|
||||||
|
|
||||||
|
Verilator mostly removes the flattening, so that code may be shared between
|
||||||
|
multiple invocations of the same module. It localizes variables, combines
|
||||||
|
identical functions, expands macros to C primitives, adds branch prediction
|
||||||
|
hints, and performs additional constant propagation.
|
||||||
|
|
||||||
|
Verilator finally writes the C++ modules.
|
||||||
|
|
||||||
|
=head2 Verilated Flow
|
||||||
|
|
||||||
|
The evaluation loop outputted by Verilator is designed to allow a single
|
||||||
|
function to perform evaluation under most situations.
|
||||||
|
|
||||||
|
On the first evaluation, the Verilated code calls initial blocks, and then
|
||||||
|
"settles" the modules, by evaluating functions (from always statements)
|
||||||
|
until all signals are stable.
|
||||||
|
|
||||||
|
On other evaluations, the Verilated code detects what input signals have
|
||||||
|
changes. If any are clocks, it calls the appropriate sequential functions
|
||||||
|
(from always @ posedge statements). Interspersed with sequential functions
|
||||||
|
it calls combo functions (from always @*). After this is complete, it
|
||||||
|
detects any changes due to combo loops or internally generated clocks, and
|
||||||
|
if one is found must reevaluate the model again.
|
||||||
|
|
||||||
|
For SystemC code, the eval() function is wrapped in a SystemC SC_METHOD,
|
||||||
|
sensitive to all inputs. (Ideally it would only be sensitive to clocks and
|
||||||
|
combo inputs, but tracing requires all signals to cause evaluation, and the
|
||||||
|
performance difference is small.)
|
||||||
|
|
||||||
|
If tracing is enabled, a callback examines all variables in the design for
|
||||||
|
changes, and writes the trace for each change. To accelerate this process
|
||||||
|
the evaluation process records a bitmask of variables that might have
|
||||||
|
changed; if clear, checking those signals for changes may be skipped.
|
||||||
|
|
||||||
|
=head1 CODING CONVENTIONS
|
||||||
|
|
||||||
|
=head2 Indentation style
|
||||||
|
|
||||||
|
To match the indentation of Verilator C++ sources, use 4 spaces per level,
|
||||||
|
and leave tabs at 8 columns, so every other indent level is a tab stop.
|
||||||
|
|
||||||
|
In Emacs, use in your ~/.emacs
|
||||||
|
|
||||||
|
(add-hook 'c-mode-common-hook '(lambda ()
|
||||||
|
(c-set-style "cc-mode"))))
|
||||||
|
|
||||||
|
This sets indentation to the cc-mode defaults. (Verilator predates a
|
||||||
|
CC-mode change of several years ago which overrides the defaults with GNU
|
||||||
|
style indentation; the c-set-style undoes that.)
|
||||||
|
|
||||||
|
=head2 Visitor Functions
|
||||||
|
|
||||||
|
There's three ways data is passed between visitor functions.
|
||||||
|
|
||||||
|
1. A visitor-class member variable. This is generally for passing "parent"
|
||||||
|
information down to children. m_modp is a common example. It's set to
|
||||||
|
NULL in the constructor, where that node (AstModule visitor) sets it, then
|
||||||
|
the children are iterated, then it's cleared. Children under an AstModule
|
||||||
|
will see it set, while nodes elsewhere will see it clear. If there can be
|
||||||
|
nested items (for example an AstFor under an AstFor) the variable needs to
|
||||||
|
be save-set-restored in the AstFor visitor, otherwise exiting the lower for
|
||||||
|
will loose the upper for's setting.
|
||||||
|
|
||||||
|
2. User() attributes. Each node has 5 ->user() number or ->userp() pointer
|
||||||
|
utility values (a common technique lifted from graph traversal packages).
|
||||||
|
A visitor first clears the one it wants to use by calling
|
||||||
|
AstNode::user#ClearTree(), then it can mark any node's user() with whatever
|
||||||
|
data it wants. Readers just call nodep->user(), but may need to cast
|
||||||
|
appropriately, so you'll often see nodep->userp()->castSOMETYPE(). At the
|
||||||
|
top of each visitor are comments describing how the user() stuff applies to
|
||||||
|
that visitor class. For example:
|
||||||
|
|
||||||
|
// NODE STATE
|
||||||
|
// Cleared entire netlist
|
||||||
|
// AstModule::user1p() // bool. True to inline this module
|
||||||
|
|
||||||
|
This says that at the AstNetlist user1ClearTree() is called. Each
|
||||||
|
AstModule's is user1() is used to indicate if we're going to inline it.
|
||||||
|
|
||||||
|
These comments are important to make sure a user#() on a given AstNode type
|
||||||
|
is never being used for two different purposes.
|
||||||
|
|
||||||
|
Note that calling user#ClearTree is fast, it doesn't walk the tree, so it's
|
||||||
|
ok to call fairly often. For example, it's commonly called on every
|
||||||
|
module.
|
||||||
|
|
||||||
|
3. Parameters can be passed between the visitors in close to the "normal"
|
||||||
|
function caller to callee way. This is the second "vup" parameter that is
|
||||||
|
ignored on most of the visitor functions. V3Width does this, but it proved
|
||||||
|
more messy than the above and is deprecated. (V3Width was nearly the first
|
||||||
|
module written. Someday this scheme may be removed, as it slows the
|
||||||
|
program down to have to pass vup everywhere.)
|
||||||
|
|
||||||
|
=head1 TESTING
|
||||||
|
|
||||||
|
To write a test see notes in the forum and in the verilator.txt manual.
|
||||||
|
|
||||||
|
Note you can run the regression tests in parallel; see the
|
||||||
|
test_regress/driver.pl script -j flag.
|
||||||
|
|
||||||
|
=head1 DEBUGGING
|
||||||
|
|
||||||
|
=head2 --debug
|
||||||
|
|
||||||
When you run with --debug there are two primary output file types placed into
|
When you run with --debug there are two primary output file types placed into
|
||||||
the obj_dir, .tree and .dot files.
|
the obj_dir, .tree and .dot files.
|
||||||
@@ -94,59 +235,7 @@ variable is an output.
|
|||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head1 TESTING
|
=head2 Debugging with GDB
|
||||||
|
|
||||||
To write a test see notes in the forum and in the verilator.txt manual.
|
|
||||||
|
|
||||||
Note you can run the regression tests in parallel; see the
|
|
||||||
test_regress/driver.pl script -j flag.
|
|
||||||
|
|
||||||
=head1 VISITOR FUNCTIONS
|
|
||||||
|
|
||||||
=head2 Passing Variables
|
|
||||||
|
|
||||||
There's three ways data is passed between visitor functions.
|
|
||||||
|
|
||||||
1. A visitor-class member variable. This is generally for passing "parent"
|
|
||||||
information down to children. m_modp is a common example. It's set to
|
|
||||||
NULL in the constructor, where that node (AstModule visitor) sets it, then
|
|
||||||
the children are iterated, then it's cleared. Children under an AstModule
|
|
||||||
will see it set, while nodes elsewhere will see it clear. If there can be
|
|
||||||
nested items (for example an AstFor under an AstFor) the variable needs to
|
|
||||||
be save-set-restored in the AstFor visitor, otherwise exiting the lower for
|
|
||||||
will loose the upper for's setting.
|
|
||||||
|
|
||||||
2. User() attributes. Each node has 5 ->user() number or ->userp() pointer
|
|
||||||
utility values (a common technique lifted from graph traversal packages).
|
|
||||||
A visitor first clears the one it wants to use by calling
|
|
||||||
AstNode::user#ClearTree(), then it can mark any node's user() with whatever
|
|
||||||
data it wants. Readers just call nodep->user(), but may need to cast
|
|
||||||
appropriately, so you'll often see nodep->userp()->castSOMETYPE(). At the
|
|
||||||
top of each visitor are comments describing how the user() stuff applies to
|
|
||||||
that visitor class. For example:
|
|
||||||
|
|
||||||
// NODE STATE
|
|
||||||
// Cleared entire netlist
|
|
||||||
// AstModule::user1p() // bool. True to inline this module
|
|
||||||
|
|
||||||
This says that at the AstNetlist user1ClearTree() is called. Each
|
|
||||||
AstModule's is user1() is used to indicate if we're going to inline it.
|
|
||||||
|
|
||||||
These comments are important to make sure a user#() on a given AstNode type
|
|
||||||
is never being used for two different purposes.
|
|
||||||
|
|
||||||
Note that calling user#ClearTree is fast, it doesn't walk the tree, so it's
|
|
||||||
ok to call fairly often. For example, it's commonly called on every
|
|
||||||
module.
|
|
||||||
|
|
||||||
3. Parameters can be passed between the visitors in close to the "normal"
|
|
||||||
function caller to callee way. This is the second "vup" parameter that is
|
|
||||||
ignored on most of the visitor functions. V3Width does this, but it proved
|
|
||||||
more messy than the above and is deprecated. (V3Width was nearly the first
|
|
||||||
module written. Someday this scheme may be removed, as it slows the
|
|
||||||
program down to have to pass vup everywhere.)
|
|
||||||
|
|
||||||
=head1 DEBUGGING WITH GDB
|
|
||||||
|
|
||||||
The test_regress/driver.pl script accepts --debug --gdb to start Verilator
|
The test_regress/driver.pl script accepts --debug --gdb to start Verilator
|
||||||
under gdb. You can also use --debug --gdbbt to just backtrace and then
|
under gdb. You can also use --debug --gdbbt to just backtrace and then
|
||||||
|
|||||||
+7
-5
@@ -121,6 +121,7 @@ HEADERS = $(wildcard V*.h v*.h)
|
|||||||
|
|
||||||
ASTGEN = $(srcdir)/astgen
|
ASTGEN = $(srcdir)/astgen
|
||||||
BISONPRE = $(srcdir)/bisonpre
|
BISONPRE = $(srcdir)/bisonpre
|
||||||
|
FLEXFIX = $(srcdir)/flexfix
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
#### Top level
|
#### Top level
|
||||||
@@ -194,8 +195,9 @@ RAW_OBJS = \
|
|||||||
V3Link.o \
|
V3Link.o \
|
||||||
V3LinkCells.o \
|
V3LinkCells.o \
|
||||||
V3LinkDot.o \
|
V3LinkDot.o \
|
||||||
V3LinkLevel.o \
|
V3LinkJump.o \
|
||||||
V3LinkLValue.o \
|
V3LinkLValue.o \
|
||||||
|
V3LinkLevel.o \
|
||||||
V3LinkParse.o \
|
V3LinkParse.o \
|
||||||
V3LinkResolve.o \
|
V3LinkResolve.o \
|
||||||
V3Localize.o \
|
V3Localize.o \
|
||||||
@@ -295,15 +297,15 @@ V3Lexer_pregen.yy.cpp: verilog.l V3ParseBison.h $(HEADERS)
|
|||||||
${LEX} --version
|
${LEX} --version
|
||||||
${LEX} ${LFLAGS} -o$@ $<
|
${LEX} ${LFLAGS} -o$@ $<
|
||||||
|
|
||||||
V3Lexer.yy.cpp: V3Lexer_pregen.yy.cpp
|
V3Lexer.yy.cpp: V3Lexer_pregen.yy.cpp $(FLEXFIX)
|
||||||
$(PERL) $(srcdir)/flexfix <$< >$@
|
$(PERL) $(FLEXFIX) V3Lexer <$< >$@
|
||||||
|
|
||||||
V3PreLex_pregen.yy.cpp: V3PreLex.l $(HEADERS)
|
V3PreLex_pregen.yy.cpp: V3PreLex.l $(HEADERS)
|
||||||
${LEX} --version
|
${LEX} --version
|
||||||
${LEX} ${LFLAGS} -o$@ $<
|
${LEX} ${LFLAGS} -o$@ $<
|
||||||
|
|
||||||
V3PreLex.yy.cpp: V3PreLex_pregen.yy.cpp
|
V3PreLex.yy.cpp: V3PreLex_pregen.yy.cpp $(FLEXFIX)
|
||||||
$(PERL) $(srcdir)/flexfix <$< >$@
|
$(PERL) $(FLEXFIX) V3PreLex <$< >$@
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|||||||
@@ -761,6 +761,7 @@ public:
|
|||||||
AstNode* clonep() const { return ((m_cloneCnt==s_cloneCntGbl)?m_clonep:NULL); }
|
AstNode* clonep() const { return ((m_cloneCnt==s_cloneCntGbl)?m_clonep:NULL); }
|
||||||
AstNode* firstAbovep() const { return ((backp() && backp()->nextp()!=this) ? backp() : NULL); } // Returns NULL when second or later in list
|
AstNode* firstAbovep() const { return ((backp() && backp()->nextp()!=this) ? backp() : NULL); } // Returns NULL when second or later in list
|
||||||
bool brokeExists() const;
|
bool brokeExists() const;
|
||||||
|
bool brokeExistsAbove() const;
|
||||||
|
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
virtual ~AstNode();
|
virtual ~AstNode();
|
||||||
@@ -870,6 +871,7 @@ public:
|
|||||||
AstNode* addNext(AstNode* newp); // Returns this, adds to end of list
|
AstNode* addNext(AstNode* newp); // Returns this, adds to end of list
|
||||||
AstNode* addNextNull(AstNode* newp); // Returns this, adds to end of list, NULL is OK
|
AstNode* addNextNull(AstNode* newp); // Returns this, adds to end of list, NULL is OK
|
||||||
void addNextHere(AstNode* newp); // Adds after speced node
|
void addNextHere(AstNode* newp); // Adds after speced node
|
||||||
|
void addPrev(AstNode* newp) { replaceWith(newp); newp->addNext(this); }
|
||||||
void addHereThisAsNext(AstNode* newp); // Adds at old place of this, this becomes next
|
void addHereThisAsNext(AstNode* newp); // Adds at old place of this, this becomes next
|
||||||
void replaceWith(AstNode* newp); // Replace current node in tree with new node
|
void replaceWith(AstNode* newp); // Replace current node in tree with new node
|
||||||
void v3errorEnd(ostringstream& str) const;
|
void v3errorEnd(ostringstream& str) const;
|
||||||
|
|||||||
@@ -494,6 +494,12 @@ void AstDisplay::dump(ostream& str) {
|
|||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
//str<<" "<<displayType().ascii();
|
//str<<" "<<displayType().ascii();
|
||||||
}
|
}
|
||||||
|
void AstJumpGo::dump(ostream& str) {
|
||||||
|
this->AstNode::dump(str);
|
||||||
|
str<<" -> ";
|
||||||
|
if (labelp()) { labelp()->dump(str); }
|
||||||
|
else { str<<"%Error:UNLINKED"; }
|
||||||
|
}
|
||||||
void AstEnumItemRef::dump(ostream& str) {
|
void AstEnumItemRef::dump(ostream& str) {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
str<<" -> ";
|
str<<" -> ";
|
||||||
|
|||||||
+81
-10
@@ -1846,14 +1846,6 @@ struct AstGenFor : public AstNodeFor {
|
|||||||
ASTNODE_NODE_FUNCS(GenFor, GENFOR)
|
ASTNODE_NODE_FUNCS(GenFor, GENFOR)
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstFor : public AstNodeFor {
|
|
||||||
AstFor(FileLine* fileline, AstNode* initsp, AstNode* condp,
|
|
||||||
AstNode* incsp, AstNode* bodysp)
|
|
||||||
: AstNodeFor(fileline, initsp, condp, incsp, bodysp) {
|
|
||||||
}
|
|
||||||
ASTNODE_NODE_FUNCS(For, FOR)
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AstRepeat : public AstNodeStmt {
|
struct AstRepeat : public AstNodeStmt {
|
||||||
AstRepeat(FileLine* fileline, AstNode* countp, AstNode* bodysp)
|
AstRepeat(FileLine* fileline, AstNode* countp, AstNode* bodysp)
|
||||||
: AstNodeStmt(fileline) {
|
: AstNodeStmt(fileline) {
|
||||||
@@ -1869,16 +1861,18 @@ struct AstRepeat : public AstNodeStmt {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct AstWhile : public AstNodeStmt {
|
struct AstWhile : public AstNodeStmt {
|
||||||
AstWhile(FileLine* fileline, AstNode* condp, AstNode* bodysp)
|
AstWhile(FileLine* fileline, AstNode* condp, AstNode* bodysp, AstNode* incsp=NULL)
|
||||||
: AstNodeStmt(fileline) {
|
: AstNodeStmt(fileline) {
|
||||||
setOp2p(condp); addNOp3p(bodysp);
|
setOp2p(condp); addNOp3p(bodysp); addNOp4p(incsp);
|
||||||
}
|
}
|
||||||
ASTNODE_NODE_FUNCS(While, WHILE)
|
ASTNODE_NODE_FUNCS(While, WHILE)
|
||||||
AstNode* precondsp() const { return op1p()->castNode(); } // op1= prepare statements for condition (exec every loop)
|
AstNode* precondsp() const { return op1p()->castNode(); } // op1= prepare statements for condition (exec every loop)
|
||||||
AstNode* condp() const { return op2p()->castNode(); } // op2= condition to continue
|
AstNode* condp() const { return op2p()->castNode(); } // op2= condition to continue
|
||||||
AstNode* bodysp() const { return op3p()->castNode(); } // op3= body of loop
|
AstNode* bodysp() const { return op3p()->castNode(); } // op3= body of loop
|
||||||
|
AstNode* incsp() const { return op4p()->castNode(); } // op4= increment (if from a FOR loop)
|
||||||
void addPrecondsp(AstNode* newp) { addOp1p(newp); }
|
void addPrecondsp(AstNode* newp) { addOp1p(newp); }
|
||||||
void addBodysp(AstNode* newp) { addOp3p(newp); }
|
void addBodysp(AstNode* newp) { addOp3p(newp); }
|
||||||
|
void addIncsp(AstNode* newp) { addOp4p(newp); }
|
||||||
virtual bool isGateOptimizable() const { return false; }
|
virtual bool isGateOptimizable() const { return false; }
|
||||||
virtual int instrCount() const { return instrCountBranch(); }
|
virtual int instrCount() const { return instrCountBranch(); }
|
||||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||||
@@ -1887,6 +1881,36 @@ struct AstWhile : public AstNodeStmt {
|
|||||||
virtual void addNextStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here
|
virtual void addNextStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AstBreak : public AstNodeStmt {
|
||||||
|
AstBreak(FileLine* fileline)
|
||||||
|
: AstNodeStmt (fileline) {}
|
||||||
|
ASTNODE_NODE_FUNCS(Break, BREAK)
|
||||||
|
virtual string verilogKwd() const { return "break"; };
|
||||||
|
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||||
|
virtual bool isSplittable() const { return false; } // SPECIAL: We don't process code after breaks
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AstContinue : public AstNodeStmt {
|
||||||
|
AstContinue(FileLine* fileline)
|
||||||
|
: AstNodeStmt (fileline) {}
|
||||||
|
ASTNODE_NODE_FUNCS(Continue, CONTINUE)
|
||||||
|
virtual string verilogKwd() const { return "continue"; };
|
||||||
|
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||||
|
virtual bool isSplittable() const { return false; } // SPECIAL: We don't process code after breaks
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AstReturn : public AstNodeStmt {
|
||||||
|
AstReturn(FileLine* fileline, AstNode* lhsp=NULL)
|
||||||
|
: AstNodeStmt (fileline) {
|
||||||
|
setNOp1p(lhsp);
|
||||||
|
}
|
||||||
|
ASTNODE_NODE_FUNCS(Return, RETURN)
|
||||||
|
virtual string verilogKwd() const { return "return"; };
|
||||||
|
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||||
|
AstNode* lhsp() const { return op1p(); }
|
||||||
|
virtual bool isSplittable() const { return false; } // SPECIAL: We don't process code after breaks
|
||||||
|
};
|
||||||
|
|
||||||
struct AstGenIf : public AstNodeIf {
|
struct AstGenIf : public AstNodeIf {
|
||||||
AstGenIf(FileLine* fileline, AstNode* condp, AstNode* ifsp, AstNode* elsesp)
|
AstGenIf(FileLine* fileline, AstNode* condp, AstNode* ifsp, AstNode* elsesp)
|
||||||
: AstNodeIf(fileline, condp, ifsp, elsesp) {
|
: AstNodeIf(fileline, condp, ifsp, elsesp) {
|
||||||
@@ -1901,6 +1925,53 @@ struct AstIf : public AstNodeIf {
|
|||||||
ASTNODE_NODE_FUNCS(If, IF)
|
ASTNODE_NODE_FUNCS(If, IF)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AstJumpLabel : public AstNodeStmt {
|
||||||
|
// Jump point declaration
|
||||||
|
// Separate from AstJumpGo; as a declaration can't be deleted
|
||||||
|
// Parents: {statement list}
|
||||||
|
// Children: {statement list, with JumpGo below}
|
||||||
|
private:
|
||||||
|
int m_labelNum; // Set by V3EmitCSyms to tell final V3Emit what to increment
|
||||||
|
public:
|
||||||
|
AstJumpLabel(FileLine* fl, AstNode* stmtsp)
|
||||||
|
: AstNodeStmt(fl) ,m_labelNum(0) {
|
||||||
|
addNOp1p(stmtsp);
|
||||||
|
}
|
||||||
|
virtual int instrCount() const { return 0; }
|
||||||
|
ASTNODE_NODE_FUNCS(JumpLabel, JUMPLABEL)
|
||||||
|
virtual bool maybePointedTo() const { return true; }
|
||||||
|
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||||
|
virtual bool same(AstNode* samep) const { return true; }
|
||||||
|
// op1 = Statements
|
||||||
|
AstNode* stmtsp() const { return op1p()->castNode(); } // op1 = List of statements
|
||||||
|
void addStmtsp(AstNode* nodep) { addNOp1p(nodep); }
|
||||||
|
int labelNum() const { return m_labelNum; }
|
||||||
|
void labelNum(int flag) { m_labelNum=flag; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AstJumpGo : public AstNodeStmt {
|
||||||
|
// Jump point; branch up to the JumpLabel
|
||||||
|
// Parents: {statement list}
|
||||||
|
private:
|
||||||
|
AstJumpLabel* m_labelp; // [After V3Jump] Pointer to declaration
|
||||||
|
public:
|
||||||
|
AstJumpGo(FileLine* fl, AstJumpLabel* labelp)
|
||||||
|
: AstNodeStmt(fl) {
|
||||||
|
m_labelp = labelp;
|
||||||
|
}
|
||||||
|
ASTNODE_NODE_FUNCS(JumpGo, JUMPGO)
|
||||||
|
virtual bool broken() const { return !labelp()->brokeExistsAbove(); }
|
||||||
|
virtual void cloneRelink() { if (m_labelp->clonep()) m_labelp = m_labelp->clonep()->castJumpLabel(); }
|
||||||
|
virtual void dump(ostream& str);
|
||||||
|
virtual int instrCount() const { return instrCountBranch(); }
|
||||||
|
virtual V3Hash sameHash() const { return V3Hash(labelp()); }
|
||||||
|
virtual bool same(AstNode* samep) const { // Also same if identical tree structure all the way down, but hard to detect
|
||||||
|
return labelp()==samep->castJumpGo()->labelp(); }
|
||||||
|
virtual bool isGateOptimizable() const { return false; }
|
||||||
|
virtual bool isSplittable() const { return false; } // SPECIAL: We don't process code after breaks
|
||||||
|
AstJumpLabel* labelp() const { return m_labelp; }
|
||||||
|
};
|
||||||
|
|
||||||
struct AstUntilStable : public AstNodeStmt {
|
struct AstUntilStable : public AstNodeStmt {
|
||||||
// Quasi-while loop until given signals are stable
|
// Quasi-while loop until given signals are stable
|
||||||
// Parents: CFUNC (generally)
|
// Parents: CFUNC (generally)
|
||||||
|
|||||||
@@ -135,53 +135,6 @@ private:
|
|||||||
m_modp->addStmtp(nodep);
|
m_modp->addStmtp(nodep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstFor* nodep, AstNUser*) {
|
|
||||||
// So later optimizations don't need to deal with them,
|
|
||||||
// FOR(init,cond,assign,body) -> init,WHILE(cond) { body, assign }
|
|
||||||
AstNode* initsp = nodep->initsp(); if (initsp) initsp->unlinkFrBackWithNext();
|
|
||||||
AstNode* condp = nodep->condp(); if (condp) condp->unlinkFrBackWithNext();
|
|
||||||
AstNode* incsp = nodep->incsp(); if (incsp) incsp->unlinkFrBackWithNext();
|
|
||||||
AstNode* bodysp = nodep->bodysp(); if (bodysp) bodysp->unlinkFrBackWithNext();
|
|
||||||
bodysp = bodysp->addNext(incsp);
|
|
||||||
AstNode* newp = new AstWhile(nodep->fileline(),
|
|
||||||
condp,
|
|
||||||
bodysp);
|
|
||||||
initsp = initsp->addNext(newp);
|
|
||||||
newp = initsp;
|
|
||||||
nodep->replaceWith(newp);
|
|
||||||
nodep->deleteTree(); nodep=NULL;
|
|
||||||
}
|
|
||||||
virtual void visit(AstRepeat* nodep, AstNUser*) {
|
|
||||||
// So later optimizations don't need to deal with them,
|
|
||||||
// REPEAT(count,body) -> loop=count,WHILE(loop>0) { body, loop-- }
|
|
||||||
// Note var can be signed or unsigned based on original number.
|
|
||||||
AstNode* countp = nodep->countp()->unlinkFrBackWithNext();
|
|
||||||
string name = string("__Vrepeat")+cvtToStr(m_repeatNum++);
|
|
||||||
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP, name, AstLogicPacked(), countp->width());
|
|
||||||
m_modp->addStmtp(varp);
|
|
||||||
AstNode* initsp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
|
|
||||||
countp);
|
|
||||||
AstNode* decp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
|
|
||||||
new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
|
|
||||||
new AstConst(nodep->fileline(), 1)));
|
|
||||||
AstNode* condp;
|
|
||||||
if (countp->isSigned()) {
|
|
||||||
condp = new AstGtS(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
|
|
||||||
new AstConst(nodep->fileline(), 0));
|
|
||||||
} else {
|
|
||||||
condp = new AstGt (nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
|
|
||||||
new AstConst(nodep->fileline(), 0));
|
|
||||||
}
|
|
||||||
AstNode* bodysp = nodep->bodysp(); if (bodysp) bodysp->unlinkFrBackWithNext();
|
|
||||||
bodysp = bodysp->addNext(decp);
|
|
||||||
AstNode* newp = new AstWhile(nodep->fileline(),
|
|
||||||
condp,
|
|
||||||
bodysp);
|
|
||||||
initsp = initsp->addNext(newp);
|
|
||||||
newp = initsp;
|
|
||||||
nodep->replaceWith(newp);
|
|
||||||
nodep->deleteTree(); nodep=NULL;
|
|
||||||
}
|
|
||||||
virtual void visit(AstScopeName* nodep, AstNUser*) {
|
virtual void visit(AstScopeName* nodep, AstNUser*) {
|
||||||
// If there's a %m in the display text, we add a special node that will contain the name()
|
// If there's a %m in the display text, we add a special node that will contain the name()
|
||||||
// Similar code in V3Inline
|
// Similar code in V3Inline
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ private:
|
|||||||
static const int FLAG_IN_TREE = 0x02; // Is in netlist tree
|
static const int FLAG_IN_TREE = 0x02; // Is in netlist tree
|
||||||
static const int FLAG_LINKABLE = 0x04; // Is in netlist tree, can be linked to
|
static const int FLAG_LINKABLE = 0x04; // Is in netlist tree, can be linked to
|
||||||
static const int FLAG_LEAKED = 0x08; // Known to have been leaked
|
static const int FLAG_LEAKED = 0x08; // Known to have been leaked
|
||||||
|
static const int FLAG_UNDER_NOW = 0x10; // Is in tree as parent of current node
|
||||||
public:
|
public:
|
||||||
// METHODS
|
// METHODS
|
||||||
static void deleted(const AstNode* nodep) {
|
static void deleted(const AstNode* nodep) {
|
||||||
@@ -74,6 +75,15 @@ public:
|
|||||||
s_nodes.insert(make_pair(nodep,FLAG_ALLOCATED));
|
s_nodes.insert(make_pair(nodep,FLAG_ALLOCATED));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static void setUnder(const AstNode* nodep, bool flag) {
|
||||||
|
// Called by BrokenCheckVisitor when each node entered/exited
|
||||||
|
if (!okIfLinkedTo(nodep)) return;
|
||||||
|
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||||
|
if (iter!=s_nodes.end()) {
|
||||||
|
iter->second &= ~FLAG_UNDER_NOW;
|
||||||
|
if (flag) iter->second |= FLAG_UNDER_NOW;
|
||||||
|
}
|
||||||
|
}
|
||||||
static void addInTree(AstNode* nodep, bool linkable) {
|
static void addInTree(AstNode* nodep, bool linkable) {
|
||||||
#ifndef VL_LEAK_CHECKS
|
#ifndef VL_LEAK_CHECKS
|
||||||
if (!linkable) return; // save some time, else the map will get huge!
|
if (!linkable) return; // save some time, else the map will get huge!
|
||||||
@@ -111,6 +121,14 @@ public:
|
|||||||
if (!(iter->second & FLAG_LINKABLE)) return false;
|
if (!(iter->second & FLAG_LINKABLE)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
static bool okIfBelow(const AstNode* nodep) {
|
||||||
|
// Must be linked to and below current node
|
||||||
|
if (!okIfLinkedTo(nodep)) return false;
|
||||||
|
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||||
|
if (iter == s_nodes.end()) return false;
|
||||||
|
if (!(iter->second & FLAG_UNDER_NOW)) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
static void prepForTree() {
|
static void prepForTree() {
|
||||||
#ifndef VL_LEAK_CHECKS
|
#ifndef VL_LEAK_CHECKS
|
||||||
s_nodes.clear();
|
s_nodes.clear();
|
||||||
@@ -152,6 +170,10 @@ bool AstNode::brokeExists() const {
|
|||||||
// Called by node->broken() routines to do table lookup
|
// Called by node->broken() routines to do table lookup
|
||||||
return BrokenTable::okIfLinkedTo(this);
|
return BrokenTable::okIfLinkedTo(this);
|
||||||
}
|
}
|
||||||
|
bool AstNode::brokeExistsAbove() const {
|
||||||
|
// Called by node->broken() routines to do table lookup
|
||||||
|
return BrokenTable::okIfBelow(this);
|
||||||
|
}
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|
||||||
@@ -180,6 +202,7 @@ public:
|
|||||||
class BrokenCheckVisitor : public AstNVisitor {
|
class BrokenCheckVisitor : public AstNVisitor {
|
||||||
private:
|
private:
|
||||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||||
|
BrokenTable::setUnder(nodep,true);
|
||||||
if (nodep->broken()) {
|
if (nodep->broken()) {
|
||||||
nodep->v3fatalSrc("Broken link in node (or something without maybePointedTo)\n");
|
nodep->v3fatalSrc("Broken link in node (or something without maybePointedTo)\n");
|
||||||
}
|
}
|
||||||
@@ -192,6 +215,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
|
BrokenTable::setUnder(nodep,false);
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
// CONSTUCTORS
|
// CONSTUCTORS
|
||||||
|
|||||||
+27
-1
@@ -96,6 +96,7 @@ private:
|
|||||||
// ** only when m_warn/m_expensive is set. If state is needed other times,
|
// ** only when m_warn/m_expensive is set. If state is needed other times,
|
||||||
// ** must track down everywhere V3Const is called and make sure no overlaps.
|
// ** must track down everywhere V3Const is called and make sure no overlaps.
|
||||||
// AstVar::user4p -> Used by ConstVarMarkVisitor/ConstVarFindVisitor
|
// AstVar::user4p -> Used by ConstVarMarkVisitor/ConstVarFindVisitor
|
||||||
|
// AstJumpLabel::user4 -> bool. Set when AstJumpGo uses this label
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
bool m_params; // If true, propogate parameterized and true numbers only
|
bool m_params; // If true, propogate parameterized and true numbers only
|
||||||
@@ -1487,7 +1488,8 @@ private:
|
|||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
if (nodep->condp()->isZero()) {
|
if (nodep->condp()->isZero()) {
|
||||||
UINFO(4,"WHILE(0) => nop "<<nodep<<endl);
|
UINFO(4,"WHILE(0) => nop "<<nodep<<endl);
|
||||||
nodep->unlinkFrBack();
|
if (nodep->precondsp()) nodep->replaceWith(nodep->precondsp());
|
||||||
|
else nodep->unlinkFrBack();
|
||||||
nodep->deleteTree(); nodep=NULL;
|
nodep->deleteTree(); nodep=NULL;
|
||||||
}
|
}
|
||||||
else if (operandBoolShift(nodep->condp())) {
|
else if (operandBoolShift(nodep->condp())) {
|
||||||
@@ -1499,6 +1501,30 @@ private:
|
|||||||
// If output of a presel didn't get consted, chances are V3Param didn't visit properly
|
// If output of a presel didn't get consted, chances are V3Param didn't visit properly
|
||||||
virtual void visit(AstNodePreSel* nodep, AstNUser*) {}
|
virtual void visit(AstNodePreSel* nodep, AstNUser*) {}
|
||||||
|
|
||||||
|
//-----
|
||||||
|
// Jump elimination
|
||||||
|
|
||||||
|
virtual void visit(AstJumpGo* nodep, AstNUser*) {
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
if (m_expensive) { nodep->labelp()->user4(true); }
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(AstJumpLabel* nodep, AstNUser*) {
|
||||||
|
// Because JumpLabels disable many optimizations,
|
||||||
|
// remove JumpLabels that are not pointed to by any AstJumpGos
|
||||||
|
// Note this assumes all AstJumpGos are underneath the given label; V3Broken asserts this
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
// AstJumpGo's below here that point to this node will set user4
|
||||||
|
if (m_expensive && !nodep->user4()) {
|
||||||
|
UINFO(4,"JUMPLABEL => unused "<<nodep<<endl);
|
||||||
|
AstNode* underp = NULL;
|
||||||
|
if (nodep->stmtsp()) underp = nodep->stmtsp()->unlinkFrBackWithNext();
|
||||||
|
if (underp) nodep->replaceWith(underp);
|
||||||
|
else nodep->unlinkFrBack();
|
||||||
|
nodep->deleteTree(); nodep=NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//-----
|
//-----
|
||||||
// Below lines are magic expressions processed by astgen
|
// Below lines are magic expressions processed by astgen
|
||||||
// "AstNODETYPE { # bracket not paren
|
// "AstNODETYPE { # bracket not paren
|
||||||
|
|||||||
@@ -360,12 +360,22 @@ public:
|
|||||||
puts(")); }\n");
|
puts(")); }\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstJumpGo* nodep, AstNUser*) {
|
||||||
|
puts("goto __Vlabel"+cvtToStr(nodep->labelp()->labelNum())+";\n");
|
||||||
|
}
|
||||||
|
virtual void visit(AstJumpLabel* nodep, AstNUser*) {
|
||||||
|
puts("{\n");
|
||||||
|
nodep->stmtsp()->iterateAndNext(*this);
|
||||||
|
puts("}\n");
|
||||||
|
puts("__Vlabel"+cvtToStr(nodep->labelNum())+": ;\n");
|
||||||
|
}
|
||||||
virtual void visit(AstWhile* nodep, AstNUser*) {
|
virtual void visit(AstWhile* nodep, AstNUser*) {
|
||||||
nodep->precondsp()->iterateAndNext(*this);
|
nodep->precondsp()->iterateAndNext(*this);
|
||||||
puts("while (");
|
puts("while (");
|
||||||
nodep->condp()->iterateAndNext(*this);
|
nodep->condp()->iterateAndNext(*this);
|
||||||
puts(") {\n");
|
puts(") {\n");
|
||||||
nodep->bodysp()->iterateAndNext(*this);
|
nodep->bodysp()->iterateAndNext(*this);
|
||||||
|
nodep->incsp()->iterateAndNext(*this);
|
||||||
nodep->precondsp()->iterateAndNext(*this); // Need to recompute before next loop
|
nodep->precondsp()->iterateAndNext(*this); // Need to recompute before next loop
|
||||||
puts("}\n");
|
puts("}\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ class EmitCSyms : EmitCBaseVisitor {
|
|||||||
ScopeFuncs m_scopeFuncs; // Each {scope,dpiexportfunc}
|
ScopeFuncs m_scopeFuncs; // Each {scope,dpiexportfunc}
|
||||||
V3LanguageWords m_words; // Reserved word detector
|
V3LanguageWords m_words; // Reserved word detector
|
||||||
int m_coverBins; // Coverage bin number
|
int m_coverBins; // Coverage bin number
|
||||||
|
int m_labelNum; // Next label number
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
void emitSymHdr();
|
void emitSymHdr();
|
||||||
@@ -114,6 +115,7 @@ class EmitCSyms : EmitCBaseVisitor {
|
|||||||
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
virtual void visit(AstNodeModule* nodep, AstNUser*) {
|
||||||
nameCheck(nodep);
|
nameCheck(nodep);
|
||||||
m_modp = nodep;
|
m_modp = nodep;
|
||||||
|
m_labelNum = 0;
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
m_modp = NULL;
|
m_modp = NULL;
|
||||||
}
|
}
|
||||||
@@ -138,6 +140,10 @@ class EmitCSyms : EmitCBaseVisitor {
|
|||||||
nodep->binNum(m_coverBins++);
|
nodep->binNum(m_coverBins++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstJumpLabel* nodep, AstNUser*) {
|
||||||
|
nodep->labelNum(++m_labelNum);
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
}
|
||||||
virtual void visit(AstCFunc* nodep, AstNUser*) {
|
virtual void visit(AstCFunc* nodep, AstNUser*) {
|
||||||
if (nodep->dpiImport() || nodep->dpiExportWrapper()) {
|
if (nodep->dpiImport() || nodep->dpiExportWrapper()) {
|
||||||
m_dpis.push_back(nodep);
|
m_dpis.push_back(nodep);
|
||||||
@@ -160,6 +166,7 @@ public:
|
|||||||
m_funcp = NULL;
|
m_funcp = NULL;
|
||||||
m_modp = NULL;
|
m_modp = NULL;
|
||||||
m_coverBins = 0;
|
m_coverBins = 0;
|
||||||
|
m_labelNum = 0;
|
||||||
nodep->accept(*this);
|
nodep->accept(*this);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -135,6 +135,10 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||||||
nodep->rhsp()->iterateAndNext(*this);
|
nodep->rhsp()->iterateAndNext(*this);
|
||||||
if (!m_suppressSemi) puts(";\n");
|
if (!m_suppressSemi) puts(";\n");
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstBreak* nodep, AstNUser*) {
|
||||||
|
putbs("break");
|
||||||
|
if (!m_suppressSemi) puts(";\n");
|
||||||
|
}
|
||||||
virtual void visit(AstSenTree* nodep, AstNUser*) {
|
virtual void visit(AstSenTree* nodep, AstNUser*) {
|
||||||
// AstSenItem is called for dumping in isolation by V3Order
|
// AstSenItem is called for dumping in isolation by V3Order
|
||||||
putfs(nodep,"@(");
|
putfs(nodep,"@(");
|
||||||
@@ -180,6 +184,10 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||||||
puts((string)"// "+nodep->name()+"\n");
|
puts((string)"// "+nodep->name()+"\n");
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstContinue* nodep, AstNUser*) {
|
||||||
|
putbs("continue");
|
||||||
|
if (!m_suppressSemi) puts(";\n");
|
||||||
|
}
|
||||||
virtual void visit(AstCoverDecl*, AstNUser*) {} // N/A
|
virtual void visit(AstCoverDecl*, AstNUser*) {} // N/A
|
||||||
virtual void visit(AstCoverInc*, AstNUser*) {} // N/A
|
virtual void visit(AstCoverInc*, AstNUser*) {} // N/A
|
||||||
virtual void visit(AstCoverToggle*, AstNUser*) {} // N/A
|
virtual void visit(AstCoverToggle*, AstNUser*) {} // N/A
|
||||||
@@ -236,6 +244,14 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||||||
if (nodep->filep()) nodep->filep()->iterateChildren(*this);
|
if (nodep->filep()) nodep->filep()->iterateChildren(*this);
|
||||||
puts(");\n");
|
puts(");\n");
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstJumpGo* nodep, AstNUser*) {
|
||||||
|
putbs("disable "+cvtToStr((void*)(nodep->labelp()))+";\n");
|
||||||
|
}
|
||||||
|
virtual void visit(AstJumpLabel* nodep, AstNUser*) {
|
||||||
|
putbs("begin : "+cvtToStr((void*)(nodep))+"\n");
|
||||||
|
if (nodep->stmtsp()) nodep->stmtsp()->iterateChildren(*this);
|
||||||
|
puts("end\n");
|
||||||
|
}
|
||||||
virtual void visit(AstReadMem* nodep, AstNUser*) {
|
virtual void visit(AstReadMem* nodep, AstNUser*) {
|
||||||
putfs(nodep,nodep->verilogKwd());
|
putfs(nodep,nodep->verilogKwd());
|
||||||
putbs(" (");
|
putbs(" (");
|
||||||
@@ -272,6 +288,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||||||
nodep->condp()->iterateAndNext(*this);
|
nodep->condp()->iterateAndNext(*this);
|
||||||
puts(") begin\n");
|
puts(") begin\n");
|
||||||
nodep->bodysp()->iterateAndNext(*this);
|
nodep->bodysp()->iterateAndNext(*this);
|
||||||
|
nodep->incsp()->iterateAndNext(*this);
|
||||||
nodep->precondsp()->iterateAndNext(*this); // Need to recompute before next loop
|
nodep->precondsp()->iterateAndNext(*this); // Need to recompute before next loop
|
||||||
putfs(nodep,"end\n");
|
putfs(nodep,"end\n");
|
||||||
}
|
}
|
||||||
@@ -287,6 +304,11 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||||||
}
|
}
|
||||||
putqs(nodep,"end\n");
|
putqs(nodep,"end\n");
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstReturn* nodep, AstNUser*) {
|
||||||
|
putfs(nodep,"return ");
|
||||||
|
nodep->lhsp()->iterateAndNext(*this);
|
||||||
|
puts(";\n");
|
||||||
|
}
|
||||||
virtual void visit(AstStop* nodep, AstNUser*) {
|
virtual void visit(AstStop* nodep, AstNUser*) {
|
||||||
putfs(nodep,"$stop;\n");
|
putfs(nodep,"$stop;\n");
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -44,6 +44,7 @@ public:
|
|||||||
// Boolean information we track per-line, but aren't errors
|
// Boolean information we track per-line, but aren't errors
|
||||||
I_COVERAGE, // Coverage is on/off from /*verilator coverage_on/off*/
|
I_COVERAGE, // Coverage is on/off from /*verilator coverage_on/off*/
|
||||||
I_TRACING, // Tracing is on/off from /*verilator tracing_on/off*/
|
I_TRACING, // Tracing is on/off from /*verilator tracing_on/off*/
|
||||||
|
I_DEF_NETTYPE_WIRE, // `default_nettype is WIRE (false=NONE)
|
||||||
// Error codes:
|
// Error codes:
|
||||||
E_MULTITOP, // Error: Multiple top level modules
|
E_MULTITOP, // Error: Multiple top level modules
|
||||||
E_TASKNSVAR, // Error: Task I/O not simple
|
E_TASKNSVAR, // Error: Task I/O not simple
|
||||||
@@ -91,7 +92,7 @@ public:
|
|||||||
// Leading spaces indicate it can't be disabled.
|
// Leading spaces indicate it can't be disabled.
|
||||||
" MIN", " SUPPRESS", " INFO", " FATAL", " FATALSRC", " ERROR",
|
" MIN", " SUPPRESS", " INFO", " FATAL", " FATALSRC", " ERROR",
|
||||||
// Boolean
|
// Boolean
|
||||||
" I_COVERAGE", " I_TRACING",
|
" I_COVERAGE", " I_TRACING", " I_DEF_NETTYPE_WIRE",
|
||||||
// Errors
|
// Errors
|
||||||
"MULTITOP", "TASKNSVAR", "BLKLOOPINIT",
|
"MULTITOP", "TASKNSVAR", "BLKLOOPINIT",
|
||||||
// Warnings
|
// Warnings
|
||||||
|
|||||||
+23
-1
@@ -288,6 +288,7 @@ private:
|
|||||||
// STATE
|
// STATE
|
||||||
LifeState* m_statep; // Current state
|
LifeState* m_statep; // Current state
|
||||||
bool m_sideEffect; // Side effects discovered in assign RHS
|
bool m_sideEffect; // Side effects discovered in assign RHS
|
||||||
|
bool m_noopt; // Disable optimization of variables in this block
|
||||||
|
|
||||||
// LIFE MAP
|
// LIFE MAP
|
||||||
// For each basic block, we'll make a new map of what variables that if/else is changing
|
// For each basic block, we'll make a new map of what variables that if/else is changing
|
||||||
@@ -327,7 +328,7 @@ private:
|
|||||||
V3Const::constifyEdit(nodep->rhsp()); // rhsp may change
|
V3Const::constifyEdit(nodep->rhsp()); // rhsp may change
|
||||||
}
|
}
|
||||||
// Has to be direct assignment without any EXTRACTing.
|
// Has to be direct assignment without any EXTRACTing.
|
||||||
if (nodep->lhsp()->castVarRef() && !m_sideEffect) {
|
if (nodep->lhsp()->castVarRef() && !m_sideEffect && !m_noopt) {
|
||||||
AstVarScope* vscp = nodep->lhsp()->castVarRef()->varScopep();
|
AstVarScope* vscp = nodep->lhsp()->castVarRef()->varScopep();
|
||||||
if (!vscp) nodep->v3fatalSrc("Scope lost on variable");
|
if (!vscp) nodep->v3fatalSrc("Scope lost on variable");
|
||||||
m_lifep->simpleAssign(vscp, nodep);
|
m_lifep->simpleAssign(vscp, nodep);
|
||||||
@@ -388,6 +389,7 @@ private:
|
|||||||
{
|
{
|
||||||
m_lifep = bodyLifep;
|
m_lifep = bodyLifep;
|
||||||
nodep->bodysp()->iterateAndNext(*this);
|
nodep->bodysp()->iterateAndNext(*this);
|
||||||
|
nodep->incsp()->iterateAndNext(*this);
|
||||||
m_lifep = prevLifep;
|
m_lifep = prevLifep;
|
||||||
}
|
}
|
||||||
UINFO(4," joinfor"<<endl);
|
UINFO(4," joinfor"<<endl);
|
||||||
@@ -397,6 +399,25 @@ private:
|
|||||||
delete condLifep;
|
delete condLifep;
|
||||||
delete bodyLifep;
|
delete bodyLifep;
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstJumpLabel* nodep, AstNUser*) {
|
||||||
|
// As with While's we can't predict if a JumpGo will kill us or not
|
||||||
|
// It's worse though as an IF(..., JUMPGO) may change the control flow.
|
||||||
|
// Just don't optimize blocks with labels; they're rare - so far.
|
||||||
|
LifeBlock* prevLifep = m_lifep;
|
||||||
|
LifeBlock* bodyLifep = new LifeBlock (prevLifep, m_statep);
|
||||||
|
bool prev_noopt = m_noopt;
|
||||||
|
{
|
||||||
|
m_lifep = bodyLifep;
|
||||||
|
m_noopt = true;
|
||||||
|
nodep->stmtsp()->iterateAndNext(*this);
|
||||||
|
m_lifep = prevLifep;
|
||||||
|
m_noopt = prev_noopt;
|
||||||
|
}
|
||||||
|
UINFO(4," joinjump"<<endl);
|
||||||
|
// For the next assignments, clear any variables that were read or written in the block
|
||||||
|
bodyLifep->lifeToAbove();
|
||||||
|
delete bodyLifep;
|
||||||
|
}
|
||||||
virtual void visit(AstCCall* nodep, AstNUser*) {
|
virtual void visit(AstCCall* nodep, AstNUser*) {
|
||||||
//UINFO(4," CCALL "<<nodep<<endl);
|
//UINFO(4," CCALL "<<nodep<<endl);
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
@@ -432,6 +453,7 @@ public:
|
|||||||
UINFO(4," LifeVisitor on "<<nodep<<endl);
|
UINFO(4," LifeVisitor on "<<nodep<<endl);
|
||||||
m_statep = statep;
|
m_statep = statep;
|
||||||
m_sideEffect = false;
|
m_sideEffect = false;
|
||||||
|
m_noopt = false;
|
||||||
{
|
{
|
||||||
m_lifep = new LifeBlock (NULL, m_statep);
|
m_lifep = new LifeBlock (NULL, m_statep);
|
||||||
nodep->accept(*this);
|
nodep->accept(*this);
|
||||||
|
|||||||
+7
-1
@@ -185,7 +185,13 @@ private:
|
|||||||
// Create implicit after warning
|
// Create implicit after warning
|
||||||
if (linkVarName(forrefp)) { forrefp=NULL; return; }
|
if (linkVarName(forrefp)) { forrefp=NULL; return; }
|
||||||
if (!forrefp->varp()) {
|
if (!forrefp->varp()) {
|
||||||
if (!noWarn) forrefp->v3warn(IMPLICIT,"Signal definition not found, creating implicitly: "<<forrefp->prettyName());
|
if (!noWarn) {
|
||||||
|
if (forrefp->fileline()->warnIsOff(V3ErrorCode::I_DEF_NETTYPE_WIRE)) {
|
||||||
|
forrefp->v3error("Signal definition not found, and implicit disabled with `default_nettype: "<<forrefp->prettyName());
|
||||||
|
} else {
|
||||||
|
forrefp->v3warn(IMPLICIT,"Signal definition not found, creating implicitly: "<<forrefp->prettyName());
|
||||||
|
}
|
||||||
|
}
|
||||||
AstVar* newp = new AstVar (forrefp->fileline(), AstVarType::WIRE,
|
AstVar* newp = new AstVar (forrefp->fileline(), AstVarType::WIRE,
|
||||||
forrefp->name(), AstLogicPacked(), 1);
|
forrefp->name(), AstLogicPacked(), 1);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,227 @@
|
|||||||
|
//*************************************************************************
|
||||||
|
// DESCRIPTION: Verilator: Replace return/continue with jumps
|
||||||
|
//
|
||||||
|
// Code available from: http://www.veripool.org/verilator
|
||||||
|
//
|
||||||
|
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
//
|
||||||
|
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||||
|
// redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
// Version 2.0.
|
||||||
|
//
|
||||||
|
// Verilator is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
// V3LinkJump's Transformations:
|
||||||
|
//
|
||||||
|
// Each module:
|
||||||
|
// Look for BEGINs
|
||||||
|
// BEGIN(VAR...) -> VAR ... {renamed}
|
||||||
|
// FOR -> WHILEs
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
|
||||||
|
#include "config_build.h"
|
||||||
|
#include "verilatedos.h"
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "V3Global.h"
|
||||||
|
#include "V3LinkJump.h"
|
||||||
|
#include "V3Ast.h"
|
||||||
|
|
||||||
|
//######################################################################
|
||||||
|
|
||||||
|
class LinkJumpVisitor : public AstNVisitor {
|
||||||
|
private:
|
||||||
|
// TYPES
|
||||||
|
typedef vector<AstBegin*> BeginStack;
|
||||||
|
|
||||||
|
// STATE
|
||||||
|
AstModule* m_modp; // Current module
|
||||||
|
AstNodeFTask* m_ftaskp; // Current function/task
|
||||||
|
AstWhile* m_loopp; // Current loop
|
||||||
|
int m_repeatNum; // Repeat counter
|
||||||
|
BeginStack m_beginStack; // All begin blocks above current node
|
||||||
|
|
||||||
|
// METHODS
|
||||||
|
static int debug() {
|
||||||
|
static int level = -1;
|
||||||
|
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
|
||||||
|
return level;
|
||||||
|
}
|
||||||
|
|
||||||
|
AstJumpLabel* findAddLabel(AstNode* nodep, bool endOfIter) {
|
||||||
|
// Put label under given node, and if WHILE optionally at end of iteration
|
||||||
|
UINFO(4,"Create label for "<<nodep<<endl);
|
||||||
|
if (nodep->castJumpLabel()) return nodep->castJumpLabel(); // Done
|
||||||
|
|
||||||
|
AstNode* underp = NULL;
|
||||||
|
bool under_and_next = true;
|
||||||
|
if (nodep->castBegin()) underp = nodep->castBegin()->stmtsp();
|
||||||
|
else if (nodep->castNodeFTask()) underp = nodep->castNodeFTask()->stmtsp();
|
||||||
|
else if (nodep->castWhile()) {
|
||||||
|
if (endOfIter) {
|
||||||
|
// Note we jump to end of bodysp; a FOR loop has its increment under incsp() which we don't skip
|
||||||
|
underp = nodep->castWhile()->bodysp();
|
||||||
|
} else {
|
||||||
|
underp = nodep; under_and_next=false; // IE we skip the entire while
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nodep->v3fatalSrc("Unknown jump point for break/disable/continue");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!underp) {
|
||||||
|
nodep->v3fatalSrc("Break/disable/continue not under expected statement");
|
||||||
|
return NULL;
|
||||||
|
} else if (underp->castJumpLabel()) {
|
||||||
|
return underp->castJumpLabel();
|
||||||
|
} else { // Move underp stuff to be under a new label
|
||||||
|
AstJumpLabel* labelp = new AstJumpLabel(nodep->fileline(), NULL);
|
||||||
|
|
||||||
|
AstNRelinker repHandle;
|
||||||
|
if (under_and_next) underp->unlinkFrBackWithNext(&repHandle);
|
||||||
|
else underp->unlinkFrBack(&repHandle);
|
||||||
|
repHandle.relink(labelp);
|
||||||
|
|
||||||
|
labelp->addStmtsp(underp);
|
||||||
|
// Keep any AstVars under the function not under the new JumpLabel
|
||||||
|
for (AstNode* nextp, *varp=underp; varp; varp = nextp) {
|
||||||
|
nextp = varp->nextp();
|
||||||
|
if (varp->castVar()) {
|
||||||
|
labelp->addPrev(varp->unlinkFrBack());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return labelp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// VISITORS
|
||||||
|
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||||
|
m_modp = nodep;
|
||||||
|
m_repeatNum = 0;
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
m_modp = NULL;
|
||||||
|
}
|
||||||
|
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
||||||
|
m_ftaskp = nodep;
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
m_ftaskp = NULL;
|
||||||
|
}
|
||||||
|
virtual void visit(AstBegin* nodep, AstNUser*) {
|
||||||
|
UINFO(8," "<<nodep<<endl);
|
||||||
|
m_beginStack.push_back(nodep);
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
m_beginStack.pop_back();
|
||||||
|
}
|
||||||
|
virtual void visit(AstRepeat* nodep, AstNUser*) {
|
||||||
|
// So later optimizations don't need to deal with them,
|
||||||
|
// REPEAT(count,body) -> loop=count,WHILE(loop>0) { body, loop-- }
|
||||||
|
// Note var can be signed or unsigned based on original number.
|
||||||
|
AstNode* countp = nodep->countp()->unlinkFrBackWithNext();
|
||||||
|
string name = string("__Vrepeat")+cvtToStr(m_repeatNum++);
|
||||||
|
// Spec says value is integral, if negative is ignored
|
||||||
|
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP, name,
|
||||||
|
AstLogicPacked(), 32);
|
||||||
|
varp->isSigned(true);
|
||||||
|
varp->dtypep()->isSigned(true);
|
||||||
|
m_modp->addStmtp(varp);
|
||||||
|
AstNode* initsp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
|
||||||
|
countp);
|
||||||
|
AstNode* decp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
|
||||||
|
new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
|
||||||
|
new AstConst(nodep->fileline(), 1)));
|
||||||
|
AstNode* zerosp = new AstConst(nodep->fileline(), 0); zerosp->isSigned(true);
|
||||||
|
AstNode* condp = new AstGtS(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
|
||||||
|
zerosp);
|
||||||
|
AstNode* bodysp = nodep->bodysp(); if (bodysp) bodysp->unlinkFrBackWithNext();
|
||||||
|
AstNode* newp = new AstWhile(nodep->fileline(),
|
||||||
|
condp,
|
||||||
|
bodysp,
|
||||||
|
decp);
|
||||||
|
initsp = initsp->addNext(newp);
|
||||||
|
newp = initsp;
|
||||||
|
nodep->replaceWith(newp);
|
||||||
|
nodep->deleteTree(); nodep=NULL;
|
||||||
|
}
|
||||||
|
virtual void visit(AstWhile* nodep, AstNUser*) {
|
||||||
|
// Don't need to track AstRepeat/AstFor as they have already been converted
|
||||||
|
AstWhile* lastLoopp = m_loopp;
|
||||||
|
m_loopp = nodep;
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
m_loopp = lastLoopp;
|
||||||
|
}
|
||||||
|
virtual void visit(AstReturn* nodep, AstNUser*) {
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
AstFunc* funcp = m_ftaskp->castFunc();
|
||||||
|
if (!m_ftaskp) { nodep->v3error("Return isn't underneath a task or function"); }
|
||||||
|
else if (funcp && !nodep->lhsp()) { nodep->v3error("Return underneath a function should have return value"); }
|
||||||
|
else if (!funcp && nodep->lhsp()) { nodep->v3error("Return underneath a task shouldn't have return value"); }
|
||||||
|
else {
|
||||||
|
if (funcp && nodep->lhsp()) {
|
||||||
|
// Set output variable to return value
|
||||||
|
nodep->addPrev(new AstAssign(nodep->fileline(),
|
||||||
|
new AstVarRef(nodep->fileline(), funcp->fvarp()->castVar(), true),
|
||||||
|
nodep->lhsp()->unlinkFrBackWithNext()));
|
||||||
|
}
|
||||||
|
// Jump to the end of the function call
|
||||||
|
AstJumpLabel* labelp = findAddLabel(m_ftaskp, false);
|
||||||
|
nodep->addPrev(new AstJumpGo(nodep->fileline(), labelp));
|
||||||
|
}
|
||||||
|
nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL;
|
||||||
|
}
|
||||||
|
virtual void visit(AstBreak* nodep, AstNUser*) {
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
if (!m_loopp) { nodep->v3error("break isn't underneath a loop"); }
|
||||||
|
else {
|
||||||
|
// Jump to the end of the loop
|
||||||
|
AstJumpLabel* labelp = findAddLabel(m_loopp, false);
|
||||||
|
nodep->addNextHere(new AstJumpGo(nodep->fileline(), labelp));
|
||||||
|
}
|
||||||
|
nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL;
|
||||||
|
}
|
||||||
|
virtual void visit(AstContinue* nodep, AstNUser*) {
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
if (!m_loopp) { nodep->v3error("continue isn't underneath a loop"); }
|
||||||
|
else {
|
||||||
|
// Jump to the end of this iteration
|
||||||
|
// If a "for" loop then need to still do the post-loop increment
|
||||||
|
AstJumpLabel* labelp = findAddLabel(m_loopp, true);
|
||||||
|
nodep->addNextHere(new AstJumpGo(nodep->fileline(), labelp));
|
||||||
|
}
|
||||||
|
nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
// CONSTUCTORS
|
||||||
|
LinkJumpVisitor(AstNetlist* nodep) {
|
||||||
|
m_modp = NULL;
|
||||||
|
m_ftaskp = NULL;
|
||||||
|
m_loopp = NULL;
|
||||||
|
m_repeatNum = 0;
|
||||||
|
nodep->accept(*this);
|
||||||
|
}
|
||||||
|
virtual ~LinkJumpVisitor() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
//######################################################################
|
||||||
|
// Task class functions
|
||||||
|
|
||||||
|
void V3LinkJump::linkJump(AstNetlist* nodep) {
|
||||||
|
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||||
|
LinkJumpVisitor bvisitor (nodep);
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
// -*- C++ -*-
|
||||||
|
//*************************************************************************
|
||||||
|
// DESCRIPTION: Verilator: Replace return/continue with jumps
|
||||||
|
//
|
||||||
|
// Code available from: http://www.veripool.org/verilator
|
||||||
|
//
|
||||||
|
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
//
|
||||||
|
// Copyright 2003-2010 by Wilson Snyder. This program is free software; you can
|
||||||
|
// redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
// Version 2.0.
|
||||||
|
//
|
||||||
|
// Verilator is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
|
||||||
|
#ifndef _V3LINKJUMP_H_
|
||||||
|
#define _V3LINKJUMP_H_ 1
|
||||||
|
#include "config_build.h"
|
||||||
|
#include "verilatedos.h"
|
||||||
|
#include "V3Error.h"
|
||||||
|
#include "V3Ast.h"
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
class V3LinkJump {
|
||||||
|
public:
|
||||||
|
static void linkJump(AstNetlist* nodep);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // Guard
|
||||||
@@ -75,6 +75,13 @@ private:
|
|||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
m_modp = NULL;
|
m_modp = NULL;
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstInitial* nodep, AstNUser*) {
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
// Initial assignments under function/tasks can just be simple assignments without the initial
|
||||||
|
if (m_ftaskp) {
|
||||||
|
nodep->replaceWith(nodep->bodysp()->unlinkFrBackWithNext()); nodep=NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
virtual void visit(AstVAssert* nodep, AstNUser*) {
|
virtual void visit(AstVAssert* nodep, AstNUser*) {
|
||||||
if (m_assertp) nodep->v3error("Assert not allowed under another assert");
|
if (m_assertp) nodep->v3error("Assert not allowed under another assert");
|
||||||
m_assertp = nodep;
|
m_assertp = nodep;
|
||||||
|
|||||||
+38
-15
@@ -941,28 +941,51 @@ void OrderVisitor::processBrokeLoop() {
|
|||||||
// Clock propagation
|
// Clock propagation
|
||||||
|
|
||||||
void OrderVisitor::processInputs() {
|
void OrderVisitor::processInputs() {
|
||||||
m_graph.userClearVertices(); // Vertex::user() // true if added as begin/end
|
m_graph.userClearVertices(); // Vertex::user() // true if processed
|
||||||
|
// Start at input vertex, process from input-to-output order
|
||||||
|
m_inputsVxp->isFromInput(true); // By definition
|
||||||
processInputsIterate(m_inputsVxp);
|
processInputsIterate(m_inputsVxp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OrderVisitor::processInputsIterate(OrderEitherVertex* vertexp) {
|
void OrderVisitor::processInputsIterate(OrderEitherVertex* vertexp) {
|
||||||
// Propagate PrimaryIn through simple assignments
|
// Propagate PrimaryIn through simple assignments
|
||||||
if (vertexp->user()) return; // Already processed
|
if (vertexp->user()) return; // Already processed
|
||||||
//UINFO(9," InIt "<<vertexp<<endl);
|
if (0 && debug()>=9) {
|
||||||
vertexp->user(true);
|
UINFO(9," InIt "<<vertexp<<endl);
|
||||||
if (OrderVarStdVertex* vvertexp = dynamic_cast<OrderVarStdVertex*>(vertexp)) {
|
if (OrderLogicVertex* vvertexp = dynamic_cast<OrderLogicVertex*>(vertexp)) {
|
||||||
vvertexp->isFromInput(true);
|
vvertexp->nodep()->dumpTree(cout,"- TT: ");
|
||||||
}
|
|
||||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
|
||||||
OrderEitherVertex* toVertexp = (OrderEitherVertex*)edgep->top();
|
|
||||||
if (OrderVarStdVertex* vvertexp = dynamic_cast<OrderVarStdVertex*>(toVertexp)) {
|
|
||||||
processInputsIterate(vvertexp);
|
|
||||||
}
|
}
|
||||||
if (OrderLogicVertex* vvertexp = dynamic_cast<OrderLogicVertex*>(toVertexp)) {
|
}
|
||||||
if (AstNodeAssign* nodep = vvertexp->nodep()->castNodeAssign()) {
|
vertexp->user(true); // Processing
|
||||||
if (nodep->lhsp()->castVarRef()
|
// First handle all inputs to this vertex, in most cases they'll be already processed earlier
|
||||||
&& nodep->rhsp()->castVarRef()) {
|
// Also, determine if this vertex is an input
|
||||||
UINFO(9," Input reassignment: "<<vvertexp<<endl);
|
int inonly = 1; // 0=no, 1=maybe, 2=yes until a no
|
||||||
|
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) {
|
||||||
|
OrderEitherVertex* frVertexp = (OrderEitherVertex*)edgep->fromp();
|
||||||
|
processInputsIterate(frVertexp);
|
||||||
|
if (frVertexp->isFromInput()) {
|
||||||
|
if (inonly==1) inonly = 2;
|
||||||
|
} else if (dynamic_cast<OrderVarPostVertex*>(frVertexp)) {
|
||||||
|
// Ignore post assignments, just for ordering
|
||||||
|
} else {
|
||||||
|
//UINFO(9," InItStopDueTo "<<frVertexp<<endl);
|
||||||
|
inonly = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (inonly == 2) { // Set it. Note may have already been set earlier, too
|
||||||
|
UINFO(9," Input reassignment: "<<vertexp<<endl);
|
||||||
|
vertexp->isFromInput(true);
|
||||||
|
}
|
||||||
|
// If we're still an input, process all targets of this vertex
|
||||||
|
if (vertexp->isFromInput()) {
|
||||||
|
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||||
|
OrderEitherVertex* toVertexp = (OrderEitherVertex*)edgep->top();
|
||||||
|
if (OrderVarStdVertex* vvertexp = dynamic_cast<OrderVarStdVertex*>(toVertexp)) {
|
||||||
|
processInputsIterate(vvertexp);
|
||||||
|
}
|
||||||
|
if (OrderLogicVertex* vvertexp = dynamic_cast<OrderLogicVertex*>(toVertexp)) {
|
||||||
|
if (vvertexp->nodep()->castNodeAssign()) {
|
||||||
processInputsIterate(vvertexp);
|
processInputsIterate(vvertexp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-6
@@ -132,10 +132,11 @@ class OrderEitherVertex : public V3GraphVertex {
|
|||||||
AstScope* m_scopep; // Scope the vertex is in
|
AstScope* m_scopep; // Scope the vertex is in
|
||||||
AstSenTree* m_domainp; // Clock domain (NULL = to be computed as we iterate)
|
AstSenTree* m_domainp; // Clock domain (NULL = to be computed as we iterate)
|
||||||
OrderLoopId m_inLoop; // Loop number vertex is in
|
OrderLoopId m_inLoop; // Loop number vertex is in
|
||||||
|
bool m_isFromInput; // From input, or derrived therefrom (conservatively false)
|
||||||
public:
|
public:
|
||||||
OrderEitherVertex(V3Graph* graphp, AstScope* scopep, AstSenTree* domainp)
|
OrderEitherVertex(V3Graph* graphp, AstScope* scopep, AstSenTree* domainp)
|
||||||
: V3GraphVertex(graphp), m_scopep(scopep), m_domainp(domainp)
|
: V3GraphVertex(graphp), m_scopep(scopep), m_domainp(domainp)
|
||||||
, m_inLoop(LOOPID_UNKNOWN) {
|
, m_inLoop(LOOPID_UNKNOWN), m_isFromInput(false) {
|
||||||
}
|
}
|
||||||
virtual ~OrderEitherVertex() {}
|
virtual ~OrderEitherVertex() {}
|
||||||
// Methods
|
// Methods
|
||||||
@@ -148,12 +149,16 @@ public:
|
|||||||
AstSenTree* domainp() const { return m_domainp; }
|
AstSenTree* domainp() const { return m_domainp; }
|
||||||
OrderLoopId inLoop() const { return m_inLoop; }
|
OrderLoopId inLoop() const { return m_inLoop; }
|
||||||
void inLoop(OrderLoopId inloop) { m_inLoop = inloop; }
|
void inLoop(OrderLoopId inloop) { m_inLoop = inloop; }
|
||||||
|
void isFromInput(bool flag) { m_isFromInput=flag; }
|
||||||
|
bool isFromInput() const { return m_isFromInput; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class OrderInputsVertex : public OrderEitherVertex {
|
class OrderInputsVertex : public OrderEitherVertex {
|
||||||
public:
|
public:
|
||||||
OrderInputsVertex(V3Graph* graphp, AstSenTree* domainp)
|
OrderInputsVertex(V3Graph* graphp, AstSenTree* domainp)
|
||||||
: OrderEitherVertex(graphp, NULL, domainp) {}
|
: OrderEitherVertex(graphp, NULL, domainp) {
|
||||||
|
isFromInput(true); // By definition
|
||||||
|
}
|
||||||
virtual ~OrderInputsVertex() {}
|
virtual ~OrderInputsVertex() {}
|
||||||
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_INPUTS; }
|
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_INPUTS; }
|
||||||
virtual string name() const { return "*INPUTS*"; }
|
virtual string name() const { return "*INPUTS*"; }
|
||||||
@@ -195,11 +200,10 @@ class OrderVarVertex : public OrderEitherVertex {
|
|||||||
AstVarScope* m_varScp;
|
AstVarScope* m_varScp;
|
||||||
OrderVarVertex* m_pilNewVertexp; // for processInsLoopNewVar
|
OrderVarVertex* m_pilNewVertexp; // for processInsLoopNewVar
|
||||||
bool m_isClock; // Used as clock
|
bool m_isClock; // Used as clock
|
||||||
bool m_isFromInput; // From input, or derrived therefrom (conservatively false)
|
|
||||||
public:
|
public:
|
||||||
OrderVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
|
OrderVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
|
||||||
: OrderEitherVertex(graphp, scopep, NULL), m_varScp(varScp)
|
: OrderEitherVertex(graphp, scopep, NULL), m_varScp(varScp)
|
||||||
, m_pilNewVertexp(NULL), m_isClock(false), m_isFromInput(false)
|
, m_pilNewVertexp(NULL), m_isClock(false)
|
||||||
{}
|
{}
|
||||||
virtual ~OrderVarVertex() {}
|
virtual ~OrderVarVertex() {}
|
||||||
virtual OrderVarVertex* clone (V3Graph* graphp) const = 0;
|
virtual OrderVarVertex* clone (V3Graph* graphp) const = 0;
|
||||||
@@ -208,8 +212,6 @@ public:
|
|||||||
AstVarScope* varScp() const { return m_varScp; }
|
AstVarScope* varScp() const { return m_varScp; }
|
||||||
void isClock(bool flag) { m_isClock=flag; }
|
void isClock(bool flag) { m_isClock=flag; }
|
||||||
bool isClock() const { return m_isClock; }
|
bool isClock() const { return m_isClock; }
|
||||||
void isFromInput(bool flag) { m_isFromInput=flag; }
|
|
||||||
bool isFromInput() const { return m_isFromInput; }
|
|
||||||
OrderVarVertex* pilNewVertexp() const { return m_pilNewVertexp; }
|
OrderVarVertex* pilNewVertexp() const { return m_pilNewVertexp; }
|
||||||
void pilNewVertexp (OrderVarVertex* vertexp) { m_pilNewVertexp = vertexp; }
|
void pilNewVertexp (OrderVarVertex* vertexp) { m_pilNewVertexp = vertexp; }
|
||||||
};
|
};
|
||||||
|
|||||||
+14
-3
@@ -84,6 +84,11 @@
|
|||||||
# define yyerrorf V3PreLexerrorf
|
# define yyerrorf V3PreLexerrorf
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef yyourleng
|
||||||
|
# define yyourleng V3PreLexourleng
|
||||||
|
# define yyourtext V3PreLexourtext
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef YY_BUFFER_STATE
|
#ifndef YY_BUFFER_STATE
|
||||||
struct yy_buffer_state;
|
struct yy_buffer_state;
|
||||||
typedef struct yy_buffer_state *YY_BUFFER_STATE;
|
typedef struct yy_buffer_state *YY_BUFFER_STATE;
|
||||||
@@ -92,17 +97,23 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE;
|
|||||||
|
|
||||||
extern int yylex();
|
extern int yylex();
|
||||||
extern void yyrestart(FILE*);
|
extern void yyrestart(FILE*);
|
||||||
extern char* yytext;
|
|
||||||
extern int yyleng;
|
// Accessors, because flex keeps changing the type of yyleng
|
||||||
|
extern char* yyourtext();
|
||||||
|
extern size_t yyourleng();
|
||||||
|
extern void yyourtext(const char* textp, size_t size); // Must call with static
|
||||||
|
|
||||||
YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size );
|
YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size );
|
||||||
void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer );
|
void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer );
|
||||||
void yy_delete_buffer( YY_BUFFER_STATE b );
|
void yy_delete_buffer( YY_BUFFER_STATE b );
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// Class entry for each per-lexter state
|
|
||||||
|
|
||||||
#define KEEPCMT_SUB 2
|
#define KEEPCMT_SUB 2
|
||||||
|
|
||||||
|
//======================================================================
|
||||||
|
// Class entry for each per-lexter state
|
||||||
|
|
||||||
class V3PreLex {
|
class V3PreLex {
|
||||||
public: // Used only by V3PreLex.cpp and V3PreProc.cpp
|
public: // Used only by V3PreLex.cpp and V3PreProc.cpp
|
||||||
FileLine* m_curFilelinep; // Current processing point
|
FileLine* m_curFilelinep; // Current processing point
|
||||||
|
|||||||
@@ -33,6 +33,11 @@ V3PreLex* V3PreLex::s_currentLexp = NULL; // Current lexing point
|
|||||||
|
|
||||||
#define LEXP V3PreLex::s_currentLexp
|
#define LEXP V3PreLex::s_currentLexp
|
||||||
|
|
||||||
|
// Accessors, because flex keeps changing the type of yyleng
|
||||||
|
char* yyourtext() { return yytext; }
|
||||||
|
size_t yyourleng() { return yyleng; }
|
||||||
|
void yyourtext(const char* textp, size_t size) { yytext=(char*)textp; yyleng=size; }
|
||||||
|
|
||||||
// Prevent conflicts from perl version
|
// Prevent conflicts from perl version
|
||||||
static void linenoInc() {LEXP->incLineno();}
|
static void linenoInc() {LEXP->incLineno();}
|
||||||
static bool optPsl() { return V3PreProc::optPsl(); }
|
static bool optPsl() { return V3PreProc::optPsl(); }
|
||||||
@@ -154,6 +159,7 @@ psl [p]sl
|
|||||||
|
|
||||||
/* Reading definition value */
|
/* Reading definition value */
|
||||||
<DEFVAL>"/*" { LEXP->m_defCmtSlash=false; yy_push_state(DEFCMT); yymore(); } /* Special comment parser */
|
<DEFVAL>"/*" { LEXP->m_defCmtSlash=false; yy_push_state(DEFCMT); yymore(); } /* Special comment parser */
|
||||||
|
<DEFVAL>"//"[^\n\r]*[\\]{crnl} { linenoInc(); appendDefValue((char*)"\n",1); } /* Spec says // not part of define value */
|
||||||
<DEFVAL>"//"[^\n\r]* { return (VP_COMMENT);}
|
<DEFVAL>"//"[^\n\r]* { return (VP_COMMENT);}
|
||||||
<DEFVAL>{drop} { }
|
<DEFVAL>{drop} { }
|
||||||
<DEFVAL><<EOF>> { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); } /* Technically illegal, but people complained */
|
<DEFVAL><<EOF>> { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); } /* Technically illegal, but people complained */
|
||||||
|
|||||||
+30
-25
@@ -71,7 +71,7 @@ class V3DefineRef {
|
|||||||
string m_name; // Define last name being defined
|
string m_name; // Define last name being defined
|
||||||
string m_params; // Define parameter list for next expansion
|
string m_params; // Define parameter list for next expansion
|
||||||
string m_nextarg; // String being built for next argument
|
string m_nextarg; // String being built for next argument
|
||||||
int m_parenLevel; // Parenthesis counting inside def args
|
int m_parenLevel; // Parenthesis counting inside def args (for PARENT not child)
|
||||||
|
|
||||||
vector<string> m_args; // List of define arguments
|
vector<string> m_args; // List of define arguments
|
||||||
public:
|
public:
|
||||||
@@ -80,9 +80,10 @@ public:
|
|||||||
string nextarg() const { return m_nextarg; }
|
string nextarg() const { return m_nextarg; }
|
||||||
void nextarg(const string& value) { m_nextarg = value; }
|
void nextarg(const string& value) { m_nextarg = value; }
|
||||||
int parenLevel() const { return m_parenLevel; }
|
int parenLevel() const { return m_parenLevel; }
|
||||||
|
void parenLevel(int value) { m_parenLevel = value; }
|
||||||
vector<string>& args() { return m_args; }
|
vector<string>& args() { return m_args; }
|
||||||
V3DefineRef(const string& name, const string& params, int pl)
|
V3DefineRef(const string& name, const string& params)
|
||||||
: m_name(name), m_params(params), m_parenLevel(pl) {}
|
: m_name(name), m_params(params), m_parenLevel(0) {}
|
||||||
~V3DefineRef() {}
|
~V3DefineRef() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -510,7 +511,9 @@ string V3PreProcImp::defineSubst(V3DefineRef* refp) {
|
|||||||
if (*cp=='"') quote=!quote;
|
if (*cp=='"') quote=!quote;
|
||||||
if (*cp) token += *cp;
|
if (*cp) token += *cp;
|
||||||
}
|
}
|
||||||
if (refp->args().size() > numArgs) {
|
if (refp->args().size() > numArgs
|
||||||
|
// `define X() is ok to call with nothing
|
||||||
|
&& !(refp->args().size()==1 && numArgs==0 && trimWhitespace(refp->args()[0],false)=="")) {
|
||||||
fileline()->v3error("Define passed too many arguments: "+refp->name()+"\n");
|
fileline()->v3error("Define passed too many arguments: "+refp->name()+"\n");
|
||||||
return " `"+refp->name()+" ";
|
return " `"+refp->name()+" ";
|
||||||
}
|
}
|
||||||
@@ -680,7 +683,7 @@ int V3PreProcImp::getRawToken() {
|
|||||||
if (m_lineAdd) {
|
if (m_lineAdd) {
|
||||||
m_lineAdd--;
|
m_lineAdd--;
|
||||||
m_rawAtBol = true;
|
m_rawAtBol = true;
|
||||||
yytext=(char*)"\n"; yyleng=1;
|
yyourtext("\n",1);
|
||||||
if (debug()) debugToken(VP_WHITE, "LNA");
|
if (debug()) debugToken(VP_WHITE, "LNA");
|
||||||
return (VP_WHITE);
|
return (VP_WHITE);
|
||||||
}
|
}
|
||||||
@@ -692,11 +695,11 @@ int V3PreProcImp::getRawToken() {
|
|||||||
if (!m_rawAtBol) rtncmt = "\n"+rtncmt;
|
if (!m_rawAtBol) rtncmt = "\n"+rtncmt;
|
||||||
m_lineCmtNl = false;
|
m_lineCmtNl = false;
|
||||||
}
|
}
|
||||||
yytext=(char*)rtncmt.c_str(); yyleng=rtncmt.length();
|
yyourtext(rtncmt.c_str(), rtncmt.length());
|
||||||
m_lineCmt = "";
|
m_lineCmt = "";
|
||||||
if (yyleng) m_rawAtBol = (yytext[yyleng-1]=='\n');
|
if (yyourleng()) m_rawAtBol = (yyourtext()[yyourleng()-1]=='\n');
|
||||||
if (m_state==ps_DEFVALUE) {
|
if (m_state==ps_DEFVALUE) {
|
||||||
V3PreLex::s_currentLexp->appendDefValue(yytext,yyleng);
|
V3PreLex::s_currentLexp->appendDefValue(yyourtext(),yyourleng());
|
||||||
goto next_tok;
|
goto next_tok;
|
||||||
} else {
|
} else {
|
||||||
if (debug()) debugToken(VP_TEXT, "LCM");
|
if (debug()) debugToken(VP_TEXT, "LCM");
|
||||||
@@ -718,14 +721,14 @@ int V3PreProcImp::getRawToken() {
|
|||||||
goto next_tok; // Parse parent, or find the EOF.
|
goto next_tok; // Parse parent, or find the EOF.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (yyleng) m_rawAtBol = (yytext[yyleng-1]=='\n');
|
if (yyourleng()) m_rawAtBol = (yyourtext()[yyourleng()-1]=='\n');
|
||||||
return tok;
|
return tok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void V3PreProcImp::debugToken(int tok, const char* cmtp) {
|
void V3PreProcImp::debugToken(int tok, const char* cmtp) {
|
||||||
if (debug()>4) {
|
if (debug()>4) {
|
||||||
string buf = string (yytext, yyleng);
|
string buf = string (yyourtext(), yyourleng());
|
||||||
string::size_type pos;
|
string::size_type pos;
|
||||||
while ((pos=buf.find("\n")) != string::npos) { buf.replace(pos, 1, "\\n"); }
|
while ((pos=buf.find("\n")) != string::npos) { buf.replace(pos, 1, "\\n"); }
|
||||||
while ((pos=buf.find("\r")) != string::npos) { buf.replace(pos, 1, "\\r"); }
|
while ((pos=buf.find("\r")) != string::npos) { buf.replace(pos, 1, "\\r"); }
|
||||||
@@ -750,7 +753,7 @@ int V3PreProcImp::getToken() {
|
|||||||
if (tok==VP_COMMENT) {
|
if (tok==VP_COMMENT) {
|
||||||
if (!m_off) {
|
if (!m_off) {
|
||||||
if (m_lexp->m_keepComments == KEEPCMT_SUB) {
|
if (m_lexp->m_keepComments == KEEPCMT_SUB) {
|
||||||
string rtn; rtn.assign(yytext,yyleng);
|
string rtn; rtn.assign(yyourtext(),yyourleng());
|
||||||
comment(rtn);
|
comment(rtn);
|
||||||
} else {
|
} else {
|
||||||
return (tok);
|
return (tok);
|
||||||
@@ -759,7 +762,7 @@ int V3PreProcImp::getToken() {
|
|||||||
// We're off or processed the comment specially. If there are newlines
|
// We're off or processed the comment specially. If there are newlines
|
||||||
// in it, we also return the newlines as TEXT so that the linenumber
|
// in it, we also return the newlines as TEXT so that the linenumber
|
||||||
// count is maintained for downstream tools
|
// count is maintained for downstream tools
|
||||||
for (int len=0; len<yyleng; len++) { if (yytext[len]=='\n') m_lineAdd++; }
|
for (int len=0; len<yyourleng(); len++) { if (yyourtext()[len]=='\n') m_lineAdd++; }
|
||||||
goto next_tok;
|
goto next_tok;
|
||||||
}
|
}
|
||||||
if (tok==VP_LINE) {
|
if (tok==VP_LINE) {
|
||||||
@@ -774,7 +777,7 @@ int V3PreProcImp::getToken() {
|
|||||||
case ps_DEFNAME: {
|
case ps_DEFNAME: {
|
||||||
if (tok==VP_SYMBOL) {
|
if (tok==VP_SYMBOL) {
|
||||||
m_state = ps_TOP;
|
m_state = ps_TOP;
|
||||||
m_lastSym.assign(yytext,yyleng);
|
m_lastSym.assign(yyourtext(),yyourleng());
|
||||||
if (m_stateFor==VP_IFDEF
|
if (m_stateFor==VP_IFDEF
|
||||||
|| m_stateFor==VP_IFNDEF) {
|
|| m_stateFor==VP_IFNDEF) {
|
||||||
bool enable = defExists(m_lastSym);
|
bool enable = defExists(m_lastSym);
|
||||||
@@ -876,11 +879,11 @@ int V3PreProcImp::getToken() {
|
|||||||
m_state = ps_TOP;
|
m_state = ps_TOP;
|
||||||
// DEFVALUE is terminated by a return, but lex can't return both tokens.
|
// DEFVALUE is terminated by a return, but lex can't return both tokens.
|
||||||
// Thus, we emit a return here.
|
// Thus, we emit a return here.
|
||||||
yytext=(char*)(newlines.c_str()); yyleng=newlines.length();
|
yyourtext(newlines.c_str(), newlines.length());
|
||||||
return(VP_WHITE);
|
return(VP_WHITE);
|
||||||
}
|
}
|
||||||
case ps_DEFPAREN: {
|
case ps_DEFPAREN: {
|
||||||
if (tok==VP_TEXT && yyleng==1 && yytext[0]=='(') {
|
if (tok==VP_TEXT && yyourleng()==1 && yyourtext()[0]=='(') {
|
||||||
m_state = ps_DEFARG;
|
m_state = ps_DEFARG;
|
||||||
goto next_tok;
|
goto next_tok;
|
||||||
} else {
|
} else {
|
||||||
@@ -896,13 +899,13 @@ int V3PreProcImp::getToken() {
|
|||||||
V3DefineRef* refp = &(m_defRefs.top());
|
V3DefineRef* refp = &(m_defRefs.top());
|
||||||
refp->nextarg(refp->nextarg()+m_lexp->m_defValue); m_lexp->m_defValue="";
|
refp->nextarg(refp->nextarg()+m_lexp->m_defValue); m_lexp->m_defValue="";
|
||||||
UINFO(4,"defarg++ "<<refp->nextarg()<<endl);
|
UINFO(4,"defarg++ "<<refp->nextarg()<<endl);
|
||||||
if (tok==VP_DEFARG && yyleng==1 && yytext[0]==',') {
|
if (tok==VP_DEFARG && yyourleng()==1 && yyourtext()[0]==',') {
|
||||||
refp->args().push_back(refp->nextarg());
|
refp->args().push_back(refp->nextarg());
|
||||||
m_state = ps_DEFARG;
|
m_state = ps_DEFARG;
|
||||||
m_lexp->pushStateDefArg(1);
|
m_lexp->pushStateDefArg(1);
|
||||||
refp->nextarg("");
|
refp->nextarg("");
|
||||||
goto next_tok;
|
goto next_tok;
|
||||||
} else if (tok==VP_DEFARG && yyleng==1 && yytext[0]==')') {
|
} else if (tok==VP_DEFARG && yyourleng()==1 && yyourtext()[0]==')') {
|
||||||
refp->args().push_back(refp->nextarg());
|
refp->args().push_back(refp->nextarg());
|
||||||
string out = defineSubst(refp);
|
string out = defineSubst(refp);
|
||||||
// Substitute in and prepare for next action
|
// Substitute in and prepare for next action
|
||||||
@@ -929,7 +932,7 @@ int V3PreProcImp::getToken() {
|
|||||||
// we'll append it when we push the argument.
|
// we'll append it when we push the argument.
|
||||||
break;
|
break;
|
||||||
} else if (tok==VP_SYMBOL || tok==VP_STRING || VP_TEXT || VP_WHITE || VP_PSL) {
|
} else if (tok==VP_SYMBOL || tok==VP_STRING || VP_TEXT || VP_WHITE || VP_PSL) {
|
||||||
string rtn; rtn.assign(yytext,yyleng);
|
string rtn; rtn.assign(yyourtext(),yyourleng());
|
||||||
refp->nextarg(refp->nextarg()+rtn);
|
refp->nextarg(refp->nextarg()+rtn);
|
||||||
goto next_tok;
|
goto next_tok;
|
||||||
} else {
|
} else {
|
||||||
@@ -941,7 +944,7 @@ int V3PreProcImp::getToken() {
|
|||||||
case ps_INCNAME: {
|
case ps_INCNAME: {
|
||||||
if (tok==VP_STRING) {
|
if (tok==VP_STRING) {
|
||||||
m_state = ps_TOP;
|
m_state = ps_TOP;
|
||||||
m_lastSym.assign(yytext,yyleng);
|
m_lastSym.assign(yyourtext(),yyourleng());
|
||||||
UINFO(4,"Include "<<m_lastSym<<endl);
|
UINFO(4,"Include "<<m_lastSym<<endl);
|
||||||
// Drop leading and trailing quotes.
|
// Drop leading and trailing quotes.
|
||||||
m_lastSym.erase(0,1);
|
m_lastSym.erase(0,1);
|
||||||
@@ -949,7 +952,7 @@ int V3PreProcImp::getToken() {
|
|||||||
include(m_lastSym);
|
include(m_lastSym);
|
||||||
goto next_tok;
|
goto next_tok;
|
||||||
}
|
}
|
||||||
else if (tok==VP_TEXT && yyleng==1 && yytext[0]=='<') {
|
else if (tok==VP_TEXT && yyourleng()==1 && yyourtext()[0]=='<') {
|
||||||
// include <filename>
|
// include <filename>
|
||||||
m_state = ps_INCNAME; // Still
|
m_state = ps_INCNAME; // Still
|
||||||
m_lexp->pushStateIncFilename();
|
m_lexp->pushStateIncFilename();
|
||||||
@@ -969,7 +972,7 @@ int V3PreProcImp::getToken() {
|
|||||||
if (tok==VP_STRING) {
|
if (tok==VP_STRING) {
|
||||||
m_state = ps_TOP;
|
m_state = ps_TOP;
|
||||||
if (!m_off) {
|
if (!m_off) {
|
||||||
m_lastSym.assign(yytext,yyleng);
|
m_lastSym.assign(yyourtext(),yyourleng());
|
||||||
fileline()->v3error(m_lastSym);
|
fileline()->v3error(m_lastSym);
|
||||||
}
|
}
|
||||||
goto next_tok;
|
goto next_tok;
|
||||||
@@ -1022,7 +1025,7 @@ int V3PreProcImp::getToken() {
|
|||||||
|
|
||||||
case VP_DEFREF: {
|
case VP_DEFREF: {
|
||||||
if (!m_off) {
|
if (!m_off) {
|
||||||
string name; name.append(yytext+1,yyleng-1);
|
string name; name.append(yyourtext()+1,yyourleng()-1);
|
||||||
UINFO(4,"DefRef "<<name<<endl);
|
UINFO(4,"DefRef "<<name<<endl);
|
||||||
if (m_defDepth++ > V3PreProc::DEFINE_RECURSION_LEVEL_MAX) {
|
if (m_defDepth++ > V3PreProc::DEFINE_RECURSION_LEVEL_MAX) {
|
||||||
fileline()->v3error("Recursive `define substitution: `"+name);
|
fileline()->v3error("Recursive `define substitution: `"+name);
|
||||||
@@ -1054,7 +1057,9 @@ int V3PreProcImp::getToken() {
|
|||||||
}
|
}
|
||||||
else { // Found, with parameters
|
else { // Found, with parameters
|
||||||
UINFO(4,"Defref `"<<name<<" => parameterized"<<endl);
|
UINFO(4,"Defref `"<<name<<" => parameterized"<<endl);
|
||||||
m_defRefs.push(V3DefineRef(name, params, m_lexp->m_parenLevel));
|
// The CURRENT macro needs the paren saved, it's not a property of the child macro
|
||||||
|
if (!m_defRefs.empty()) m_defRefs.top().parenLevel(m_lexp->m_parenLevel);
|
||||||
|
m_defRefs.push(V3DefineRef(name, params));
|
||||||
m_state = ps_DEFPAREN; m_stateFor = tok;
|
m_state = ps_DEFPAREN; m_stateFor = tok;
|
||||||
m_lexp->pushStateDefArg(0);
|
m_lexp->pushStateDefArg(0);
|
||||||
goto next_tok;
|
goto next_tok;
|
||||||
@@ -1107,7 +1112,7 @@ string V3PreProcImp::getline() {
|
|||||||
while (NULL==(rtnp=strchr(m_lineChars.c_str(),'\n')) && !gotEof) {
|
while (NULL==(rtnp=strchr(m_lineChars.c_str(),'\n')) && !gotEof) {
|
||||||
int tok = getToken();
|
int tok = getToken();
|
||||||
if (debug()>4) {
|
if (debug()>4) {
|
||||||
string buf = string (yytext, yyleng);
|
string buf = string (yyourtext(), yyourleng());
|
||||||
string::size_type pos;
|
string::size_type pos;
|
||||||
while ((pos=buf.find("\n")) != string::npos) { buf.replace(pos, 1, "\\n"); }
|
while ((pos=buf.find("\n")) != string::npos) { buf.replace(pos, 1, "\\n"); }
|
||||||
while ((pos=buf.find("\r")) != string::npos) { buf.replace(pos, 1, "\\r"); }
|
while ((pos=buf.find("\r")) != string::npos) { buf.replace(pos, 1, "\\r"); }
|
||||||
@@ -1126,7 +1131,7 @@ string V3PreProcImp::getline() {
|
|||||||
m_lineChars.append(" psl ");
|
m_lineChars.append(" psl ");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_lineChars.append(yytext,0,yyleng);
|
m_lineChars.append(yyourtext(),0,yyourleng());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -170,6 +170,7 @@ private:
|
|||||||
m_inWhilep = NULL;
|
m_inWhilep = NULL;
|
||||||
startStatement(nodep);
|
startStatement(nodep);
|
||||||
nodep->bodysp()->iterateAndNext(*this);
|
nodep->bodysp()->iterateAndNext(*this);
|
||||||
|
nodep->incsp()->iterateAndNext(*this);
|
||||||
m_stmtp = NULL;
|
m_stmtp = NULL;
|
||||||
}
|
}
|
||||||
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ private:
|
|||||||
|
|
||||||
//=======
|
//=======
|
||||||
// These have proper signedness set when they were created.
|
// These have proper signedness set when they were created.
|
||||||
|
virtual void visit(AstReturn* nodep, AstNUser*) { nodep->iterateChildren(*this); }
|
||||||
virtual void visit(AstNodeDType* nodep, AstNUser*) { nodep->iterateChildren(*this); }
|
virtual void visit(AstNodeDType* nodep, AstNUser*) { nodep->iterateChildren(*this); }
|
||||||
|
|
||||||
// Inherit from others
|
// Inherit from others
|
||||||
|
|||||||
+60
-8
@@ -88,6 +88,7 @@ private:
|
|||||||
bool m_inDlyAssign; ///< Under delayed assignment
|
bool m_inDlyAssign; ///< Under delayed assignment
|
||||||
int m_instrCount; ///< Number of nodes
|
int m_instrCount; ///< Number of nodes
|
||||||
int m_dataCount; ///< Bytes of data
|
int m_dataCount; ///< Bytes of data
|
||||||
|
AstJumpGo* m_jumpp; ///< Jump label we're branching from
|
||||||
// Simulating:
|
// Simulating:
|
||||||
deque<V3Number*> m_numFreeps; ///< List of all numbers free and not in use
|
deque<V3Number*> m_numFreeps; ///< List of all numbers free and not in use
|
||||||
deque<V3Number*> m_numAllps; ///< List of all numbers free and in use
|
deque<V3Number*> m_numAllps; ///< List of all numbers free and in use
|
||||||
@@ -230,8 +231,14 @@ private:
|
|||||||
: v3Global.opt.unrollCount();
|
: v3Global.opt.unrollCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool jumpingOver(AstNode* nodep) {
|
||||||
|
// True to jump over this node - all visitors must call this up front
|
||||||
|
return (m_jumpp && m_jumpp->labelp()!=nodep);
|
||||||
|
}
|
||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
virtual void visit(AstAlways* nodep, AstNUser*) {
|
virtual void visit(AstAlways* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
checkNodeInfo(nodep);
|
checkNodeInfo(nodep);
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
}
|
}
|
||||||
@@ -239,6 +246,7 @@ private:
|
|||||||
// Sensitivities aren't inputs per se; we'll keep our tree under the same sens.
|
// Sensitivities aren't inputs per se; we'll keep our tree under the same sens.
|
||||||
}
|
}
|
||||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
if (!optimizable()) return; // Accelerate
|
if (!optimizable()) return; // Accelerate
|
||||||
AstNode* vscp = varOrScope(nodep);
|
AstNode* vscp = varOrScope(nodep);
|
||||||
|
|
||||||
@@ -285,16 +293,19 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstVarXRef* nodep, AstNUser*) {
|
virtual void visit(AstVarXRef* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
if (m_scoped) { badNodeType(nodep); return; }
|
if (m_scoped) { badNodeType(nodep); return; }
|
||||||
else { clearOptimizable(nodep,"Language violation: Dotted hierarchical references not allowed in constant functions"); }
|
else { clearOptimizable(nodep,"Language violation: Dotted hierarchical references not allowed in constant functions"); }
|
||||||
}
|
}
|
||||||
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
if (!m_params) { badNodeType(nodep); return; }
|
if (!m_params) { badNodeType(nodep); return; }
|
||||||
if (nodep->dpiImport()) { clearOptimizable(nodep,"DPI import functions aren't simulatable"); }
|
if (nodep->dpiImport()) { clearOptimizable(nodep,"DPI import functions aren't simulatable"); }
|
||||||
checkNodeInfo(nodep);
|
checkNodeInfo(nodep);
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
}
|
}
|
||||||
virtual void visit(AstNodeIf* nodep, AstNUser*) {
|
virtual void visit(AstNodeIf* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
UINFO(5," IF "<<nodep<<endl);
|
UINFO(5," IF "<<nodep<<endl);
|
||||||
checkNodeInfo(nodep);
|
checkNodeInfo(nodep);
|
||||||
if (m_checkOnly) {
|
if (m_checkOnly) {
|
||||||
@@ -364,6 +375,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
if (!optimizable()) return; // Accelerate
|
if (!optimizable()) return; // Accelerate
|
||||||
if (nodep->castAssignDly()) {
|
if (nodep->castAssignDly()) {
|
||||||
if (m_anyAssignComb) clearOptimizable(nodep, "Mix of dly/non dly assigns");
|
if (m_anyAssignComb) clearOptimizable(nodep, "Mix of dly/non dly assigns");
|
||||||
@@ -400,6 +412,7 @@ private:
|
|||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
}
|
}
|
||||||
virtual void visit(AstNodeCase* nodep, AstNUser*) {
|
virtual void visit(AstNodeCase* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
UINFO(5," CASE "<<nodep<<endl);
|
UINFO(5," CASE "<<nodep<<endl);
|
||||||
checkNodeInfo(nodep);
|
checkNodeInfo(nodep);
|
||||||
if (m_checkOnly) {
|
if (m_checkOnly) {
|
||||||
@@ -436,12 +449,30 @@ private:
|
|||||||
|
|
||||||
virtual void visit(AstCaseItem* nodep, AstNUser*) {
|
virtual void visit(AstCaseItem* nodep, AstNUser*) {
|
||||||
// Real handling is in AstNodeCase
|
// Real handling is in AstNodeCase
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
checkNodeInfo(nodep);
|
checkNodeInfo(nodep);
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void visit(AstComment*, AstNUser*) {}
|
virtual void visit(AstComment*, AstNUser*) {}
|
||||||
|
|
||||||
|
virtual void visit(AstJumpGo* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
|
checkNodeInfo(nodep);
|
||||||
|
if (!m_checkOnly) {
|
||||||
|
UINFO(5," JUMP GO "<<nodep<<endl);
|
||||||
|
m_jumpp = nodep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
virtual void visit(AstJumpLabel* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
|
checkNodeInfo(nodep);
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
if (m_jumpp && m_jumpp->labelp() == nodep) {
|
||||||
|
UINFO(5," JUMP DONE "<<nodep<<endl);
|
||||||
|
m_jumpp = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
virtual void visit(AstStop* nodep, AstNUser*) {
|
virtual void visit(AstStop* nodep, AstNUser*) {
|
||||||
if (m_params) { // This message seems better than an obscure $stop
|
if (m_params) { // This message seems better than an obscure $stop
|
||||||
// The spec says $stop is just ignored, it seems evil to ignore assertions
|
// The spec says $stop is just ignored, it seems evil to ignore assertions
|
||||||
@@ -479,6 +510,7 @@ private:
|
|||||||
|
|
||||||
virtual void visit(AstWhile* nodep, AstNUser*) {
|
virtual void visit(AstWhile* nodep, AstNUser*) {
|
||||||
// Doing lots of Whiles is slow, so only for parameters
|
// Doing lots of Whiles is slow, so only for parameters
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
UINFO(5," WHILE "<<nodep<<endl);
|
UINFO(5," WHILE "<<nodep<<endl);
|
||||||
if (!m_params) { badNodeType(nodep); return; }
|
if (!m_params) { badNodeType(nodep); return; }
|
||||||
checkNodeInfo(nodep);
|
checkNodeInfo(nodep);
|
||||||
@@ -489,12 +521,19 @@ private:
|
|||||||
while (1) {
|
while (1) {
|
||||||
UINFO(5," WHILE-ITER "<<nodep<<endl);
|
UINFO(5," WHILE-ITER "<<nodep<<endl);
|
||||||
nodep->precondsp()->iterateAndNext(*this);
|
nodep->precondsp()->iterateAndNext(*this);
|
||||||
|
if (jumpingOver(nodep)) break;
|
||||||
nodep->condp()->iterateAndNext(*this);
|
nodep->condp()->iterateAndNext(*this);
|
||||||
|
if (jumpingOver(nodep)) break;
|
||||||
if (!optimizable()) break;
|
if (!optimizable()) break;
|
||||||
if (!fetchNumber(nodep->condp())->isNeqZero()) {
|
if (!fetchNumber(nodep->condp())->isNeqZero()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
nodep->bodysp()->iterateAndNext(*this);
|
nodep->bodysp()->iterateAndNext(*this);
|
||||||
|
if (jumpingOver(nodep)) break;
|
||||||
|
nodep->incsp()->iterateAndNext(*this);
|
||||||
|
if (jumpingOver(nodep)) break;
|
||||||
|
|
||||||
|
// Prep for next loop
|
||||||
if (loops++ > unrollCount()*16) {
|
if (loops++ > unrollCount()*16) {
|
||||||
clearOptimizable(nodep, "Loop unrolling took too long; probably this is an infinite loop, or set --unroll-count above "+cvtToStr(unrollCount()));
|
clearOptimizable(nodep, "Loop unrolling took too long; probably this is an infinite loop, or set --unroll-count above "+cvtToStr(unrollCount()));
|
||||||
break;
|
break;
|
||||||
@@ -504,6 +543,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void visit(AstFuncRef* nodep, AstNUser*) {
|
virtual void visit(AstFuncRef* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
UINFO(5," FUNCREF "<<nodep<<endl);
|
UINFO(5," FUNCREF "<<nodep<<endl);
|
||||||
if (!m_params) { badNodeType(nodep); return; }
|
if (!m_params) { badNodeType(nodep); return; }
|
||||||
AstNodeFTask* funcp = nodep->taskp()->castNodeFTask(); if (!funcp) nodep->v3fatalSrc("Not linked");
|
AstNodeFTask* funcp = nodep->taskp()->castNodeFTask(); if (!funcp) nodep->v3fatalSrc("Not linked");
|
||||||
@@ -540,6 +580,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void visit(AstVar* nodep, AstNUser*) {
|
virtual void visit(AstVar* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
if (!m_params) { badNodeType(nodep); return; }
|
if (!m_params) { badNodeType(nodep); return; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,20 +589,30 @@ private:
|
|||||||
// AstCoverInc, AstDisplay, AstArraySel, AstStop, AstFinish,
|
// AstCoverInc, AstDisplay, AstArraySel, AstStop, AstFinish,
|
||||||
// AstRand, AstTime, AstUCFunc, AstCCall, AstCStmt, AstUCStmt
|
// AstRand, AstTime, AstUCFunc, AstCCall, AstCStmt, AstUCStmt
|
||||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||||
|
if (jumpingOver(nodep)) return;
|
||||||
badNodeType(nodep);
|
badNodeType(nodep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// MEMBERS - called by constructor
|
||||||
|
void setMode(bool scoped, bool checkOnly, bool params) {
|
||||||
|
m_checkOnly = checkOnly;
|
||||||
|
m_scoped = scoped;
|
||||||
|
m_params = params;
|
||||||
|
}
|
||||||
|
void mainGuts(AstNode* nodep) {
|
||||||
|
nodep->accept(*this);
|
||||||
|
if (m_jumpp) {
|
||||||
|
m_jumpp->v3fatalSrc("JumpGo branched to label that wasn't found");
|
||||||
|
m_jumpp = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
SimulateVisitor() {
|
SimulateVisitor() {
|
||||||
setMode(false,false,false);
|
setMode(false,false,false);
|
||||||
clear(); // We reuse this structure in the main loop, so put initializers inside clear()
|
clear(); // We reuse this structure in the main loop, so put initializers inside clear()
|
||||||
}
|
}
|
||||||
void setMode(bool scoped, bool checkOnly, bool params) {
|
|
||||||
m_checkOnly = checkOnly;
|
|
||||||
m_scoped = scoped;
|
|
||||||
m_params = params;
|
|
||||||
}
|
|
||||||
void clear() {
|
void clear() {
|
||||||
m_whyNotOptimizable = "";
|
m_whyNotOptimizable = "";
|
||||||
m_whyNotNodep = NULL;
|
m_whyNotNodep = NULL;
|
||||||
@@ -570,6 +621,7 @@ public:
|
|||||||
m_inDlyAssign = false;
|
m_inDlyAssign = false;
|
||||||
m_instrCount = 0;
|
m_instrCount = 0;
|
||||||
m_dataCount = 0;
|
m_dataCount = 0;
|
||||||
|
m_jumpp = NULL;
|
||||||
|
|
||||||
AstNode::user1ClearTree(); // user1p() used on entire tree
|
AstNode::user1ClearTree(); // user1p() used on entire tree
|
||||||
AstNode::user2ClearTree(); // user2p() used on entire tree
|
AstNode::user2ClearTree(); // user2p() used on entire tree
|
||||||
@@ -580,15 +632,15 @@ public:
|
|||||||
}
|
}
|
||||||
void mainTableCheck (AstNode* nodep) {
|
void mainTableCheck (AstNode* nodep) {
|
||||||
setMode(true/*scoped*/,true/*checking*/, false/*params*/);
|
setMode(true/*scoped*/,true/*checking*/, false/*params*/);
|
||||||
nodep->accept(*this);
|
mainGuts(nodep);
|
||||||
}
|
}
|
||||||
void mainTableEmulate (AstNode* nodep) {
|
void mainTableEmulate (AstNode* nodep) {
|
||||||
setMode(true/*scoped*/,false/*checking*/, false/*params*/);
|
setMode(true/*scoped*/,false/*checking*/, false/*params*/);
|
||||||
nodep->accept(*this);
|
mainGuts(nodep);
|
||||||
}
|
}
|
||||||
void mainParamEmulate (AstNode* nodep) {
|
void mainParamEmulate (AstNode* nodep) {
|
||||||
setMode(false/*scoped*/,false/*checking*/, true/*params*/);
|
setMode(false/*scoped*/,false/*checking*/, true/*params*/);
|
||||||
nodep->accept(*this);
|
mainGuts(nodep);
|
||||||
}
|
}
|
||||||
virtual ~SimulateVisitor() {
|
virtual ~SimulateVisitor() {
|
||||||
for (deque<V3Number*>::iterator it = m_numAllps.begin(); it != m_numAllps.end(); ++it) {
|
for (deque<V3Number*>::iterator it = m_numAllps.begin(); it != m_numAllps.end(); ++it) {
|
||||||
|
|||||||
+2
-1
@@ -1039,7 +1039,7 @@ private:
|
|||||||
// Create output variable
|
// Create output variable
|
||||||
string namePrefix = "__Vfunc_"+nodep->taskp()->shortName()+"__"+cvtToStr(m_modNCalls++);
|
string namePrefix = "__Vfunc_"+nodep->taskp()->shortName()+"__"+cvtToStr(m_modNCalls++);
|
||||||
AstVarScope* outvscp = createVarScope (funcp->fvarp()->castVar(),
|
AstVarScope* outvscp = createVarScope (funcp->fvarp()->castVar(),
|
||||||
namePrefix+"__out");
|
namePrefix+"__Vfuncout");
|
||||||
// Create cloned statements
|
// Create cloned statements
|
||||||
if (debug()>=9) { nodep->taskp()->dumpTree(cout,"-oldfunc:"); }
|
if (debug()>=9) { nodep->taskp()->dumpTree(cout,"-oldfunc:"); }
|
||||||
if (!nodep->taskp()) nodep->v3fatalSrc("Unlinked?");
|
if (!nodep->taskp()) nodep->v3fatalSrc("Unlinked?");
|
||||||
@@ -1127,6 +1127,7 @@ private:
|
|||||||
// Body insert just before themselves
|
// Body insert just before themselves
|
||||||
m_insStmtp = NULL; // First thing should be new statement
|
m_insStmtp = NULL; // First thing should be new statement
|
||||||
nodep->bodysp()->iterateAndNext(*this);
|
nodep->bodysp()->iterateAndNext(*this);
|
||||||
|
nodep->incsp()->iterateAndNext(*this);
|
||||||
// Done the loop
|
// Done the loop
|
||||||
m_insStmtp = NULL; // Next thing should be new statement
|
m_insStmtp = NULL; // Next thing should be new statement
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-4
@@ -185,6 +185,9 @@ private:
|
|||||||
for (AstNode* bodp = bodysp; bodp; bodp=bodp->nextp()) {
|
for (AstNode* bodp = bodysp; bodp; bodp=bodp->nextp()) {
|
||||||
bodySize++;
|
bodySize++;
|
||||||
}
|
}
|
||||||
|
for (AstNode* bodp = incp; bodp; bodp=bodp->nextp()) {
|
||||||
|
bodySize++;
|
||||||
|
}
|
||||||
if (bodySize > v3Global.opt.unrollStmts())
|
if (bodySize > v3Global.opt.unrollStmts())
|
||||||
return cantUnroll(nodep, "too many statements");
|
return cantUnroll(nodep, "too many statements");
|
||||||
}
|
}
|
||||||
@@ -195,6 +198,7 @@ private:
|
|||||||
m_ignoreIncp = incp;
|
m_ignoreIncp = incp;
|
||||||
precondsp->iterateAndNext(*this);
|
precondsp->iterateAndNext(*this);
|
||||||
bodysp->iterateAndNext(*this);
|
bodysp->iterateAndNext(*this);
|
||||||
|
incp->iterateAndNext(*this);
|
||||||
m_varModeCheck = false;
|
m_varModeCheck = false;
|
||||||
m_ignoreIncp = NULL;
|
m_ignoreIncp = NULL;
|
||||||
if (m_varAssignHit) return cantUnroll(nodep, "genvar assigned *inside* loop");
|
if (m_varAssignHit) return cantUnroll(nodep, "genvar assigned *inside* loop");
|
||||||
@@ -231,6 +235,10 @@ private:
|
|||||||
bodysp->unlinkFrBackWithNext();
|
bodysp->unlinkFrBackWithNext();
|
||||||
stmtsp = stmtsp->addNextNull(bodysp); // Maybe null if no body
|
stmtsp = stmtsp->addNextNull(bodysp); // Maybe null if no body
|
||||||
}
|
}
|
||||||
|
if (incp && !nodep->castGenFor()) { // Generates don't need to increment loop index
|
||||||
|
incp->unlinkFrBackWithNext();
|
||||||
|
stmtsp = stmtsp->addNextNull(incp); // Maybe null if no body
|
||||||
|
}
|
||||||
// If it's a While, then incp is already part of bodysp.
|
// If it's a While, then incp is already part of bodysp.
|
||||||
V3Number loopValue(nodep->fileline(), m_forVarp->width()); // May differ in size from numInitp
|
V3Number loopValue(nodep->fileline(), m_forVarp->width()); // May differ in size from numInitp
|
||||||
loopValue.opAssign(numInit);
|
loopValue.opAssign(numInit);
|
||||||
@@ -279,7 +287,6 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Leaving the iterator at the final value is handled by the increment statements being left the final body
|
|
||||||
// Replace the FOR()
|
// Replace the FOR()
|
||||||
if (newbodysp) nodep->replaceWith(newbodysp);
|
if (newbodysp) nodep->replaceWith(newbodysp);
|
||||||
else nodep->unlinkFrBack();
|
else nodep->unlinkFrBack();
|
||||||
@@ -303,9 +310,13 @@ private:
|
|||||||
if (nodep->backp()->nextp() == nodep) initp=nodep->backp();
|
if (nodep->backp()->nextp() == nodep) initp=nodep->backp();
|
||||||
// Grab assignment
|
// Grab assignment
|
||||||
AstNode* incp = NULL; // Should be last statement
|
AstNode* incp = NULL; // Should be last statement
|
||||||
for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {}
|
if (nodep->incsp()) V3Const::constifyEdit(nodep->incsp());
|
||||||
if (incp) { V3Const::constifyEdit(incp); incp=NULL; }
|
if (nodep->incsp()) incp = nodep->incsp();
|
||||||
for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {} // Again, as may have changed
|
else {
|
||||||
|
for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {}
|
||||||
|
if (incp) { V3Const::constifyEdit(incp); incp=NULL; }
|
||||||
|
for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {} // Again, as may have changed
|
||||||
|
}
|
||||||
// And check it
|
// And check it
|
||||||
if (forUnrollCheck(nodep, initp,
|
if (forUnrollCheck(nodep, initp,
|
||||||
nodep->precondsp(), nodep->condp(),
|
nodep->precondsp(), nodep->condp(),
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ private:
|
|||||||
bool m_paramsOnly; // Computing parameter value; limit operation
|
bool m_paramsOnly; // Computing parameter value; limit operation
|
||||||
AstRange* m_cellRangep; // Range for arrayed instantiations, NULL for normal instantiations
|
AstRange* m_cellRangep; // Range for arrayed instantiations, NULL for normal instantiations
|
||||||
AstNodeCase* m_casep; // Current case statement CaseItem is under
|
AstNodeCase* m_casep; // Current case statement CaseItem is under
|
||||||
|
AstFunc* m_funcp; // Current function
|
||||||
|
|
||||||
// CLASSES
|
// CLASSES
|
||||||
#define ANYSIZE 0
|
#define ANYSIZE 0
|
||||||
@@ -711,6 +712,7 @@ private:
|
|||||||
nodep->precondsp()->iterateAndNext(*this);
|
nodep->precondsp()->iterateAndNext(*this);
|
||||||
nodep->condp()->iterateAndNext(*this,WidthVP(1,1,BOTH).p());
|
nodep->condp()->iterateAndNext(*this,WidthVP(1,1,BOTH).p());
|
||||||
nodep->bodysp()->iterateAndNext(*this);
|
nodep->bodysp()->iterateAndNext(*this);
|
||||||
|
nodep->incsp()->iterateAndNext(*this);
|
||||||
widthCheckReduce(nodep,"For Test Condition",nodep->condp(),1,1); // it's like an if() condition.
|
widthCheckReduce(nodep,"For Test Condition",nodep->condp(),1,1); // it's like an if() condition.
|
||||||
}
|
}
|
||||||
virtual void visit(AstNodeIf* nodep, AstNUser*) {
|
virtual void visit(AstNodeIf* nodep, AstNUser*) {
|
||||||
@@ -924,6 +926,20 @@ private:
|
|||||||
nodep->width(nodep->fvarp()->width(), nodep->fvarp()->width());
|
nodep->width(nodep->fvarp()->width(), nodep->fvarp()->width());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
m_funcp = NULL;
|
||||||
|
}
|
||||||
|
virtual void visit(AstReturn* nodep, AstNUser* vup) {
|
||||||
|
if (!m_funcp) {
|
||||||
|
if (nodep->lhsp()) { // Return w/o value ok other places
|
||||||
|
nodep->v3error("Return with return value isn't underneath a function");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (nodep->lhsp()) {
|
||||||
|
// Function hasn't been widthed, so make it so.
|
||||||
|
nodep->iterateChildren(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||||
|
nodep->widthSignedFrom(m_funcp->fvarp());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstFuncRef* nodep, AstNUser* vup) {
|
virtual void visit(AstFuncRef* nodep, AstNUser* vup) {
|
||||||
visit(nodep->castNodeFTaskRef(), vup);
|
visit(nodep->castNodeFTaskRef(), vup);
|
||||||
@@ -1028,6 +1044,7 @@ public:
|
|||||||
m_taskDepth = 0;
|
m_taskDepth = 0;
|
||||||
m_cellRangep = NULL;
|
m_cellRangep = NULL;
|
||||||
m_casep = NULL;
|
m_casep = NULL;
|
||||||
|
m_funcp = NULL;
|
||||||
}
|
}
|
||||||
AstNode* mainAcceptEdit(AstNode* nodep) {
|
AstNode* mainAcceptEdit(AstNode* nodep) {
|
||||||
return nodep->acceptSubtreeReturnEdits(*this, WidthVP(ANYSIZE,0,BOTH).p());
|
return nodep->acceptSubtreeReturnEdits(*this, WidthVP(ANYSIZE,0,BOTH).p());
|
||||||
|
|||||||
+5
-2
@@ -52,8 +52,8 @@
|
|||||||
#include "V3File.h"
|
#include "V3File.h"
|
||||||
#include "V3Cdc.h"
|
#include "V3Cdc.h"
|
||||||
#include "V3Gate.h"
|
#include "V3Gate.h"
|
||||||
#include "V3Graph.h"
|
|
||||||
#include "V3GenClk.h"
|
#include "V3GenClk.h"
|
||||||
|
#include "V3Graph.h"
|
||||||
#include "V3Inline.h"
|
#include "V3Inline.h"
|
||||||
#include "V3Inst.h"
|
#include "V3Inst.h"
|
||||||
#include "V3Life.h"
|
#include "V3Life.h"
|
||||||
@@ -61,9 +61,10 @@
|
|||||||
#include "V3Link.h"
|
#include "V3Link.h"
|
||||||
#include "V3LinkCells.h"
|
#include "V3LinkCells.h"
|
||||||
#include "V3LinkDot.h"
|
#include "V3LinkDot.h"
|
||||||
|
#include "V3LinkJump.h"
|
||||||
|
#include "V3LinkLValue.h"
|
||||||
#include "V3LinkLevel.h"
|
#include "V3LinkLevel.h"
|
||||||
#include "V3LinkParse.h"
|
#include "V3LinkParse.h"
|
||||||
#include "V3LinkLValue.h"
|
|
||||||
#include "V3LinkResolve.h"
|
#include "V3LinkResolve.h"
|
||||||
#include "V3Localize.h"
|
#include "V3Localize.h"
|
||||||
#include "V3Name.h"
|
#include "V3Name.h"
|
||||||
@@ -143,6 +144,8 @@ void process () {
|
|||||||
V3LinkResolve::linkResolve(v3Global.rootp());
|
V3LinkResolve::linkResolve(v3Global.rootp());
|
||||||
// Set Lvalue's in variable refs
|
// Set Lvalue's in variable refs
|
||||||
V3LinkLValue::linkLValue(v3Global.rootp());
|
V3LinkLValue::linkLValue(v3Global.rootp());
|
||||||
|
// Convert return/continue/disable to jumps
|
||||||
|
V3LinkJump::linkJump(v3Global.rootp());
|
||||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("link.tree"));
|
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("link.tree"));
|
||||||
V3Error::abortIfErrors();
|
V3Error::abortIfErrors();
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
//**********************************************************************
|
//**********************************************************************
|
||||||
//**** Version and host name
|
//**** Version and host name
|
||||||
|
|
||||||
#define DTVERSION "Verilator 3.800 2010/02/07"
|
#define DTVERSION "Verilator 3.801 2010/03/17"
|
||||||
|
|
||||||
//**********************************************************************
|
//**********************************************************************
|
||||||
//**** Functions
|
//**** Functions
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
|
|
||||||
# DESCRIPTION: Edits flex output to get around various broken flex issues.
|
# DESCRIPTION: Edits flex output to get around various broken flex issues.
|
||||||
|
|
||||||
|
my $Opt_Prefix = $ARGV[0] or die "%Error: No prefix specified,";
|
||||||
|
|
||||||
foreach my $line (<STDIN>) {
|
foreach my $line (<STDIN>) {
|
||||||
# Fix flex 2.5.4 namespace omission
|
# Fix flex 2.5.4 namespace omission
|
||||||
$line =~ s/^class istream;/\#include <iostream>\nusing namespace std;\n/;
|
$line =~ s/^class istream;/\#include <iostream>\nusing namespace std;\n/;
|
||||||
@@ -28,6 +30,8 @@ foreach my $line (<STDIN>) {
|
|||||||
$line =~ s!for \( n = 0; n < max_size && !for ( n = 0; ((size_t)n < (size_t)max_size) && !g;
|
$line =~ s!for \( n = 0; n < max_size && !for ( n = 0; ((size_t)n < (size_t)max_size) && !g;
|
||||||
# Fix flex 2.5.4 and GCC 4.0.2 under FLEX_DEBUG
|
# Fix flex 2.5.4 and GCC 4.0.2 under FLEX_DEBUG
|
||||||
$line =~ s!--accepting rule at line %d !--accepting rule at line %ld !g;
|
$line =~ s!--accepting rule at line %d !--accepting rule at line %ld !g;
|
||||||
|
# Fix compiler warning filenames
|
||||||
|
$line =~ s!(#line \d+ ".*)_pretmp!$1!;
|
||||||
|
|
||||||
print "$line";
|
print "$line";
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-5
@@ -382,10 +382,12 @@ escid \\[^ \t\f\r\n]+
|
|||||||
"always_ff" { FL; return yALWAYS; }
|
"always_ff" { FL; return yALWAYS; }
|
||||||
"always_latch" { FL; return yALWAYS; }
|
"always_latch" { FL; return yALWAYS; }
|
||||||
"bit" { FL; return yBIT; }
|
"bit" { FL; return yBIT; }
|
||||||
|
"break" { FL; return yBREAK; }
|
||||||
"byte" { FL; return yBYTE; }
|
"byte" { FL; return yBYTE; }
|
||||||
"chandle" { FL; return yCHANDLE; }
|
"chandle" { FL; return yCHANDLE; }
|
||||||
"clocking" { FL; return yCLOCKING; }
|
"clocking" { FL; return yCLOCKING; }
|
||||||
"context" { FL; return yCONTEXT; }
|
"context" { FL; return yCONTEXT; }
|
||||||
|
"continue" { FL; return yCONTINUE; }
|
||||||
"do" { FL; return yDO; }
|
"do" { FL; return yDO; }
|
||||||
"endclocking" { FL; return yENDCLOCKING; }
|
"endclocking" { FL; return yENDCLOCKING; }
|
||||||
"endpackage" { FL; return yENDPACKAGE; }
|
"endpackage" { FL; return yENDPACKAGE; }
|
||||||
@@ -403,6 +405,7 @@ escid \\[^ \t\f\r\n]+
|
|||||||
"priority" { FL; return yPRIORITY; }
|
"priority" { FL; return yPRIORITY; }
|
||||||
"program" { FL; return yPROGRAM; }
|
"program" { FL; return yPROGRAM; }
|
||||||
"pure" { FL; return yPURE; }
|
"pure" { FL; return yPURE; }
|
||||||
|
"return" { FL; return yRETURN; }
|
||||||
"shortint" { FL; return ySHORTINT; }
|
"shortint" { FL; return ySHORTINT; }
|
||||||
"static" { FL; return ySTATIC; }
|
"static" { FL; return ySTATIC; }
|
||||||
"string" { FL; return ySTRING; }
|
"string" { FL; return ySTRING; }
|
||||||
@@ -419,10 +422,8 @@ escid \\[^ \t\f\r\n]+
|
|||||||
"bind" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"bind" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"binsof" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"binsof" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"break" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
|
||||||
"class" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"class" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"constraint" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"constraint" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"continue" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
|
||||||
"covergroup" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"covergroup" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"coverpoint" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"coverpoint" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"cross" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"cross" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
@@ -457,7 +458,6 @@ escid \\[^ \t\f\r\n]+
|
|||||||
"randomize" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"randomize" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"randsequence" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"randsequence" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"ref" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"ref" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"return" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
|
||||||
"shortreal" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"shortreal" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"solve" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"solve" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
"struct" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
"struct" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
|
||||||
@@ -863,7 +863,10 @@ escid \\[^ \t\f\r\n]+
|
|||||||
"`autoexpand_vectornets" { } // Verilog-XL compatibility
|
"`autoexpand_vectornets" { } // Verilog-XL compatibility
|
||||||
"`celldefine" { PARSEP->inCellDefine(true); }
|
"`celldefine" { PARSEP->inCellDefine(true); }
|
||||||
"`default_decay_time"{ws}+[^\n\r]* { } // Verilog spec - delays only
|
"`default_decay_time"{ws}+[^\n\r]* { } // Verilog spec - delays only
|
||||||
"`default_nettype"{ws}+[a-zA-Z0-9]* { yyerrorf("Unsupported: Verilog 2001 directive not implemented: %s",yytext); } // Verilog 2001
|
"`default_nettype"{ws}+"wire" { PARSEP->fileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE,true); }
|
||||||
|
"`default_nettype"{ws}+"none" { PARSEP->fileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE,false); }
|
||||||
|
"`default_nettype"{ws}+[a-zA-Z0-9]* { yyerrorf("Unsupported: `default_nettype of other than none or wire: %s",yytext); }
|
||||||
|
"`default_trireg_strength"{ws}+[^\n\r]* { yyerrorf("Unsupported: Verilog optional directive not implemented: %s",yytext); }
|
||||||
"`delay_mode_distributed" { } // Verilog spec - delays only
|
"`delay_mode_distributed" { } // Verilog spec - delays only
|
||||||
"`delay_mode_path" { } // Verilog spec - delays only
|
"`delay_mode_path" { } // Verilog spec - delays only
|
||||||
"`delay_mode_unit" { } // Verilog spec - delays only
|
"`delay_mode_unit" { } // Verilog spec - delays only
|
||||||
@@ -887,7 +890,7 @@ escid \\[^ \t\f\r\n]+
|
|||||||
"`psl" { if (PARSEP->optPsl()) { BEGIN PSL; } else { BEGIN IGNORE; } }
|
"`psl" { if (PARSEP->optPsl()) { BEGIN PSL; } else { BEGIN IGNORE; } }
|
||||||
"`remove_gatenames" { } // Verilog-XL compatibility
|
"`remove_gatenames" { } // Verilog-XL compatibility
|
||||||
"`remove_netnames" { } // Verilog-XL compatibility
|
"`remove_netnames" { } // Verilog-XL compatibility
|
||||||
"`resetall" { }
|
"`resetall" { PARSEP->fileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE,true); } // Rest handled by preproc
|
||||||
"`suppress_faults" { } // Verilog-XL compatibility
|
"`suppress_faults" { } // Verilog-XL compatibility
|
||||||
"`timescale"{ws}+[^\n\r]* { } // Verilog spec - not supported
|
"`timescale"{ws}+[^\n\r]* { } // Verilog spec - not supported
|
||||||
|
|
||||||
|
|||||||
+16
-7
@@ -264,6 +264,7 @@ class AstSenTree;
|
|||||||
%token<fl> yAUTOMATIC "automatic"
|
%token<fl> yAUTOMATIC "automatic"
|
||||||
%token<fl> yBEGIN "begin"
|
%token<fl> yBEGIN "begin"
|
||||||
%token<fl> yBIT "bit"
|
%token<fl> yBIT "bit"
|
||||||
|
%token<fl> yBREAK "break"
|
||||||
%token<fl> yBUF "buf"
|
%token<fl> yBUF "buf"
|
||||||
%token<fl> yBUFIF0 "bufif0"
|
%token<fl> yBUFIF0 "bufif0"
|
||||||
%token<fl> yBUFIF1 "bufif1"
|
%token<fl> yBUFIF1 "bufif1"
|
||||||
@@ -275,6 +276,7 @@ class AstSenTree;
|
|||||||
%token<fl> yCLOCKING "clocking"
|
%token<fl> yCLOCKING "clocking"
|
||||||
%token<fl> yCMOS "cmos"
|
%token<fl> yCMOS "cmos"
|
||||||
%token<fl> yCONTEXT "context"
|
%token<fl> yCONTEXT "context"
|
||||||
|
%token<fl> yCONTINUE "continue"
|
||||||
%token<fl> yCOVER "cover"
|
%token<fl> yCOVER "cover"
|
||||||
%token<fl> yDEFAULT "default"
|
%token<fl> yDEFAULT "default"
|
||||||
%token<fl> yDEFPARAM "defparam"
|
%token<fl> yDEFPARAM "defparam"
|
||||||
@@ -340,6 +342,7 @@ class AstSenTree;
|
|||||||
%token<fl> yRCMOS "rcmos"
|
%token<fl> yRCMOS "rcmos"
|
||||||
%token<fl> yREG "reg"
|
%token<fl> yREG "reg"
|
||||||
%token<fl> yREPEAT "repeat"
|
%token<fl> yREPEAT "repeat"
|
||||||
|
%token<fl> yRETURN "return"
|
||||||
%token<fl> yRNMOS "rnmos"
|
%token<fl> yRNMOS "rnmos"
|
||||||
%token<fl> yRPMOS "rpmos"
|
%token<fl> yRPMOS "rpmos"
|
||||||
%token<fl> yRTRAN "rtran"
|
%token<fl> yRTRAN "rtran"
|
||||||
@@ -1436,6 +1439,7 @@ genvar_iteration<nodep>: // ==IEEE: genvar_iteration
|
|||||||
| varRefBase yP_SRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftR ($2,$1->cloneTree(true),$3)); }
|
| varRefBase yP_SRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftR ($2,$1->cloneTree(true),$3)); }
|
||||||
| varRefBase yP_SSRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftRS($2,$1->cloneTree(true),$3)); }
|
| varRefBase yP_SSRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftRS($2,$1->cloneTree(true),$3)); }
|
||||||
// // inc_or_dec_operator
|
// // inc_or_dec_operator
|
||||||
|
// When support ++ as a real AST type, maybe AstWhile::precondsp() becomes generic AstMathStmt?
|
||||||
| yP_PLUSPLUS varRefBase { $$ = new AstAssign($1,$2,new AstAdd ($1,$2->cloneTree(true),new AstConst($1,V3Number($1,"'b1")))); }
|
| yP_PLUSPLUS varRefBase { $$ = new AstAssign($1,$2,new AstAdd ($1,$2->cloneTree(true),new AstConst($1,V3Number($1,"'b1")))); }
|
||||||
| yP_MINUSMINUS varRefBase { $$ = new AstAssign($1,$2,new AstSub ($1,$2->cloneTree(true),new AstConst($1,V3Number($1,"'b1")))); }
|
| yP_MINUSMINUS varRefBase { $$ = new AstAssign($1,$2,new AstSub ($1,$2->cloneTree(true),new AstConst($1,V3Number($1,"'b1")))); }
|
||||||
| varRefBase yP_PLUSPLUS { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true),new AstConst($2,V3Number($2,"'b1")))); }
|
| varRefBase yP_PLUSPLUS { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true),new AstConst($2,V3Number($2,"'b1")))); }
|
||||||
@@ -1831,7 +1835,7 @@ statement_item<nodep>: // IEEE: statement_item
|
|||||||
| statementVerilatorPragmas { $$ = $1; }
|
| statementVerilatorPragmas { $$ = $1; }
|
||||||
//
|
//
|
||||||
// // IEEE: disable_statement
|
// // IEEE: disable_statement
|
||||||
//UNSUP yDISABLE hierarchical_identifier/*task_or_block*/ ';' { UNSUP }
|
//UNSUP yDISABLE idAny/*hierarchical_identifier-task_or_block*/ ';' { UNSUP }
|
||||||
//UNSUP yDISABLE yFORK ';' { UNSUP }
|
//UNSUP yDISABLE yFORK ';' { UNSUP }
|
||||||
// // IEEE: event_trigger
|
// // IEEE: event_trigger
|
||||||
//UNSUP yP_MINUSGT hierarchical_identifier/*event*/ ';' { UNSUP }
|
//UNSUP yP_MINUSGT hierarchical_identifier/*event*/ ';' { UNSUP }
|
||||||
@@ -1842,15 +1846,15 @@ statement_item<nodep>: // IEEE: statement_item
|
|||||||
| yWHILE '(' expr ')' stmtBlock { $$ = new AstWhile($1,$3,$5);}
|
| yWHILE '(' expr ')' stmtBlock { $$ = new AstWhile($1,$3,$5);}
|
||||||
// // for's first ';' is in for_initalization
|
// // for's first ';' is in for_initalization
|
||||||
| yFOR '(' for_initialization expr ';' for_stepE ')' stmtBlock
|
| yFOR '(' for_initialization expr ';' for_stepE ')' stmtBlock
|
||||||
{ $$ = new AstBegin($1,"",$3); $3->addNext(new AstFor($1,NULL,$4,$6,$8));}
|
{ $$ = new AstBegin($1,"",$3); $3->addNext(new AstWhile($1, $4,$8,$6)); }
|
||||||
| yDO stmtBlock yWHILE '(' expr ')' { $$ = $2->cloneTree(true); $$->addNext(new AstWhile($1,$5,$2));}
|
| yDO stmtBlock yWHILE '(' expr ')' { $$ = $2->cloneTree(true); $$->addNext(new AstWhile($1,$5,$2));}
|
||||||
//UNSUP yFOREACH '(' idClassForeach/*array_id[loop_variables]*/ ')' stmt { UNSUP }
|
//UNSUP yFOREACH '(' idClassForeach/*array_id[loop_variables]*/ ')' stmt { UNSUP }
|
||||||
//
|
//
|
||||||
// // IEEE: jump_statement
|
// // IEEE: jump_statement
|
||||||
//UNSUP yRETURN ';' { UNSUP }
|
| yRETURN ';' { $$ = new AstReturn($1); }
|
||||||
//UNSUP yRETURN expr ';' { UNSUP }
|
| yRETURN expr ';' { $$ = new AstReturn($1,$2); }
|
||||||
//UNSUP yBREAK ';' { UNSUP }
|
| yBREAK ';' { $$ = new AstBreak($1); }
|
||||||
//UNSUP yCONTINUE ';' { UNSUP }
|
| yCONTINUE ';' { $$ = new AstContinue($1); }
|
||||||
//
|
//
|
||||||
//UNSUP par_block { $$ = $1; }
|
//UNSUP par_block { $$ = $1; }
|
||||||
// // IEEE: procedural_timing_control_statement + procedural_timing_control
|
// // IEEE: procedural_timing_control_statement + procedural_timing_control
|
||||||
@@ -2738,9 +2742,14 @@ specifyJunk:
|
|||||||
;
|
;
|
||||||
|
|
||||||
specparam_declaration<nodep>: // ==IEEE: specparam_declaration
|
specparam_declaration<nodep>: // ==IEEE: specparam_declaration
|
||||||
ySPECPARAM junkToSemi ';' { $$ = NULL; }
|
ySPECPARAM junkToSemiList ';' { $$ = NULL; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
junkToSemiList:
|
||||||
|
junkToSemi { } /* ignored */
|
||||||
|
| junkToSemiList junkToSemi { } /* ignored */
|
||||||
|
;
|
||||||
|
|
||||||
junkToSemi:
|
junkToSemi:
|
||||||
BISONPRE_NOT(';',yENDSPECIFY,yENDMODULE) { }
|
BISONPRE_NOT(';',yENDSPECIFY,yENDMODULE) { }
|
||||||
| error {}
|
| error {}
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ sub parameter {
|
|||||||
elsif ($param =~ /\.pl/) {
|
elsif ($param =~ /\.pl/) {
|
||||||
push @opt_tests, $param;
|
push @opt_tests, $param;
|
||||||
}
|
}
|
||||||
elsif ($param =~ /^--debugi/) {
|
elsif ($param =~ /^-?-debugi/) {
|
||||||
push @Opt_Driver_Verilator_Flags, $param;
|
push @Opt_Driver_Verilator_Flags, $param;
|
||||||
$_Parameter_Next_Level = $param;
|
$_Parameter_Next_Level = $param;
|
||||||
}
|
}
|
||||||
|
|||||||
Executable
+18
@@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||||
|
# redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
|
||||||
|
compile (
|
||||||
|
);
|
||||||
|
|
||||||
|
execute (
|
||||||
|
check_finished=>1,
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed into the Public Domain, for any use,
|
||||||
|
// without warranty, 2010 by Wilson Snyder.
|
||||||
|
//
|
||||||
|
// --------------------------------------------------------
|
||||||
|
// Bug Description:
|
||||||
|
//
|
||||||
|
// Issue: The gated clock gclk_vld[0] toggles but dvld[0]
|
||||||
|
// input to the flop does not propagate to the output
|
||||||
|
// signal entry_vld[0] correctly. The value that propagates
|
||||||
|
// is the new value of dvld[0] not the one just before the
|
||||||
|
// posedge of gclk_vld[0].
|
||||||
|
// --------------------------------------------------------
|
||||||
|
|
||||||
|
// Define to see the bug with test failing with gated clock 'gclk_vld'
|
||||||
|
// Comment out the define to see the test passing with ungated clock 'clk'
|
||||||
|
`define GATED_CLK_TESTCASE 1
|
||||||
|
|
||||||
|
// A side effect of the problem is this warning, disabled by default
|
||||||
|
//verilator lint_on IMPERFECTSCH
|
||||||
|
|
||||||
|
// Test Bench
|
||||||
|
module t (/*AUTOARG*/
|
||||||
|
// Inputs
|
||||||
|
clk
|
||||||
|
);
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
integer cyc=0;
|
||||||
|
reg [63:0] crc;
|
||||||
|
|
||||||
|
// Take CRC data and apply to testblock inputs
|
||||||
|
wire [7:0] dvld = crc[7:0];
|
||||||
|
wire [7:0] ff_en_e1 = crc[15:8];
|
||||||
|
|
||||||
|
/*AUTOWIRE*/
|
||||||
|
// Beginning of automatic wires (for undeclared instantiated-module outputs)
|
||||||
|
wire [7:0] entry_vld; // From test of Test.v
|
||||||
|
wire [7:0] ff_en_vld; // From test of Test.v
|
||||||
|
// End of automatics
|
||||||
|
|
||||||
|
Test test (/*AUTOINST*/
|
||||||
|
// Outputs
|
||||||
|
.ff_en_vld (ff_en_vld[7:0]),
|
||||||
|
.entry_vld (entry_vld[7:0]),
|
||||||
|
// Inputs
|
||||||
|
.clk (clk),
|
||||||
|
.dvld (dvld[7:0]),
|
||||||
|
.ff_en_e1 (ff_en_e1[7:0]));
|
||||||
|
|
||||||
|
reg err_code;
|
||||||
|
reg ffq_clk_active;
|
||||||
|
reg [7:0] prv_dvld;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
err_code = 0;
|
||||||
|
ffq_clk_active = 0;
|
||||||
|
end
|
||||||
|
always @ (posedge clk) begin
|
||||||
|
prv_dvld = test.dvld;
|
||||||
|
end
|
||||||
|
always @ (negedge test.ff_entry_dvld_0.clk) begin
|
||||||
|
ffq_clk_active = 1;
|
||||||
|
if (test.entry_vld[0] !== prv_dvld[0]) err_code = 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
// Test loop
|
||||||
|
always @ (posedge clk) begin
|
||||||
|
`ifdef TEST_VERBOSE
|
||||||
|
$write("[%0t] cyc==%0d crc=%x ",$time, cyc, crc);
|
||||||
|
$display(" en=%b fen=%b d=%b ev=%b",
|
||||||
|
test.flop_en_vld[0], test.ff_en_vld[0],
|
||||||
|
test.dvld[0], test.entry_vld[0]);
|
||||||
|
`endif
|
||||||
|
cyc <= cyc + 1;
|
||||||
|
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
|
||||||
|
if (cyc<3) begin
|
||||||
|
crc <= 64'h5aef0c8d_d70a4497;
|
||||||
|
end
|
||||||
|
else if (cyc==99) begin
|
||||||
|
$write("[%0t] cyc==%0d crc=%x\n",$time, cyc, crc);
|
||||||
|
if (ffq_clk_active == 0) begin
|
||||||
|
$display ("----");
|
||||||
|
$display ("%%Error: TESTCASE FAILED with no Clock arriving at FFQs");
|
||||||
|
$display ("----");
|
||||||
|
$stop;
|
||||||
|
end
|
||||||
|
else if (err_code) begin
|
||||||
|
$display ("----");
|
||||||
|
$display ("%%Error: TESTCASE FAILED with invalid propagation of 'd' to 'q' of FFQs");
|
||||||
|
$display ("----");
|
||||||
|
$stop;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module llq (clk, d, q);
|
||||||
|
parameter WIDTH = 32;
|
||||||
|
input clk;
|
||||||
|
input [WIDTH-1:0] d;
|
||||||
|
output [WIDTH-1:0] q;
|
||||||
|
|
||||||
|
reg [WIDTH-1:0] qr;
|
||||||
|
|
||||||
|
/* verilator lint_off COMBDLY */
|
||||||
|
|
||||||
|
always @(clk or d)
|
||||||
|
if (clk == 1'b0)
|
||||||
|
qr <= d;
|
||||||
|
|
||||||
|
/* verilator lint_on COMBDLY */
|
||||||
|
|
||||||
|
assign q = qr;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module ffq (clk, d, q);
|
||||||
|
parameter WIDTH = 32;
|
||||||
|
input clk;
|
||||||
|
input [WIDTH-1:0] d;
|
||||||
|
output [WIDTH-1:0] q;
|
||||||
|
|
||||||
|
reg [WIDTH-1:0] qr;
|
||||||
|
|
||||||
|
always @(posedge clk)
|
||||||
|
qr <= d;
|
||||||
|
|
||||||
|
assign q = qr;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
// DUT module
|
||||||
|
module Test (/*AUTOARG*/
|
||||||
|
// Outputs
|
||||||
|
ff_en_vld, entry_vld,
|
||||||
|
// Inputs
|
||||||
|
clk, dvld, ff_en_e1
|
||||||
|
);
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
input [7:0] dvld;
|
||||||
|
input [7:0] ff_en_e1;
|
||||||
|
|
||||||
|
output [7:0] ff_en_vld;
|
||||||
|
output wire [7:0] entry_vld;
|
||||||
|
|
||||||
|
wire [7:0] gclk_vld;
|
||||||
|
wire [7:0] ff_en_vld /*verilator clock_enable*/;
|
||||||
|
reg [7:0] flop_en_vld;
|
||||||
|
|
||||||
|
always @(posedge clk) flop_en_vld <= ff_en_e1;
|
||||||
|
|
||||||
|
// clock gating
|
||||||
|
`ifdef GATED_CLK_TESTCASE
|
||||||
|
assign gclk_vld = {8{clk}} & ff_en_vld;
|
||||||
|
`else
|
||||||
|
assign gclk_vld = {8{clk}};
|
||||||
|
`endif
|
||||||
|
|
||||||
|
// latch for avoiding glitch on the clock gating control
|
||||||
|
llq #(8) dp_ff_en_vld (.clk(clk), .d(flop_en_vld), .q(ff_en_vld));
|
||||||
|
|
||||||
|
// flops that use the gated clock signal
|
||||||
|
ffq #(1) ff_entry_dvld_0 (.clk(gclk_vld[0]), .d(dvld[0]), .q(entry_vld[0]));
|
||||||
|
ffq #(1) ff_entry_dvld_1 (.clk(gclk_vld[1]), .d(dvld[1]), .q(entry_vld[1]));
|
||||||
|
ffq #(1) ff_entry_dvld_2 (.clk(gclk_vld[2]), .d(dvld[2]), .q(entry_vld[2]));
|
||||||
|
ffq #(1) ff_entry_dvld_3 (.clk(gclk_vld[3]), .d(dvld[3]), .q(entry_vld[3]));
|
||||||
|
ffq #(1) ff_entry_dvld_4 (.clk(gclk_vld[4]), .d(dvld[4]), .q(entry_vld[4]));
|
||||||
|
ffq #(1) ff_entry_dvld_5 (.clk(gclk_vld[5]), .d(dvld[5]), .q(entry_vld[5]));
|
||||||
|
ffq #(1) ff_entry_dvld_6 (.clk(gclk_vld[6]), .d(dvld[6]), .q(entry_vld[6]));
|
||||||
|
ffq #(1) ff_entry_dvld_7 (.clk(gclk_vld[7]), .d(dvld[7]), .q(entry_vld[7]));
|
||||||
|
|
||||||
|
endmodule
|
||||||
Executable
+52
@@ -0,0 +1,52 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2010 by Wilson Snyder. This program is free software; you can
|
||||||
|
# redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
|
||||||
|
use Cwd;
|
||||||
|
|
||||||
|
my $root = "..";
|
||||||
|
my $Debug;
|
||||||
|
|
||||||
|
if (!-r "$root/.git") {
|
||||||
|
$Self->skip("Not in a git repository");
|
||||||
|
} else {
|
||||||
|
my $cwd = getcwd();
|
||||||
|
my $destdir = "$cwd/".$Self->{obj_dir};
|
||||||
|
# Start clean
|
||||||
|
$Self->_run(cmd=>["rm -rf $destdir && mkdir -p $destdir"],
|
||||||
|
check_finished=>0);
|
||||||
|
# Install into temp area
|
||||||
|
print "Install...\n";
|
||||||
|
$Self->_run (cmd=>["cd $root && make DESTDIR=$destdir install"],
|
||||||
|
check_finished=>0);
|
||||||
|
|
||||||
|
# Check we can run a test
|
||||||
|
# Unfortunately the prefix was hardcoded in the exec at a different place,
|
||||||
|
# so we can't do much here.
|
||||||
|
#print "Check install...\n";
|
||||||
|
|
||||||
|
# Uninstall
|
||||||
|
print "Uninstall...\n";
|
||||||
|
$Self->_run (cmd=>["cd $root && make DESTDIR=$destdir uninstall"],
|
||||||
|
check_finished=>0);
|
||||||
|
|
||||||
|
# Check empty
|
||||||
|
my @files;
|
||||||
|
$finds = `find $destdir -type f -print`;
|
||||||
|
foreach my $f (split /\n/, $finds) {
|
||||||
|
print "\tLEFT: $f\n";
|
||||||
|
$f =~ s!^$cwd!.!;
|
||||||
|
push @files, $f;
|
||||||
|
}
|
||||||
|
if ($#files >= 0) {
|
||||||
|
$Self->error("Uninstall missed files: ",join(' ',@files));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
Executable
+18
@@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||||
|
# redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
|
||||||
|
compile (
|
||||||
|
);
|
||||||
|
|
||||||
|
execute (
|
||||||
|
check_finished=>1,
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed into the Public Domain, for any use,
|
||||||
|
// without warranty, 2009 by Wilson Snyder.
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/
|
||||||
|
// Inputs
|
||||||
|
clk
|
||||||
|
);
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
integer cyc=0;
|
||||||
|
reg [63:0] crc;
|
||||||
|
reg [63:0] sum;
|
||||||
|
|
||||||
|
// Take CRC data and apply to testblock inputs
|
||||||
|
wire [3:0] l_stop = crc[3:0];
|
||||||
|
wire [3:0] l_break = crc[7:4];
|
||||||
|
wire [3:0] l_continue = crc[11:8];
|
||||||
|
|
||||||
|
/*AUTOWIRE*/
|
||||||
|
|
||||||
|
wire [15:0] out0 = Test0(l_stop, l_break, l_continue);
|
||||||
|
wire [15:0] out1 = Test1(l_stop, l_break, l_continue);
|
||||||
|
wire [15:0] out2 = Test2(l_stop, l_break, l_continue);
|
||||||
|
wire [15:0] out3 = Test3(l_stop, l_break, l_continue);
|
||||||
|
|
||||||
|
// Aggregate outputs into a single result vector
|
||||||
|
wire [63:0] result = {out3,out2,out1,out0};
|
||||||
|
|
||||||
|
// Test loop
|
||||||
|
always @ (posedge clk) begin
|
||||||
|
`ifdef TEST_VERBOSE
|
||||||
|
$write("[%0t] cyc==%0d crc=%x result=%x\n",$time, cyc, crc, result);
|
||||||
|
`endif
|
||||||
|
cyc <= cyc + 1;
|
||||||
|
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
|
||||||
|
sum <= result ^ {sum[62:0],sum[63]^sum[2]^sum[0]};
|
||||||
|
if (cyc==0) begin
|
||||||
|
// Setup
|
||||||
|
crc <= 64'h5aef0c8d_d70a4497;
|
||||||
|
sum <= 64'h0;
|
||||||
|
end
|
||||||
|
else if (cyc<10) begin
|
||||||
|
sum <= 64'h0;
|
||||||
|
end
|
||||||
|
else if (cyc<90) begin
|
||||||
|
if (out0!==out1) $stop;
|
||||||
|
if (out0!==out2) $stop;
|
||||||
|
if (out0!==out3) $stop;
|
||||||
|
end
|
||||||
|
else if (cyc==99) begin
|
||||||
|
$write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum);
|
||||||
|
if (crc !== 64'hc77bb9b3784ea091) $stop;
|
||||||
|
// What checksum will we end up with (above print should match)
|
||||||
|
`define EXPECTED_SUM 64'h293e9f9798e97da0
|
||||||
|
if (sum !== `EXPECTED_SUM) $stop;
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function [15:0] Test0;
|
||||||
|
input [3:0] loop_stop;
|
||||||
|
input [3:0] loop_break;
|
||||||
|
input [3:0] loop_continue;
|
||||||
|
integer i;
|
||||||
|
reg broken;
|
||||||
|
|
||||||
|
Test0 = 0;
|
||||||
|
broken = 0;
|
||||||
|
begin
|
||||||
|
for (i=1; i<20; i=i+1) begin
|
||||||
|
if (!broken) begin
|
||||||
|
Test0 = Test0 + 1;
|
||||||
|
if (i[3:0] != loop_continue) begin // continue
|
||||||
|
if (i[3:0] == loop_break) begin
|
||||||
|
broken = 1'b1;
|
||||||
|
end
|
||||||
|
if (!broken) begin
|
||||||
|
Test0 = Test0 + i[15:0];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function [15:0] Test1;
|
||||||
|
input [3:0] loop_stop;
|
||||||
|
input [3:0] loop_break;
|
||||||
|
input [3:0] loop_continue;
|
||||||
|
integer i;
|
||||||
|
|
||||||
|
// Placeholder
|
||||||
|
return Test0(loop_stop,loop_break,loop_continue);
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function [15:0] Test2;
|
||||||
|
input [3:0] loop_stop;
|
||||||
|
input [3:0] loop_break;
|
||||||
|
input [3:0] loop_continue;
|
||||||
|
integer i;
|
||||||
|
|
||||||
|
Test2 = 0;
|
||||||
|
begin
|
||||||
|
for (i=1; i<20; i=i+1) begin
|
||||||
|
Test2 = Test2 + 1;
|
||||||
|
if (i[3:0] == loop_continue) continue;
|
||||||
|
if (i[3:0] == loop_break) break;
|
||||||
|
Test2 = Test2 + i[15:0];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function [15:0] Test3;
|
||||||
|
input [3:0] loop_stop;
|
||||||
|
input [3:0] loop_break;
|
||||||
|
input [3:0] loop_continue;
|
||||||
|
integer i;
|
||||||
|
|
||||||
|
Test3 = 0;
|
||||||
|
begin
|
||||||
|
for (i=1; i<20; i=i+1) begin
|
||||||
|
Test3 = Test3 + 1;
|
||||||
|
if (i[3:0] == loop_continue) continue;
|
||||||
|
// return, IE jump to end-of-function optionally setting return value
|
||||||
|
if (i[3:0] == loop_break) return Test3;
|
||||||
|
Test3 = Test3 + i[15:0];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
endmodule
|
||||||
@@ -10,6 +10,7 @@ module t;
|
|||||||
localparam P5 = f_while(7);
|
localparam P5 = f_while(7);
|
||||||
localparam P16 = f_for(P4);
|
localparam P16 = f_for(P4);
|
||||||
localparam P18 = f_case(P4);
|
localparam P18 = f_case(P4);
|
||||||
|
localparam P6 = f_return(P4);
|
||||||
localparam P3 = 3;
|
localparam P3 = 3;
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
@@ -19,6 +20,7 @@ module t;
|
|||||||
if (P3 !== 3) $stop;
|
if (P3 !== 3) $stop;
|
||||||
if (P4 !== 4) $stop;
|
if (P4 !== 4) $stop;
|
||||||
if (P5 !== 5) $stop;
|
if (P5 !== 5) $stop;
|
||||||
|
if (P6 !== 6) $stop;
|
||||||
if (P8 !== 8) $stop;
|
if (P8 !== 8) $stop;
|
||||||
if (P16 !== 16) $stop;
|
if (P16 !== 16) $stop;
|
||||||
if (P18 !== 18) $stop;
|
if (P18 !== 18) $stop;
|
||||||
@@ -69,4 +71,17 @@ module t;
|
|||||||
default: f_case = 99;
|
default: f_case = 99;
|
||||||
endcase
|
endcase
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
function integer f_return(input [31:0] a);
|
||||||
|
integer out = 2;
|
||||||
|
while (1) begin
|
||||||
|
out = out+1;
|
||||||
|
if (a>1) break;
|
||||||
|
end
|
||||||
|
while (1) begin
|
||||||
|
out = out+1;
|
||||||
|
if (a>1) return 2+out;
|
||||||
|
end
|
||||||
|
f_return = 0;
|
||||||
|
endfunction
|
||||||
endmodule
|
endmodule
|
||||||
|
|||||||
Executable
+22
@@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2008 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 (
|
||||||
|
v_flags2 => ["--lint-only"],
|
||||||
|
fails=>1,
|
||||||
|
expect=>
|
||||||
|
'%Warning-IMPLICIT: t/t_lint_implicit_def_bad.v:\d+: Signal definition not found, creating implicitly: imp_warn
|
||||||
|
%Warning-IMPLICIT: Use "/\* verilator lint_off IMPLICIT \*/" and lint_on around source to disable this message.
|
||||||
|
%Error: t/t_lint_implicit_def_bad.v:\d+: Signal definition not found, and implicit disabled with `default_nettype: imp_err
|
||||||
|
%Error: Exiting due to.*',
|
||||||
|
) if $Self->{v3};
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed into the Public Domain, for any use,
|
||||||
|
// without warranty, 2008 by Wilson Snyder.
|
||||||
|
|
||||||
|
module t (a,z);
|
||||||
|
input a;
|
||||||
|
output z;
|
||||||
|
|
||||||
|
assign imp_warn = 1'b1;
|
||||||
|
// verilator lint_off IMPLICIT
|
||||||
|
assign imp_ok = 1'b1;
|
||||||
|
|
||||||
|
`default_nettype none
|
||||||
|
assign imp_err = 1'b1;
|
||||||
|
|
||||||
|
`default_nettype wire
|
||||||
|
assign imp_ok2 = 1'b1;
|
||||||
|
|
||||||
|
`default_nettype none
|
||||||
|
`resetall
|
||||||
|
assign imp_ok3 = 1'b1;
|
||||||
|
endmodule
|
||||||
@@ -244,13 +244,64 @@ $display("bits %d %d", $bits(foo), `10);
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
1 /*verilator NOT IN DEFINE*/ (nodef)
|
1 /*verilator NOT IN DEFINE*/ (nodef)
|
||||||
2 /*verilator PART OF DEFINE*/ (hasdef)
|
2 /*verilator PART OF DEFINE*/ (hasdef)
|
||||||
3 /*verilator NOT PART OF DEFINE*/ (nodef)
|
3 /*verilator NOT PART OF DEFINE*/ (nodef)
|
||||||
4 /*verilator PART OF DEFINE*/ (nodef)
|
4 /*verilator PART OF DEFINE*/ (nodef)
|
||||||
|
5 also in also3 (nodef)
|
||||||
|
|
||||||
|
|
||||||
HAS a NEW LINE
|
HAS a NEW LINE
|
||||||
|
|
||||||
|
|
||||||
`line 203 "t/t_preproc.v" 2
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
EXP: clxx_scen
|
||||||
|
clxx_scen
|
||||||
|
EXP: clxx_scen
|
||||||
|
"clxx_scen"
|
||||||
|
|
||||||
|
EXP: do if (start("verilog/inc1.v", 25)) begin message({"Blah-", "clx_scen", " end"}); end while(0);
|
||||||
|
do
|
||||||
|
`line 231 "t/t_preproc.v" 0
|
||||||
|
if (start("t/t_preproc.v", 231)) begin message({"Blah-", "clx_scen", " end"}); end while(0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
`line 241 "t/t_preproc.v" 0
|
||||||
|
|
||||||
|
|
||||||
|
EXP: This is fooed
|
||||||
|
This is fooed
|
||||||
|
|
||||||
|
EXP: This is fooed_2
|
||||||
|
This is fooed_2
|
||||||
|
|
||||||
|
|
||||||
|
`line 250 "t/t_preproc.v" 2
|
||||||
|
|||||||
@@ -191,12 +191,57 @@ Line_Preproc_Check `__LINE__
|
|||||||
OF DEFINE */
|
OF DEFINE */
|
||||||
`define CMT4 /* verilator PART \
|
`define CMT4 /* verilator PART \
|
||||||
OF DEFINE */
|
OF DEFINE */
|
||||||
|
`define CMT5 // CMT NOT \
|
||||||
|
also in // BUT TEXT IS \
|
||||||
|
also3 // CMT NOT
|
||||||
|
|
||||||
1 `CMT1 (nodef)
|
1 `CMT1 (nodef)
|
||||||
2 `CMT2 (hasdef)
|
2 `CMT2 (hasdef)
|
||||||
3 `CMT3 (nodef)
|
3 `CMT3 (nodef)
|
||||||
4 `CMT4 (nodef)
|
4 `CMT4 (nodef)
|
||||||
|
5 `CMT5 (nodef)
|
||||||
`define NL HAS a NEW \
|
`define NL HAS a NEW \
|
||||||
LINE
|
LINE
|
||||||
`NL
|
`NL
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
|
`define msg_fatal(log, msg) \
|
||||||
|
do \
|
||||||
|
/* synopsys translate_off */ \
|
||||||
|
`ifdef NEVER \
|
||||||
|
`error "WTF" \
|
||||||
|
`else \
|
||||||
|
if (start(`__FILE__, `__LINE__)) begin \
|
||||||
|
`endif \
|
||||||
|
message(msg); \
|
||||||
|
end \
|
||||||
|
/* synopsys translate_on */ \
|
||||||
|
while(0)
|
||||||
|
|
||||||
|
`define msg_scen_(cl) cl``_scen
|
||||||
|
`define MSG_MACRO_TO_STRING(x) `"x`"
|
||||||
|
|
||||||
|
EXP: clxx_scen
|
||||||
|
`msg_scen_(clxx)
|
||||||
|
EXP: clxx_scen
|
||||||
|
`MSG_MACRO_TO_STRING(`msg_scen_(clxx))
|
||||||
|
`define mf(clx) `msg_fatal(this.log, {"Blah-", `MSG_MACRO_TO_STRING(`msg_scen_(clx)), " end"});
|
||||||
|
EXP: do if (start("verilog/inc1.v", 25)) begin message({"Blah-", "clx_scen", " end"}); end while(0);
|
||||||
|
`mf(clx)
|
||||||
|
|
||||||
|
//======================================================================
|
||||||
|
|
||||||
|
`define makedefine(name) \
|
||||||
|
`define def_``name This is name \
|
||||||
|
`define def_``name``_2 This is name``_2 \
|
||||||
|
|
||||||
|
`makedefine(fooed)
|
||||||
|
`ifndef def_fooed `error "No def_fooed" `endif
|
||||||
|
//`ifndef def_fooed_2 `error "No def_fooed_2" `endif
|
||||||
|
EXP: This is fooed
|
||||||
|
`def_fooed
|
||||||
|
EXP: This is fooed_2
|
||||||
|
`def_fooed_2
|
||||||
|
|
||||||
|
//======================================================================
|
||||||
|
|||||||
@@ -13,7 +13,10 @@ module t (/*AUTOARG*/);
|
|||||||
repeat (0) $stop;
|
repeat (0) $stop;
|
||||||
repeat (-1) $stop;
|
repeat (-1) $stop;
|
||||||
negcnt = 'sb111;
|
negcnt = 'sb111;
|
||||||
|
// Not all commercial simulators agree on the below stopping or not
|
||||||
|
// verilator lint_off WIDTH
|
||||||
repeat (negcnt) $stop;
|
repeat (negcnt) $stop;
|
||||||
|
// verilator lint_on WIDTH
|
||||||
repeat (5) begin
|
repeat (5) begin
|
||||||
repeat (2) begin
|
repeat (2) begin
|
||||||
times = times + 1;
|
times = times + 1;
|
||||||
|
|||||||
+11
-4
@@ -24,17 +24,19 @@ include $(VERILATOR_ROOT)/include/verilated.mk
|
|||||||
DEBUG_ON = --debug
|
DEBUG_ON = --debug
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
|
ifneq ($(SYSTEMC),)
|
||||||
test_default: precopy prep preproc compile run
|
test_default: precopy prep preproc compile run
|
||||||
test_debug: precopy prep_dbg preproc compile run
|
test_debug: precopy prep_dbg preproc compile run
|
||||||
|
else
|
||||||
|
test_default: nosc
|
||||||
|
test_debug: nosc
|
||||||
|
endif
|
||||||
|
|
||||||
V_FLAGS = -f $(VERILATOR_ROOT)/test_v/input.vc
|
V_FLAGS = -f $(VERILATOR_ROOT)/test_v/input.vc
|
||||||
VERILATOR_FLAGS = --sc $(V_FLAGS) top.v
|
VERILATOR_FLAGS = --sc $(V_FLAGS) top.v
|
||||||
VERILATOR_FLAGS += --trace
|
VERILATOR_FLAGS += --trace
|
||||||
|
|
||||||
precopy: obj_dir obj_dir/sc_main.cpp
|
precopy:
|
||||||
obj_dir/sc_main.cpp: ../test_sp/sc_main.cpp
|
|
||||||
mkdir -p obj_dir
|
|
||||||
cp $^ $@
|
|
||||||
|
|
||||||
prep:
|
prep:
|
||||||
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(VERILATOR_FLAGS)
|
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(VERILATOR_FLAGS)
|
||||||
@@ -55,6 +57,11 @@ run:
|
|||||||
obj_dir:
|
obj_dir:
|
||||||
mkdir $@
|
mkdir $@
|
||||||
|
|
||||||
|
nosc:
|
||||||
|
@echo
|
||||||
|
@echo %Skip: SYSTEMC not in environment
|
||||||
|
@echo
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
maintainer-copy::
|
maintainer-copy::
|
||||||
|
|||||||
@@ -31,6 +31,4 @@ simx: sc_main.o $(VK_GLOBAL_OBJS) \
|
|||||||
$(VM_PREFIX)__ALL.a $(SC_LIB)
|
$(VM_PREFIX)__ALL.a $(SC_LIB)
|
||||||
$(LINK) $(LDFLAGS) -g $^ $(LOADLIBES) $(LDLIBS) -o $@ $(SC_LIBS) $(LIBS) 2>&1 | c++filt
|
$(LINK) $(LDFLAGS) -g $^ $(LOADLIBES) $(LDLIBS) -o $@ $(SC_LIBS) $(LIBS) 2>&1 | c++filt
|
||||||
|
|
||||||
VPATH += ../test_sp
|
|
||||||
|
|
||||||
sc_main.o: sc_main.cpp $(VM_PREFIX).h
|
sc_main.o: sc_main.cpp $(VM_PREFIX).h
|
||||||
|
|||||||
+19
-3
@@ -24,9 +24,15 @@ include $(VERILATOR_ROOT)/include/verilated.mk
|
|||||||
DEBUG_ON = --debug --trace-dups
|
DEBUG_ON = --debug --trace-dups
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
test_default: prep preproc compile run coverage
|
ifneq ($(SYSTEMPERL),)
|
||||||
test_debug: prep_dbg preproc compile_dbg run coverage
|
test_default: precopy prep preproc compile run coverage
|
||||||
test_nopublic: prep_dbg_np preproc compile_dbg run coverage
|
test_debug: precopy prep_dbg preproc compile_dbg run coverage
|
||||||
|
test_nopublic: precopy prep_dbg_np preproc compile_dbg run coverage
|
||||||
|
else
|
||||||
|
test_default: nosp
|
||||||
|
test_debug: nosp
|
||||||
|
test_nopublic: nosp
|
||||||
|
endif
|
||||||
|
|
||||||
V_FLAGS = -f $(VERILATOR_ROOT)/test_v/input.vc
|
V_FLAGS = -f $(VERILATOR_ROOT)/test_v/input.vc
|
||||||
|
|
||||||
@@ -35,6 +41,11 @@ V_FLAGS = -f $(VERILATOR_ROOT)/test_v/input.vc
|
|||||||
VERILATOR_FLAGS = --public --output-split-cfuncs 1000 --output-split 1000 \
|
VERILATOR_FLAGS = --public --output-split-cfuncs 1000 --output-split 1000 \
|
||||||
--sp --coverage --stats --trace $(V_FLAGS) top.v
|
--sp --coverage --stats --trace $(V_FLAGS) top.v
|
||||||
|
|
||||||
|
precopy: obj_dir obj_dir/sc_main.cpp
|
||||||
|
obj_dir/sc_main.cpp: ../test_sc/sc_main.cpp
|
||||||
|
mkdir -p obj_dir
|
||||||
|
cp $^ $@
|
||||||
|
|
||||||
prep:
|
prep:
|
||||||
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(VERILATOR_FLAGS)
|
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(VERILATOR_FLAGS)
|
||||||
prep_dbg:
|
prep_dbg:
|
||||||
@@ -62,6 +73,11 @@ coverage:
|
|||||||
obj_dir:
|
obj_dir:
|
||||||
mkdir $@
|
mkdir $@
|
||||||
|
|
||||||
|
nosp:
|
||||||
|
@echo
|
||||||
|
@echo %Skip: SYSTERMPERL not in environment
|
||||||
|
@echo
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
maintainer-copy::
|
maintainer-copy::
|
||||||
|
|||||||
Reference in New Issue
Block a user