Compare commits

..
20 Commits
Author SHA1 Message Date
Wilson Snyder 6ef44a6fbb Version bump 2010-03-17 07:59:12 -04:00
Wilson Snyder 2afe40a0b5 verilated: Add debug pointers to scopeDump() 2010-03-16 19:28:29 -04:00
Wilson Snyder e57d004718 Fix clock-gates with non-AND complex logic, bug220. 2010-03-16 18:50:26 -04:00
Wilson Snyder d780d0aabb Fix flushing VCD buffers on . 2010-03-12 20:00:08 -05:00
Wilson Snyder 0f9e3f0767 Cleanup flex compiles again - remove yyleng from preproc.cpp 2010-03-05 12:02:56 -05:00
Wilson Snyder 381972c923 Fix Mac OS-X compile issues, bug217. 2010-02-26 19:50:44 -05:00
Wilson Snyder 845d7ad718 Commentary 2010-02-26 18:57:34 -05:00
Wilson Snyder f1b6c0c559 Support "`default_nettype none|wire". 2010-02-23 09:27:16 -05:00
Wilson Snyder e39eddf3fe Fix parametrized defines with empty arguments. 2010-02-21 07:20:39 -05:00
Wilson Snyder 72218fb475 Defines with // comments still need continuation - spec ambiguity 2010-02-18 20:57:46 -05:00
Wilson Snyder 9a3e497c22 Fix specparam defaults 2010-02-18 08:43:16 -05:00
Wilson Snyder 85d510cd48 Fix vl_mc_scan_plusarg returning stack based pointer 2010-02-16 11:54:39 -05:00
Wilson Snyder 786c65ea5f Makefile: reconfigure when src/*.in changes 2010-02-15 07:34:55 -05:00
Wilson Snyder 10e6f61125 Commentary 2010-02-14 19:23:29 -05:00
Wilson Snyder cdd06e7236 Support "break", "continue", "return". 2010-02-14 10:01:21 -05:00
Wilson Snyder 48603c0ee2 Commentary 2010-02-10 08:50:41 -05:00
Wilson Snyder 63f30492be Skip SystemC tests if not installed. 2010-02-08 20:51:43 -05:00
Wilson Snyder 0e8772290d Fix make uninstall, bug216 2010-02-08 09:28:40 -05:00
Wilson Snyder 6cfc5798b0 Tests: Move sc_main.cpp as there's more sc than sp users 2010-02-08 08:10:07 -05:00
Wilson Snyder 6be275f5d4 Post release version bump 2010-02-08 06:27:07 -05:00
56 changed files with 1659 additions and 339 deletions
+18
View File
@@ -3,6 +3,24 @@ Revision history for Verilator
The contributors that suggested a given feature are shown in []. [by ...]
indicates the contributor was also the author of the fix; Thanks!
* Verilator 3.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
Application visible changes:
+49 -29
View File
@@ -145,8 +145,6 @@ INST_PROJ_BIN_FILES = \
DISTFILES := $(DISTFILES_INC)
VL_INST_MAN_FILES = verilator.1
ifeq ($(OBJCACHE_JOBS),)
ifneq ($(OBJCACHE_HOSTS),)
export OBJCACHE_JOBS := -j $(shell objcache --jobs "$(OBJCACHE_HOSTS)")
@@ -238,11 +236,25 @@ internals.txt: internals.pod
-rm -f $@
$(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 \
verilator_includer verilator_profcfunc
# Some scripts go into both the search path and pkgdatadir,
# 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:
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(bindir)
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator $(DESTDIR)$(bindir)/verilator )
@@ -259,16 +271,35 @@ installman: $(VL_INST_MAN_FILES)
done
installdata:
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/include/vltstd $(DESTDIR)$(pkgdatadir)/examples
cp -r include/*.* $(DESTDIR)$(pkgdatadir)/include
cp -r ${srcdir}/include/*.* $(DESTDIR)$(pkgdatadir)/include
cp -r ${srcdir}/include/vltstd/*.* $(DESTDIR)$(pkgdatadir)/include/vltstd
cp -r ${srcdir}/test_c $(DESTDIR)$(pkgdatadir)/examples
cp -r ${srcdir}/test_sc $(DESTDIR)$(pkgdatadir)/examples
cp -r ${srcdir}/test_sp $(DESTDIR)$(pkgdatadir)/examples
cp -r ${srcdir}/test_v $(DESTDIR)$(pkgdatadir)/examples
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/include/vltstd
for p in $(VL_INST_INC_FILES) ; do \
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkgdatadir)/$$p; \
done
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_c
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_sc
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_sp
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_v
for p in $(VL_INST_DATA_FILES) ; do \
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkgdatadir)/examples/$$p; \
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-here: installman ftp
@@ -313,26 +344,15 @@ install-msg:
@echo "See 'verilator.txt' for documentation."
@echo
uninstall:
-cd $(DESTDIR)$(mandir)/man1 && rm -f $(VL_INST_MAN_FILES)
-cd $(DESTDIR)$(bindir) && rm -f $(VL_INST_BIN_FILES)
-rm -f $(DESTDIR)$(pkgdatadir)
IN_WILD := ${srcdir}/*.in ${srcdir}/*/*.in
# autoheader might not change config_build.h.in, so touch a stamp file.
IN_WILD := ${srcdir}/*.in ${srcdir}/*/*.in ${srcdir}/*/*/*.in \
*.in */*.in */*.in
${srcdir}/config_build.h.in: stamp-h.in
${srcdir}/stamp-h.in: configure.ac $(wildcard $(IN_WILD))
# autoheader might not change config_build.h.in, so touch it
${srcdir}/config_build.h: ${srcdir}/config_build.h.in configure
cd ${srcdir} && autoheader
echo timestamp > ${srcdir}/stamp-h.in
config_build.h: stamp-h
stamp-h: config_build.h.in config.status
./config.status
Makefile: Makefile.in config.status
./config.status
src/Makefile: src/Makefile.in config.status
touch $@
Makefile: Makefile.in config.status $(IN_WILD)
./config.status
src/Makefile: src/Makefile.in Makefile
config.status: configure
./config.status --recheck
configure: configure.ac
+94 -89
View File
@@ -6,129 +6,134 @@
// Version 2.0.
Features:
Latch optimizations {Need here}
Task I/Os connecting to non-simple variables.
Fix ordering of each bit separately in a signal (mips)
Language support:
* Fix ordering of each bit separately in a signal (mips)
assign b[3:0] = b[7:4]; assign b[7:4] = in;
Support gate primitives/ cell libraries from xilinx, etc
Assign dont_care value to an 1'bzzz assignment
Function to eval combo logic after /*verilator public*/ functions [gwaters]
Support generated clocks (correctness)
?gcov coverage
Selectable SystemC types based on widths (see notes below)
Coverage
Points should be per-scope like everything else rather then per-module
Expression coverage (see notes)
Constant functions for widths, etc, IE "input [log2(PARAM):0] xx;"
More Verilog 2001 Support
(* *) Attributes (just ignore -- preprocessor?)
Real numbers (NEVER)
Recursive functions (NEVER)
Verilog configuration files (NEVER)
DPI to define C/C++ calls from Verilog
* Support UDP gate primitives/ cell libraries
(have code for combos - problem is sequential udps)
* Function to eval combo logic after /*verilator public*/ functions [gwaters]
* Support generated clocks (correctness)
* Real numbers
* Recursive functions
* Verilog configuration files
* Structs/unions (have starting point)
* DPI to define C/C++ calls from Verilog
* Expression coverage (see notes)
* Better tristate support
Long-term Features
Assertions
VHDL parser [Philips]
Tristate support
SystemPerl integration
Multithreaded execution
* Assertions
* Tristate support
* 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:
Capture all inputs into global "rerun it" file
Code to make wrapper that sets signals, so can do comparison checks
New random program generator
Better graph viewer with search and zoom
Port and test against opencores.org code
* Move test_c/sp/v/verilated into test_regress format (4.000?)
* Capture all inputs into global "rerun it" file
* Code to make wrapper that sets signals, so can do comparison checks
* New random program generator
* Better graph viewer with search and zoom
* Port and test against opencores.org code
Usability:
Better reporting of unopt problems, including what lines of code
Report more errors (all of them?) before exiting [Eugene Weber]
* Detect and pre-remove most UNOPTFLATs (4.000)
* 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:
Eliminate the AstNUser* passed to all visitors; its only needed in V3Width,
and removing it will speed up and simplify all the other code.
V3Graph should be templated container type, taking in Vertex + Edge types
* Eliminate the AstNUser* passed to all visitors; its only needed in V3Width,
and removing it will speed up and simplify all the other code.
* 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:
Constant propagation
* Latch optimizations
* Constant propagation
Extra cleaning AND: 1 & ((VARREF >> 1) | ((&VARREF >> 1) & 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.
Negedge reset
* Negedge reset
Switch to remove negedges that don't matter
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
Multithreaded execution
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
* If all references to array have a constant index, blow up into separate signals-per-index
* 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
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
Used in t_mem for array delayed assignments
Replace variables if set later in same cfunc branch
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 ..."
Careful though, as b could appear in the statement or multiple times 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 )
Combine variables into wider elements
* Combine variables into wider elements
Parallel statements on different bits should become single signal
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
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)
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.
Usually blocks/values
* Usually blocks/values
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
Allow Split of case statements without a $display/$stop
I-cache packing improvements (what/how?)
Data cache organization (order of vars in class)
* 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
* I-cache packing improvements (what/how?)
* Data cache organization (order of vars in class)
First have clocks,
then bools instead of uint32_t's
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.
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)
Track recirculation and convert into clock-enables
Clock enables should become new clocking domains for speed
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)
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 (===)
* Track recirculation and convert into clock-enables
* Clock enables should become new clocking domains for speed
* 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)
+5 -5
View File
@@ -878,7 +878,7 @@ section below for descriptions of some of the files that were created.
We then can compile it
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
--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
make -f Vour.mk Vour__ALL.a
make -f Vour.mk ../sc_main.o
make -f Vour.mk verilated.o
make -j -f Vour.mk Vour__ALL.a
make -j -f Vour.mk ../sc_main.o verilated.o
And link with SystemC. Note your path to the libraries may vary,
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
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
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*/
+25 -4
View File
@@ -33,7 +33,11 @@
//===========================================================================
// Global variables
// Slow path variables
int Verilated::s_randReset = 0;
VerilatedVoidCb Verilated::s_flushCb = NULL;
// Keep below together in one cache line
int Verilated::s_debug = 1;
bool Verilated::s_calcUnusedSigs = 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);
if (Verilated::gotFinish()) {
VL_PRINTF("- %s:%d: Second verilog $finish, exiting\n", filename, linenum);
Verilated::flushCall();
exit(0);
}
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
void vl_stop (const char* filename, int linenum, const char* hier) {
Verilated::gotFinish(true);
Verilated::flushCall();
vl_fatal (filename,linenum,hier,"Verilog $stop");
}
#endif
@@ -71,6 +77,7 @@ void vl_fatal (const char* filename, int linenum, const char* hier, const char*
if (0 && hier) {}
Verilated::gotFinish(true);
VL_PRINTF("%%Error: %s:%d: %s\n", filename, linenum, msg);
Verilated::flushCall();
abort();
}
#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) {
string match = VerilatedImp::argPlusMatch(prefixp);
if (match == "") return 0;
else return match.c_str()+strlen(prefixp)+1; // +1 to skip the "+"
static VL_THREAD char outstr[VL_VALUE_STRING_MAX_WIDTH];
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;
}
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) {
VerilatedImp::commandArgs(argc,argv);
}
@@ -1058,10 +1078,11 @@ void* VerilatedScope::exportFindError(int funcnum) 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++) {
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
View File
@@ -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 WData* WDataOutP; ///< Array output from a function
typedef void (*VerilatedVoidCb)(void);
class SpTraceVcd;
class SpTraceVcdCFile;
class VerilatedVcd;
@@ -149,11 +151,12 @@ class VerilatedSyms {
class VerilatedScope {
// Fastpath:
VerilatedSyms* m_symsp; ///< Symbol table
void** m_callbacksp; ///< Callback table pointer (Fastpath)
int m_funcnumMax; ///< Maxium function number stored (Fastpath)
VerilatedSyms* m_symsp; ///< Symbol table
void** m_callbacksp; ///< Callback table pointer (Fastpath)
int m_funcnumMax; ///< Maxium function number stored (Fastpath)
// 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
VerilatedScope();
~VerilatedScope();
@@ -182,7 +185,11 @@ public: // But internals only - called from VerilatedModule's
struct Verilated {
// MEMBERS
private:
// Slow path variables
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 bool s_calcUnusedSigs; ///< Waves file on, need all signals calculated
static bool s_gotFinish; ///< A $finish statement executed
@@ -224,6 +231,9 @@ public:
/// Enable/disable assertions
static void assertOn(bool flag) { s_assertOn=flag; }
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
static void commandArgs(int argc, const char** argv);
+5
View File
@@ -88,6 +88,11 @@ void VerilatedVcd::open (const char* filename) {
m_filename = filename;
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);
if (!isOpen()) return;
+143 -54
View File
@@ -40,7 +40,148 @@ Modify the later visitor functions to process the new feature as needed.
=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
the obj_dir, .tree and .dot files.
@@ -94,59 +235,7 @@ variable is an output.
=back
=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 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
=head2 Debugging with GDB
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
+7 -5
View File
@@ -121,6 +121,7 @@ HEADERS = $(wildcard V*.h v*.h)
ASTGEN = $(srcdir)/astgen
BISONPRE = $(srcdir)/bisonpre
FLEXFIX = $(srcdir)/flexfix
######################################################################
#### Top level
@@ -194,8 +195,9 @@ RAW_OBJS = \
V3Link.o \
V3LinkCells.o \
V3LinkDot.o \
V3LinkLevel.o \
V3LinkJump.o \
V3LinkLValue.o \
V3LinkLevel.o \
V3LinkParse.o \
V3LinkResolve.o \
V3Localize.o \
@@ -295,15 +297,15 @@ V3Lexer_pregen.yy.cpp: verilog.l V3ParseBison.h $(HEADERS)
${LEX} --version
${LEX} ${LFLAGS} -o$@ $<
V3Lexer.yy.cpp: V3Lexer_pregen.yy.cpp
$(PERL) $(srcdir)/flexfix <$< >$@
V3Lexer.yy.cpp: V3Lexer_pregen.yy.cpp $(FLEXFIX)
$(PERL) $(FLEXFIX) V3Lexer <$< >$@
V3PreLex_pregen.yy.cpp: V3PreLex.l $(HEADERS)
${LEX} --version
${LEX} ${LFLAGS} -o$@ $<
V3PreLex.yy.cpp: V3PreLex_pregen.yy.cpp
$(PERL) $(srcdir)/flexfix <$< >$@
V3PreLex.yy.cpp: V3PreLex_pregen.yy.cpp $(FLEXFIX)
$(PERL) $(FLEXFIX) V3PreLex <$< >$@
######################################################################
######################################################################
+2
View File
@@ -761,6 +761,7 @@ public:
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
bool brokeExists() const;
bool brokeExistsAbove() const;
// CONSTRUCTORS
virtual ~AstNode();
@@ -870,6 +871,7 @@ public:
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
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 replaceWith(AstNode* newp); // Replace current node in tree with new node
void v3errorEnd(ostringstream& str) const;
+6
View File
@@ -494,6 +494,12 @@ void AstDisplay::dump(ostream& str) {
this->AstNode::dump(str);
//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) {
this->AstNode::dump(str);
str<<" -> ";
+81 -10
View File
@@ -1846,14 +1846,6 @@ struct AstGenFor : public AstNodeFor {
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 {
AstRepeat(FileLine* fileline, AstNode* countp, AstNode* bodysp)
: AstNodeStmt(fileline) {
@@ -1869,16 +1861,18 @@ struct AstRepeat : 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) {
setOp2p(condp); addNOp3p(bodysp);
setOp2p(condp); addNOp3p(bodysp); addNOp4p(incsp);
}
ASTNODE_NODE_FUNCS(While, WHILE)
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* 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 addBodysp(AstNode* newp) { addOp3p(newp); }
void addIncsp(AstNode* newp) { addOp4p(newp); }
virtual bool isGateOptimizable() const { return false; }
virtual int instrCount() const { return instrCountBranch(); }
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
};
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 {
AstGenIf(FileLine* fileline, AstNode* condp, AstNode* ifsp, AstNode* elsesp)
: AstNodeIf(fileline, condp, ifsp, elsesp) {
@@ -1901,6 +1925,53 @@ struct AstIf : public AstNodeIf {
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 {
// Quasi-while loop until given signals are stable
// Parents: CFUNC (generally)
-47
View File
@@ -135,53 +135,6 @@ private:
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*) {
// If there's a %m in the display text, we add a special node that will contain the name()
// Similar code in V3Inline
+24
View File
@@ -52,6 +52,7 @@ private:
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_LEAKED = 0x08; // Known to have been leaked
static const int FLAG_UNDER_NOW = 0x10; // Is in tree as parent of current node
public:
// METHODS
static void deleted(const AstNode* nodep) {
@@ -74,6 +75,15 @@ public:
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) {
#ifndef VL_LEAK_CHECKS
if (!linkable) return; // save some time, else the map will get huge!
@@ -111,6 +121,14 @@ public:
if (!(iter->second & FLAG_LINKABLE)) return false;
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() {
#ifndef VL_LEAK_CHECKS
s_nodes.clear();
@@ -152,6 +170,10 @@ bool AstNode::brokeExists() const {
// Called by node->broken() routines to do table lookup
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 {
private:
virtual void visit(AstNode* nodep, AstNUser*) {
BrokenTable::setUnder(nodep,true);
if (nodep->broken()) {
nodep->v3fatalSrc("Broken link in node (or something without maybePointedTo)\n");
}
@@ -192,6 +215,7 @@ private:
}
}
nodep->iterateChildren(*this);
BrokenTable::setUnder(nodep,false);
}
public:
// CONSTUCTORS
+27 -1
View File
@@ -96,6 +96,7 @@ private:
// ** 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.
// AstVar::user4p -> Used by ConstVarMarkVisitor/ConstVarFindVisitor
// AstJumpLabel::user4 -> bool. Set when AstJumpGo uses this label
// STATE
bool m_params; // If true, propogate parameterized and true numbers only
@@ -1487,7 +1488,8 @@ private:
nodep->iterateChildren(*this);
if (nodep->condp()->isZero()) {
UINFO(4,"WHILE(0) => nop "<<nodep<<endl);
nodep->unlinkFrBack();
if (nodep->precondsp()) nodep->replaceWith(nodep->precondsp());
else nodep->unlinkFrBack();
nodep->deleteTree(); nodep=NULL;
}
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
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
// "AstNODETYPE { # bracket not paren
+10
View File
@@ -360,12 +360,22 @@ public:
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*) {
nodep->precondsp()->iterateAndNext(*this);
puts("while (");
nodep->condp()->iterateAndNext(*this);
puts(") {\n");
nodep->bodysp()->iterateAndNext(*this);
nodep->incsp()->iterateAndNext(*this);
nodep->precondsp()->iterateAndNext(*this); // Need to recompute before next loop
puts("}\n");
}
+7
View File
@@ -75,6 +75,7 @@ class EmitCSyms : EmitCBaseVisitor {
ScopeFuncs m_scopeFuncs; // Each {scope,dpiexportfunc}
V3LanguageWords m_words; // Reserved word detector
int m_coverBins; // Coverage bin number
int m_labelNum; // Next label number
// METHODS
void emitSymHdr();
@@ -114,6 +115,7 @@ class EmitCSyms : EmitCBaseVisitor {
virtual void visit(AstNodeModule* nodep, AstNUser*) {
nameCheck(nodep);
m_modp = nodep;
m_labelNum = 0;
nodep->iterateChildren(*this);
m_modp = NULL;
}
@@ -138,6 +140,10 @@ class EmitCSyms : EmitCBaseVisitor {
nodep->binNum(m_coverBins++);
}
}
virtual void visit(AstJumpLabel* nodep, AstNUser*) {
nodep->labelNum(++m_labelNum);
nodep->iterateChildren(*this);
}
virtual void visit(AstCFunc* nodep, AstNUser*) {
if (nodep->dpiImport() || nodep->dpiExportWrapper()) {
m_dpis.push_back(nodep);
@@ -160,6 +166,7 @@ public:
m_funcp = NULL;
m_modp = NULL;
m_coverBins = 0;
m_labelNum = 0;
nodep->accept(*this);
}
};
+22
View File
@@ -135,6 +135,10 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
nodep->rhsp()->iterateAndNext(*this);
if (!m_suppressSemi) puts(";\n");
}
virtual void visit(AstBreak* nodep, AstNUser*) {
putbs("break");
if (!m_suppressSemi) puts(";\n");
}
virtual void visit(AstSenTree* nodep, AstNUser*) {
// AstSenItem is called for dumping in isolation by V3Order
putfs(nodep,"@(");
@@ -180,6 +184,10 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
puts((string)"// "+nodep->name()+"\n");
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(AstCoverInc*, 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);
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*) {
putfs(nodep,nodep->verilogKwd());
putbs(" (");
@@ -272,6 +288,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
nodep->condp()->iterateAndNext(*this);
puts(") begin\n");
nodep->bodysp()->iterateAndNext(*this);
nodep->incsp()->iterateAndNext(*this);
nodep->precondsp()->iterateAndNext(*this); // Need to recompute before next loop
putfs(nodep,"end\n");
}
@@ -287,6 +304,11 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
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*) {
putfs(nodep,"$stop;\n");
}
+2 -1
View File
@@ -44,6 +44,7 @@ public:
// Boolean information we track per-line, but aren't errors
I_COVERAGE, // Coverage is on/off from /*verilator coverage_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:
E_MULTITOP, // Error: Multiple top level modules
E_TASKNSVAR, // Error: Task I/O not simple
@@ -91,7 +92,7 @@ public:
// Leading spaces indicate it can't be disabled.
" MIN", " SUPPRESS", " INFO", " FATAL", " FATALSRC", " ERROR",
// Boolean
" I_COVERAGE", " I_TRACING",
" I_COVERAGE", " I_TRACING", " I_DEF_NETTYPE_WIRE",
// Errors
"MULTITOP", "TASKNSVAR", "BLKLOOPINIT",
// Warnings
+23 -1
View File
@@ -288,6 +288,7 @@ private:
// STATE
LifeState* m_statep; // Current state
bool m_sideEffect; // Side effects discovered in assign RHS
bool m_noopt; // Disable optimization of variables in this block
// LIFE MAP
// 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
}
// 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();
if (!vscp) nodep->v3fatalSrc("Scope lost on variable");
m_lifep->simpleAssign(vscp, nodep);
@@ -388,6 +389,7 @@ private:
{
m_lifep = bodyLifep;
nodep->bodysp()->iterateAndNext(*this);
nodep->incsp()->iterateAndNext(*this);
m_lifep = prevLifep;
}
UINFO(4," joinfor"<<endl);
@@ -397,6 +399,25 @@ private:
delete condLifep;
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*) {
//UINFO(4," CCALL "<<nodep<<endl);
nodep->iterateChildren(*this);
@@ -432,6 +453,7 @@ public:
UINFO(4," LifeVisitor on "<<nodep<<endl);
m_statep = statep;
m_sideEffect = false;
m_noopt = false;
{
m_lifep = new LifeBlock (NULL, m_statep);
nodep->accept(*this);
+7 -1
View File
@@ -185,7 +185,13 @@ private:
// Create implicit after warning
if (linkVarName(forrefp)) { forrefp=NULL; return; }
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,
forrefp->name(), AstLogicPacked(), 1);
+227
View File
@@ -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);
}
+37
View File
@@ -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
+7
View File
@@ -75,6 +75,13 @@ private:
nodep->iterateChildren(*this);
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*) {
if (m_assertp) nodep->v3error("Assert not allowed under another assert");
m_assertp = nodep;
+38 -15
View File
@@ -941,28 +941,51 @@ void OrderVisitor::processBrokeLoop() {
// Clock propagation
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);
}
void OrderVisitor::processInputsIterate(OrderEitherVertex* vertexp) {
// Propagate PrimaryIn through simple assignments
if (vertexp->user()) return; // Already processed
//UINFO(9," InIt "<<vertexp<<endl);
vertexp->user(true);
if (OrderVarStdVertex* vvertexp = dynamic_cast<OrderVarStdVertex*>(vertexp)) {
vvertexp->isFromInput(true);
}
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
OrderEitherVertex* toVertexp = (OrderEitherVertex*)edgep->top();
if (OrderVarStdVertex* vvertexp = dynamic_cast<OrderVarStdVertex*>(toVertexp)) {
processInputsIterate(vvertexp);
if (0 && debug()>=9) {
UINFO(9," InIt "<<vertexp<<endl);
if (OrderLogicVertex* vvertexp = dynamic_cast<OrderLogicVertex*>(vertexp)) {
vvertexp->nodep()->dumpTree(cout,"- TT: ");
}
if (OrderLogicVertex* vvertexp = dynamic_cast<OrderLogicVertex*>(toVertexp)) {
if (AstNodeAssign* nodep = vvertexp->nodep()->castNodeAssign()) {
if (nodep->lhsp()->castVarRef()
&& nodep->rhsp()->castVarRef()) {
UINFO(9," Input reassignment: "<<vvertexp<<endl);
}
vertexp->user(true); // Processing
// First handle all inputs to this vertex, in most cases they'll be already processed earlier
// Also, determine if this vertex is an input
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);
}
}
+8 -6
View File
@@ -132,10 +132,11 @@ class OrderEitherVertex : public V3GraphVertex {
AstScope* m_scopep; // Scope the vertex is in
AstSenTree* m_domainp; // Clock domain (NULL = to be computed as we iterate)
OrderLoopId m_inLoop; // Loop number vertex is in
bool m_isFromInput; // From input, or derrived therefrom (conservatively false)
public:
OrderEitherVertex(V3Graph* graphp, AstScope* scopep, AstSenTree* domainp)
: V3GraphVertex(graphp), m_scopep(scopep), m_domainp(domainp)
, m_inLoop(LOOPID_UNKNOWN) {
, m_inLoop(LOOPID_UNKNOWN), m_isFromInput(false) {
}
virtual ~OrderEitherVertex() {}
// Methods
@@ -148,12 +149,16 @@ public:
AstSenTree* domainp() const { return m_domainp; }
OrderLoopId inLoop() const { return m_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 {
public:
OrderInputsVertex(V3Graph* graphp, AstSenTree* domainp)
: OrderEitherVertex(graphp, NULL, domainp) {}
: OrderEitherVertex(graphp, NULL, domainp) {
isFromInput(true); // By definition
}
virtual ~OrderInputsVertex() {}
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_INPUTS; }
virtual string name() const { return "*INPUTS*"; }
@@ -195,11 +200,10 @@ class OrderVarVertex : public OrderEitherVertex {
AstVarScope* m_varScp;
OrderVarVertex* m_pilNewVertexp; // for processInsLoopNewVar
bool m_isClock; // Used as clock
bool m_isFromInput; // From input, or derrived therefrom (conservatively false)
public:
OrderVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* 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* clone (V3Graph* graphp) const = 0;
@@ -208,8 +212,6 @@ public:
AstVarScope* varScp() const { return m_varScp; }
void isClock(bool flag) { m_isClock=flag; }
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; }
void pilNewVertexp (OrderVarVertex* vertexp) { m_pilNewVertexp = vertexp; }
};
+14 -3
View File
@@ -84,6 +84,11 @@
# define yyerrorf V3PreLexerrorf
#endif
#ifndef yyourleng
# define yyourleng V3PreLexourleng
# define yyourtext V3PreLexourtext
#endif
#ifndef YY_BUFFER_STATE
struct 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 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 );
void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer );
void yy_delete_buffer( YY_BUFFER_STATE b );
//======================================================================
// Class entry for each per-lexter state
#define KEEPCMT_SUB 2
//======================================================================
// Class entry for each per-lexter state
class V3PreLex {
public: // Used only by V3PreLex.cpp and V3PreProc.cpp
FileLine* m_curFilelinep; // Current processing point
+6
View File
@@ -33,6 +33,11 @@ V3PreLex* V3PreLex::s_currentLexp = NULL; // Current lexing point
#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
static void linenoInc() {LEXP->incLineno();}
static bool optPsl() { return V3PreProc::optPsl(); }
@@ -154,6 +159,7 @@ psl [p]sl
/* Reading definition value */
<DEFVAL>"/*" { LEXP->m_defCmtSlash=false; yy_push_state(DEFCMT); yymore(); } /* Special comment parser */
<DEFVAL>"//"[^\n\r]*[\\]{crnl} { linenoInc(); appendDefValue((char*)"\n",1); } /* Spec says // not part of define value */
<DEFVAL>"//"[^\n\r]* { return (VP_COMMENT);}
<DEFVAL>{drop} { }
<DEFVAL><<EOF>> { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); } /* Technically illegal, but people complained */
+30 -25
View File
@@ -71,7 +71,7 @@ class V3DefineRef {
string m_name; // Define last name being defined
string m_params; // Define parameter list for next expansion
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
public:
@@ -80,9 +80,10 @@ public:
string nextarg() const { return m_nextarg; }
void nextarg(const string& value) { m_nextarg = value; }
int parenLevel() const { return m_parenLevel; }
void parenLevel(int value) { m_parenLevel = value; }
vector<string>& args() { return m_args; }
V3DefineRef(const string& name, const string& params, int pl)
: m_name(name), m_params(params), m_parenLevel(pl) {}
V3DefineRef(const string& name, const string& params)
: m_name(name), m_params(params), m_parenLevel(0) {}
~V3DefineRef() {}
};
@@ -510,7 +511,9 @@ string V3PreProcImp::defineSubst(V3DefineRef* refp) {
if (*cp=='"') quote=!quote;
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");
return " `"+refp->name()+" ";
}
@@ -680,7 +683,7 @@ int V3PreProcImp::getRawToken() {
if (m_lineAdd) {
m_lineAdd--;
m_rawAtBol = true;
yytext=(char*)"\n"; yyleng=1;
yyourtext("\n",1);
if (debug()) debugToken(VP_WHITE, "LNA");
return (VP_WHITE);
}
@@ -692,11 +695,11 @@ int V3PreProcImp::getRawToken() {
if (!m_rawAtBol) rtncmt = "\n"+rtncmt;
m_lineCmtNl = false;
}
yytext=(char*)rtncmt.c_str(); yyleng=rtncmt.length();
yyourtext(rtncmt.c_str(), rtncmt.length());
m_lineCmt = "";
if (yyleng) m_rawAtBol = (yytext[yyleng-1]=='\n');
if (yyourleng()) m_rawAtBol = (yyourtext()[yyourleng()-1]=='\n');
if (m_state==ps_DEFVALUE) {
V3PreLex::s_currentLexp->appendDefValue(yytext,yyleng);
V3PreLex::s_currentLexp->appendDefValue(yyourtext(),yyourleng());
goto next_tok;
} else {
if (debug()) debugToken(VP_TEXT, "LCM");
@@ -718,14 +721,14 @@ int V3PreProcImp::getRawToken() {
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;
}
}
void V3PreProcImp::debugToken(int tok, const char* cmtp) {
if (debug()>4) {
string buf = string (yytext, yyleng);
string buf = string (yyourtext(), yyourleng());
string::size_type pos;
while ((pos=buf.find("\n")) != string::npos) { buf.replace(pos, 1, "\\n"); }
while ((pos=buf.find("\r")) != string::npos) { buf.replace(pos, 1, "\\r"); }
@@ -750,7 +753,7 @@ int V3PreProcImp::getToken() {
if (tok==VP_COMMENT) {
if (!m_off) {
if (m_lexp->m_keepComments == KEEPCMT_SUB) {
string rtn; rtn.assign(yytext,yyleng);
string rtn; rtn.assign(yyourtext(),yyourleng());
comment(rtn);
} else {
return (tok);
@@ -759,7 +762,7 @@ int V3PreProcImp::getToken() {
// 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
// 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;
}
if (tok==VP_LINE) {
@@ -774,7 +777,7 @@ int V3PreProcImp::getToken() {
case ps_DEFNAME: {
if (tok==VP_SYMBOL) {
m_state = ps_TOP;
m_lastSym.assign(yytext,yyleng);
m_lastSym.assign(yyourtext(),yyourleng());
if (m_stateFor==VP_IFDEF
|| m_stateFor==VP_IFNDEF) {
bool enable = defExists(m_lastSym);
@@ -876,11 +879,11 @@ int V3PreProcImp::getToken() {
m_state = ps_TOP;
// DEFVALUE is terminated by a return, but lex can't return both tokens.
// Thus, we emit a return here.
yytext=(char*)(newlines.c_str()); yyleng=newlines.length();
yyourtext(newlines.c_str(), newlines.length());
return(VP_WHITE);
}
case ps_DEFPAREN: {
if (tok==VP_TEXT && yyleng==1 && yytext[0]=='(') {
if (tok==VP_TEXT && yyourleng()==1 && yyourtext()[0]=='(') {
m_state = ps_DEFARG;
goto next_tok;
} else {
@@ -896,13 +899,13 @@ int V3PreProcImp::getToken() {
V3DefineRef* refp = &(m_defRefs.top());
refp->nextarg(refp->nextarg()+m_lexp->m_defValue); m_lexp->m_defValue="";
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());
m_state = ps_DEFARG;
m_lexp->pushStateDefArg(1);
refp->nextarg("");
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());
string out = defineSubst(refp);
// Substitute in and prepare for next action
@@ -929,7 +932,7 @@ int V3PreProcImp::getToken() {
// we'll append it when we push the argument.
break;
} 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);
goto next_tok;
} else {
@@ -941,7 +944,7 @@ int V3PreProcImp::getToken() {
case ps_INCNAME: {
if (tok==VP_STRING) {
m_state = ps_TOP;
m_lastSym.assign(yytext,yyleng);
m_lastSym.assign(yyourtext(),yyourleng());
UINFO(4,"Include "<<m_lastSym<<endl);
// Drop leading and trailing quotes.
m_lastSym.erase(0,1);
@@ -949,7 +952,7 @@ int V3PreProcImp::getToken() {
include(m_lastSym);
goto next_tok;
}
else if (tok==VP_TEXT && yyleng==1 && yytext[0]=='<') {
else if (tok==VP_TEXT && yyourleng()==1 && yyourtext()[0]=='<') {
// include <filename>
m_state = ps_INCNAME; // Still
m_lexp->pushStateIncFilename();
@@ -969,7 +972,7 @@ int V3PreProcImp::getToken() {
if (tok==VP_STRING) {
m_state = ps_TOP;
if (!m_off) {
m_lastSym.assign(yytext,yyleng);
m_lastSym.assign(yyourtext(),yyourleng());
fileline()->v3error(m_lastSym);
}
goto next_tok;
@@ -1022,7 +1025,7 @@ int V3PreProcImp::getToken() {
case VP_DEFREF: {
if (!m_off) {
string name; name.append(yytext+1,yyleng-1);
string name; name.append(yyourtext()+1,yyourleng()-1);
UINFO(4,"DefRef "<<name<<endl);
if (m_defDepth++ > V3PreProc::DEFINE_RECURSION_LEVEL_MAX) {
fileline()->v3error("Recursive `define substitution: `"+name);
@@ -1054,7 +1057,9 @@ int V3PreProcImp::getToken() {
}
else { // Found, with parameters
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_lexp->pushStateDefArg(0);
goto next_tok;
@@ -1107,7 +1112,7 @@ string V3PreProcImp::getline() {
while (NULL==(rtnp=strchr(m_lineChars.c_str(),'\n')) && !gotEof) {
int tok = getToken();
if (debug()>4) {
string buf = string (yytext, yyleng);
string buf = string (yyourtext(), yyourleng());
string::size_type pos;
while ((pos=buf.find("\n")) != string::npos) { buf.replace(pos, 1, "\\n"); }
while ((pos=buf.find("\r")) != string::npos) { buf.replace(pos, 1, "\\r"); }
@@ -1126,7 +1131,7 @@ string V3PreProcImp::getline() {
m_lineChars.append(" psl ");
}
else {
m_lineChars.append(yytext,0,yyleng);
m_lineChars.append(yyourtext(),0,yyourleng());
}
}
+1
View File
@@ -170,6 +170,7 @@ private:
m_inWhilep = NULL;
startStatement(nodep);
nodep->bodysp()->iterateAndNext(*this);
nodep->incsp()->iterateAndNext(*this);
m_stmtp = NULL;
}
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
+1
View File
@@ -143,6 +143,7 @@ private:
//=======
// 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); }
// Inherit from others
+60 -8
View File
@@ -88,6 +88,7 @@ private:
bool m_inDlyAssign; ///< Under delayed assignment
int m_instrCount; ///< Number of nodes
int m_dataCount; ///< Bytes of data
AstJumpGo* m_jumpp; ///< Jump label we're branching from
// Simulating:
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
@@ -230,8 +231,14 @@ private:
: 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
virtual void visit(AstAlways* nodep, AstNUser*) {
if (jumpingOver(nodep)) return;
checkNodeInfo(nodep);
nodep->iterateChildren(*this);
}
@@ -239,6 +246,7 @@ private:
// Sensitivities aren't inputs per se; we'll keep our tree under the same sens.
}
virtual void visit(AstVarRef* nodep, AstNUser*) {
if (jumpingOver(nodep)) return;
if (!optimizable()) return; // Accelerate
AstNode* vscp = varOrScope(nodep);
@@ -285,16 +293,19 @@ private:
}
}
virtual void visit(AstVarXRef* nodep, AstNUser*) {
if (jumpingOver(nodep)) return;
if (m_scoped) { badNodeType(nodep); return; }
else { clearOptimizable(nodep,"Language violation: Dotted hierarchical references not allowed in constant functions"); }
}
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
if (jumpingOver(nodep)) return;
if (!m_params) { badNodeType(nodep); return; }
if (nodep->dpiImport()) { clearOptimizable(nodep,"DPI import functions aren't simulatable"); }
checkNodeInfo(nodep);
nodep->iterateChildren(*this);
}
virtual void visit(AstNodeIf* nodep, AstNUser*) {
if (jumpingOver(nodep)) return;
UINFO(5," IF "<<nodep<<endl);
checkNodeInfo(nodep);
if (m_checkOnly) {
@@ -364,6 +375,7 @@ private:
}
}
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
if (jumpingOver(nodep)) return;
if (!optimizable()) return; // Accelerate
if (nodep->castAssignDly()) {
if (m_anyAssignComb) clearOptimizable(nodep, "Mix of dly/non dly assigns");
@@ -400,6 +412,7 @@ private:
nodep->iterateChildren(*this);
}
virtual void visit(AstNodeCase* nodep, AstNUser*) {
if (jumpingOver(nodep)) return;
UINFO(5," CASE "<<nodep<<endl);
checkNodeInfo(nodep);
if (m_checkOnly) {
@@ -436,12 +449,30 @@ private:
virtual void visit(AstCaseItem* nodep, AstNUser*) {
// Real handling is in AstNodeCase
if (jumpingOver(nodep)) return;
checkNodeInfo(nodep);
nodep->iterateChildren(*this);
}
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*) {
if (m_params) { // This message seems better than an obscure $stop
// The spec says $stop is just ignored, it seems evil to ignore assertions
@@ -479,6 +510,7 @@ private:
virtual void visit(AstWhile* nodep, AstNUser*) {
// Doing lots of Whiles is slow, so only for parameters
if (jumpingOver(nodep)) return;
UINFO(5," WHILE "<<nodep<<endl);
if (!m_params) { badNodeType(nodep); return; }
checkNodeInfo(nodep);
@@ -489,12 +521,19 @@ private:
while (1) {
UINFO(5," WHILE-ITER "<<nodep<<endl);
nodep->precondsp()->iterateAndNext(*this);
if (jumpingOver(nodep)) break;
nodep->condp()->iterateAndNext(*this);
if (jumpingOver(nodep)) break;
if (!optimizable()) break;
if (!fetchNumber(nodep->condp())->isNeqZero()) {
break;
}
nodep->bodysp()->iterateAndNext(*this);
if (jumpingOver(nodep)) break;
nodep->incsp()->iterateAndNext(*this);
if (jumpingOver(nodep)) break;
// Prep for next loop
if (loops++ > unrollCount()*16) {
clearOptimizable(nodep, "Loop unrolling took too long; probably this is an infinite loop, or set --unroll-count above "+cvtToStr(unrollCount()));
break;
@@ -504,6 +543,7 @@ private:
}
virtual void visit(AstFuncRef* nodep, AstNUser*) {
if (jumpingOver(nodep)) return;
UINFO(5," FUNCREF "<<nodep<<endl);
if (!m_params) { badNodeType(nodep); return; }
AstNodeFTask* funcp = nodep->taskp()->castNodeFTask(); if (!funcp) nodep->v3fatalSrc("Not linked");
@@ -540,6 +580,7 @@ private:
}
virtual void visit(AstVar* nodep, AstNUser*) {
if (jumpingOver(nodep)) return;
if (!m_params) { badNodeType(nodep); return; }
}
@@ -548,20 +589,30 @@ private:
// AstCoverInc, AstDisplay, AstArraySel, AstStop, AstFinish,
// AstRand, AstTime, AstUCFunc, AstCCall, AstCStmt, AstUCStmt
virtual void visit(AstNode* nodep, AstNUser*) {
if (jumpingOver(nodep)) return;
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:
// CONSTRUCTORS
SimulateVisitor() {
setMode(false,false,false);
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() {
m_whyNotOptimizable = "";
m_whyNotNodep = NULL;
@@ -570,6 +621,7 @@ public:
m_inDlyAssign = false;
m_instrCount = 0;
m_dataCount = 0;
m_jumpp = NULL;
AstNode::user1ClearTree(); // user1p() used on entire tree
AstNode::user2ClearTree(); // user2p() used on entire tree
@@ -580,15 +632,15 @@ public:
}
void mainTableCheck (AstNode* nodep) {
setMode(true/*scoped*/,true/*checking*/, false/*params*/);
nodep->accept(*this);
mainGuts(nodep);
}
void mainTableEmulate (AstNode* nodep) {
setMode(true/*scoped*/,false/*checking*/, false/*params*/);
nodep->accept(*this);
mainGuts(nodep);
}
void mainParamEmulate (AstNode* nodep) {
setMode(false/*scoped*/,false/*checking*/, true/*params*/);
nodep->accept(*this);
mainGuts(nodep);
}
virtual ~SimulateVisitor() {
for (deque<V3Number*>::iterator it = m_numAllps.begin(); it != m_numAllps.end(); ++it) {
+2 -1
View File
@@ -1039,7 +1039,7 @@ private:
// Create output variable
string namePrefix = "__Vfunc_"+nodep->taskp()->shortName()+"__"+cvtToStr(m_modNCalls++);
AstVarScope* outvscp = createVarScope (funcp->fvarp()->castVar(),
namePrefix+"__out");
namePrefix+"__Vfuncout");
// Create cloned statements
if (debug()>=9) { nodep->taskp()->dumpTree(cout,"-oldfunc:"); }
if (!nodep->taskp()) nodep->v3fatalSrc("Unlinked?");
@@ -1127,6 +1127,7 @@ private:
// Body insert just before themselves
m_insStmtp = NULL; // First thing should be new statement
nodep->bodysp()->iterateAndNext(*this);
nodep->incsp()->iterateAndNext(*this);
// Done the loop
m_insStmtp = NULL; // Next thing should be new statement
}
+15 -4
View File
@@ -185,6 +185,9 @@ private:
for (AstNode* bodp = bodysp; bodp; bodp=bodp->nextp()) {
bodySize++;
}
for (AstNode* bodp = incp; bodp; bodp=bodp->nextp()) {
bodySize++;
}
if (bodySize > v3Global.opt.unrollStmts())
return cantUnroll(nodep, "too many statements");
}
@@ -195,6 +198,7 @@ private:
m_ignoreIncp = incp;
precondsp->iterateAndNext(*this);
bodysp->iterateAndNext(*this);
incp->iterateAndNext(*this);
m_varModeCheck = false;
m_ignoreIncp = NULL;
if (m_varAssignHit) return cantUnroll(nodep, "genvar assigned *inside* loop");
@@ -231,6 +235,10 @@ private:
bodysp->unlinkFrBackWithNext();
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.
V3Number loopValue(nodep->fileline(), m_forVarp->width()); // May differ in size from numInitp
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()
if (newbodysp) nodep->replaceWith(newbodysp);
else nodep->unlinkFrBack();
@@ -303,9 +310,13 @@ private:
if (nodep->backp()->nextp() == nodep) initp=nodep->backp();
// Grab assignment
AstNode* incp = NULL; // Should be last statement
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
if (nodep->incsp()) V3Const::constifyEdit(nodep->incsp());
if (nodep->incsp()) incp = nodep->incsp();
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
if (forUnrollCheck(nodep, initp,
nodep->precondsp(), nodep->condp(),
+17
View File
@@ -84,6 +84,7 @@ private:
bool m_paramsOnly; // Computing parameter value; limit operation
AstRange* m_cellRangep; // Range for arrayed instantiations, NULL for normal instantiations
AstNodeCase* m_casep; // Current case statement CaseItem is under
AstFunc* m_funcp; // Current function
// CLASSES
#define ANYSIZE 0
@@ -711,6 +712,7 @@ private:
nodep->precondsp()->iterateAndNext(*this);
nodep->condp()->iterateAndNext(*this,WidthVP(1,1,BOTH).p());
nodep->bodysp()->iterateAndNext(*this);
nodep->incsp()->iterateAndNext(*this);
widthCheckReduce(nodep,"For Test Condition",nodep->condp(),1,1); // it's like an if() condition.
}
virtual void visit(AstNodeIf* nodep, AstNUser*) {
@@ -924,6 +926,20 @@ private:
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) {
visit(nodep->castNodeFTaskRef(), vup);
@@ -1028,6 +1044,7 @@ public:
m_taskDepth = 0;
m_cellRangep = NULL;
m_casep = NULL;
m_funcp = NULL;
}
AstNode* mainAcceptEdit(AstNode* nodep) {
return nodep->acceptSubtreeReturnEdits(*this, WidthVP(ANYSIZE,0,BOTH).p());
+5 -2
View File
@@ -52,8 +52,8 @@
#include "V3File.h"
#include "V3Cdc.h"
#include "V3Gate.h"
#include "V3Graph.h"
#include "V3GenClk.h"
#include "V3Graph.h"
#include "V3Inline.h"
#include "V3Inst.h"
#include "V3Life.h"
@@ -61,9 +61,10 @@
#include "V3Link.h"
#include "V3LinkCells.h"
#include "V3LinkDot.h"
#include "V3LinkJump.h"
#include "V3LinkLValue.h"
#include "V3LinkLevel.h"
#include "V3LinkParse.h"
#include "V3LinkLValue.h"
#include "V3LinkResolve.h"
#include "V3Localize.h"
#include "V3Name.h"
@@ -143,6 +144,8 @@ void process () {
V3LinkResolve::linkResolve(v3Global.rootp());
// Set Lvalue's in variable refs
V3LinkLValue::linkLValue(v3Global.rootp());
// Convert return/continue/disable to jumps
V3LinkJump::linkJump(v3Global.rootp());
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("link.tree"));
V3Error::abortIfErrors();
+1 -1
View File
@@ -25,7 +25,7 @@
//**********************************************************************
//**** Version and host name
#define DTVERSION "Verilator 3.800 2010/02/07"
#define DTVERSION "Verilator 3.801 2010/03/17"
//**********************************************************************
//**** Functions
+4
View File
@@ -15,6 +15,8 @@
# 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>) {
# Fix flex 2.5.4 namespace omission
$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;
# 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;
# Fix compiler warning filenames
$line =~ s!(#line \d+ ".*)_pretmp!$1!;
print "$line";
}
+8 -5
View File
@@ -382,10 +382,12 @@ escid \\[^ \t\f\r\n]+
"always_ff" { FL; return yALWAYS; }
"always_latch" { FL; return yALWAYS; }
"bit" { FL; return yBIT; }
"break" { FL; return yBREAK; }
"byte" { FL; return yBYTE; }
"chandle" { FL; return yCHANDLE; }
"clocking" { FL; return yCLOCKING; }
"context" { FL; return yCONTEXT; }
"continue" { FL; return yCONTINUE; }
"do" { FL; return yDO; }
"endclocking" { FL; return yENDCLOCKING; }
"endpackage" { FL; return yENDPACKAGE; }
@@ -403,6 +405,7 @@ escid \\[^ \t\f\r\n]+
"priority" { FL; return yPRIORITY; }
"program" { FL; return yPROGRAM; }
"pure" { FL; return yPURE; }
"return" { FL; return yRETURN; }
"shortint" { FL; return ySHORTINT; }
"static" { FL; return ySTATIC; }
"string" { FL; return ySTRING; }
@@ -419,10 +422,8 @@ escid \\[^ \t\f\r\n]+
"bind" { 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); }
"break" { 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); }
"continue" { 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); }
"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); }
"randsequence" { 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); }
"solve" { 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
"`celldefine" { PARSEP->inCellDefine(true); }
"`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_path" { } // 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; } }
"`remove_gatenames" { } // 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
"`timescale"{ws}+[^\n\r]* { } // Verilog spec - not supported
+16 -7
View File
@@ -264,6 +264,7 @@ class AstSenTree;
%token<fl> yAUTOMATIC "automatic"
%token<fl> yBEGIN "begin"
%token<fl> yBIT "bit"
%token<fl> yBREAK "break"
%token<fl> yBUF "buf"
%token<fl> yBUFIF0 "bufif0"
%token<fl> yBUFIF1 "bufif1"
@@ -275,6 +276,7 @@ class AstSenTree;
%token<fl> yCLOCKING "clocking"
%token<fl> yCMOS "cmos"
%token<fl> yCONTEXT "context"
%token<fl> yCONTINUE "continue"
%token<fl> yCOVER "cover"
%token<fl> yDEFAULT "default"
%token<fl> yDEFPARAM "defparam"
@@ -340,6 +342,7 @@ class AstSenTree;
%token<fl> yRCMOS "rcmos"
%token<fl> yREG "reg"
%token<fl> yREPEAT "repeat"
%token<fl> yRETURN "return"
%token<fl> yRNMOS "rnmos"
%token<fl> yRPMOS "rpmos"
%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_SSRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftRS($2,$1->cloneTree(true),$3)); }
// // 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_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")))); }
@@ -1831,7 +1835,7 @@ statement_item<nodep>: // IEEE: statement_item
| statementVerilatorPragmas { $$ = $1; }
//
// // IEEE: disable_statement
//UNSUP yDISABLE hierarchical_identifier/*task_or_block*/ ';' { UNSUP }
//UNSUP yDISABLE idAny/*hierarchical_identifier-task_or_block*/ ';' { UNSUP }
//UNSUP yDISABLE yFORK ';' { UNSUP }
// // IEEE: event_trigger
//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);}
// // for's first ';' is in for_initalization
| 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));}
//UNSUP yFOREACH '(' idClassForeach/*array_id[loop_variables]*/ ')' stmt { UNSUP }
//
// // IEEE: jump_statement
//UNSUP yRETURN ';' { UNSUP }
//UNSUP yRETURN expr ';' { UNSUP }
//UNSUP yBREAK ';' { UNSUP }
//UNSUP yCONTINUE ';' { UNSUP }
| yRETURN ';' { $$ = new AstReturn($1); }
| yRETURN expr ';' { $$ = new AstReturn($1,$2); }
| yBREAK ';' { $$ = new AstBreak($1); }
| yCONTINUE ';' { $$ = new AstContinue($1); }
//
//UNSUP par_block { $$ = $1; }
// // IEEE: procedural_timing_control_statement + procedural_timing_control
@@ -2738,9 +2742,14 @@ specifyJunk:
;
specparam_declaration<nodep>: // ==IEEE: specparam_declaration
ySPECPARAM junkToSemi ';' { $$ = NULL; }
ySPECPARAM junkToSemiList ';' { $$ = NULL; }
;
junkToSemiList:
junkToSemi { } /* ignored */
| junkToSemiList junkToSemi { } /* ignored */
;
junkToSemi:
BISONPRE_NOT(';',yENDSPECIFY,yENDMODULE) { }
| error {}
+1 -1
View File
@@ -183,7 +183,7 @@ sub parameter {
elsif ($param =~ /\.pl/) {
push @opt_tests, $param;
}
elsif ($param =~ /^--debugi/) {
elsif ($param =~ /^-?-debugi/) {
push @Opt_Driver_Verilator_Flags, $param;
$_Parameter_Next_Level = $param;
}
+18
View File
@@ -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;
+178
View File
@@ -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
+52
View File
@@ -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;
+18
View File
@@ -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;
+134
View File
@@ -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
+15
View File
@@ -10,6 +10,7 @@ module t;
localparam P5 = f_while(7);
localparam P16 = f_for(P4);
localparam P18 = f_case(P4);
localparam P6 = f_return(P4);
localparam P3 = 3;
initial begin
@@ -19,6 +20,7 @@ module t;
if (P3 !== 3) $stop;
if (P4 !== 4) $stop;
if (P5 !== 5) $stop;
if (P6 !== 6) $stop;
if (P8 !== 8) $stop;
if (P16 !== 16) $stop;
if (P18 !== 18) $stop;
@@ -69,4 +71,17 @@ module t;
default: f_case = 99;
endcase
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
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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;
+23
View File
@@ -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
+52 -1
View File
@@ -244,13 +244,64 @@ $display("bits %d %d", $bits(foo), `10);
1 /*verilator NOT IN DEFINE*/ (nodef)
2 /*verilator PART OF DEFINE*/ (hasdef)
3 /*verilator NOT PART OF DEFINE*/ (nodef)
4 /*verilator PART OF DEFINE*/ (nodef)
5 also in also3 (nodef)
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
+45
View File
@@ -191,12 +191,57 @@ Line_Preproc_Check `__LINE__
OF DEFINE */
`define CMT4 /* verilator PART \
OF DEFINE */
`define CMT5 // CMT NOT \
also in // BUT TEXT IS \
also3 // CMT NOT
1 `CMT1 (nodef)
2 `CMT2 (hasdef)
3 `CMT3 (nodef)
4 `CMT4 (nodef)
5 `CMT5 (nodef)
`define NL HAS a NEW \
LINE
`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
//======================================================================
+3
View File
@@ -13,7 +13,10 @@ module t (/*AUTOARG*/);
repeat (0) $stop;
repeat (-1) $stop;
negcnt = 'sb111;
// Not all commercial simulators agree on the below stopping or not
// verilator lint_off WIDTH
repeat (negcnt) $stop;
// verilator lint_on WIDTH
repeat (5) begin
repeat (2) begin
times = times + 1;
+11 -4
View File
@@ -24,17 +24,19 @@ include $(VERILATOR_ROOT)/include/verilated.mk
DEBUG_ON = --debug
######################################################################
ifneq ($(SYSTEMC),)
test_default: precopy prep 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
VERILATOR_FLAGS = --sc $(V_FLAGS) top.v
VERILATOR_FLAGS += --trace
precopy: obj_dir obj_dir/sc_main.cpp
obj_dir/sc_main.cpp: ../test_sp/sc_main.cpp
mkdir -p obj_dir
cp $^ $@
precopy:
prep:
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(VERILATOR_FLAGS)
@@ -55,6 +57,11 @@ run:
obj_dir:
mkdir $@
nosc:
@echo
@echo %Skip: SYSTEMC not in environment
@echo
######################################################################
maintainer-copy::
-2
View File
@@ -31,6 +31,4 @@ simx: sc_main.o $(VK_GLOBAL_OBJS) \
$(VM_PREFIX)__ALL.a $(SC_LIB)
$(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
+19 -3
View File
@@ -24,9 +24,15 @@ include $(VERILATOR_ROOT)/include/verilated.mk
DEBUG_ON = --debug --trace-dups
######################################################################
test_default: prep preproc compile run coverage
test_debug: prep_dbg preproc compile_dbg run coverage
test_nopublic: prep_dbg_np preproc compile_dbg run coverage
ifneq ($(SYSTEMPERL),)
test_default: precopy prep preproc compile 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
@@ -35,6 +41,11 @@ V_FLAGS = -f $(VERILATOR_ROOT)/test_v/input.vc
VERILATOR_FLAGS = --public --output-split-cfuncs 1000 --output-split 1000 \
--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:
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(VERILATOR_FLAGS)
prep_dbg:
@@ -62,6 +73,11 @@ coverage:
obj_dir:
mkdir $@
nosp:
@echo
@echo %Skip: SYSTERMPERL not in environment
@echo
######################################################################
maintainer-copy::