Compare commits

...
18 Commits
Author SHA1 Message Date
Wilson Snyder 710d7c0ee5 Fix link error when using --exe with --trace.
git-svn-id: file://localhost/svn/verilator/trunk/verilator@813 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-09 13:38:15 +00:00
Wilson Snyder 1c8fd37745 Fix some Coverity Prevent warnings
git-svn-id: file://localhost/svn/verilator/trunk/verilator@812 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-06 16:08:46 +00:00
Wilson Snyder 956c854662 Add t_case_write test
git-svn-id: file://localhost/svn/verilator/trunk/verilator@811 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-05 17:54:52 +00:00
Wilson Snyder 318a6e348c Support wide public task outputs.
git-svn-id: file://localhost/svn/verilator/trunk/verilator@810 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-05 14:53:17 +00:00
Wilson Snyder e471a34323 Add maybePointedTo to v3Broken for better and faster checks
git-svn-id: file://localhost/svn/verilator/trunk/verilator@809 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-05 00:45:39 +00:00
Wilson Snyder 95c5b85e88 Unlink .vpp files without --debug
git-svn-id: file://localhost/svn/verilator/trunk/verilator@808 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-04 18:46:42 +00:00
Wilson Snyder a46a556a64 Don't coredump without --debug
git-svn-id: file://localhost/svn/verilator/trunk/verilator@807 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-04 15:46:13 +00:00
Wilson Snyder fa3e03e071 version bump
git-svn-id: file://localhost/svn/verilator/trunk/verilator@804 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-04 12:57:29 +00:00
Wilson Snyder 74d7c55f1b Fix dotted variables in always sensitivity lists.
git-svn-id: file://localhost/svn/verilator/trunk/verilator@803 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-03 13:02:21 +00:00
Wilson Snyder 79e02858cb Add --debug-check flag
git-svn-id: file://localhost/svn/verilator/trunk/verilator@802 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-10-02 17:09:56 +00:00
Wilson Snyder 7738b202ac Remove --bin from perl shell, use argv[0] instead
git-svn-id: file://localhost/svn/verilator/trunk/verilator@801 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-30 00:27:05 +00:00
Wilson Snyder b4d4917c6c Fix coredump in XREFs under FUNCREF's
git-svn-id: file://localhost/svn/verilator/trunk/verilator@800 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-30 00:08:09 +00:00
Wilson Snyder 5c93520b27 Associative same variable elimination
git-svn-id: file://localhost/svn/verilator/trunk/verilator@799 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-28 14:37:28 +00:00
Wilson Snyder 94f0809d33 Add more boolean identity fixes
git-svn-id: file://localhost/svn/verilator/trunk/verilator@798 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-27 18:00:53 +00:00
Wilson Snyder ca4e3c1737 Eliminate assigned only variables
git-svn-id: file://localhost/svn/verilator/trunk/verilator@797 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-26 17:05:08 +00:00
Wilson Snyder ba7b4f261a Redo V3Life to also do constant propagation
git-svn-id: file://localhost/svn/verilator/trunk/verilator@796 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-26 15:05:35 +00:00
Wilson Snyder 4f42c25c7c Fix inout task arguments
git-svn-id: file://localhost/svn/verilator/trunk/verilator@795 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-25 20:40:52 +00:00
Wilson Snyder 621ef70c31 Allow overriding PERL, YACC, LEX versions.
git-svn-id: file://localhost/svn/verilator/trunk/verilator@794 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-25 15:58:17 +00:00
56 changed files with 4851 additions and 321 deletions
+28 -1
View File
@@ -3,7 +3,34 @@ 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.610 09/20/2006
* Verilator 3.62**
**** Fix link error when using --exe with --trace. [Eugene Weber]
**** Public functions now allow > 64 bit arguments.
**** Don't core dump on errors when not under --debug. [Allan Cochrane]
**** Remove .vpp intermediate files when not under --debug.
* Verilator 3.620 10/04/2006
*** Support simple inout task ports. [Eugene Weber]
*** Allow overriding Perl, Flex and Bison versions. [by Robert Farrell]
*** Optimize variables set to constants within basic blocks for ~3%.
**** Default make no longer makes the docs; if you edit the documentation.
sources, run "make info" to get them.
**** Optimize additional boolean identities (a|a = a, etc.)
**** Fix coredump when dotted cross-ref inside task call. [Eugene Weber]
**** Fix dotted variables in always sensitivity lists. [Allan Cochrane]
* Verilator 3.610 09/20/2006 Stable
*** Verilator now works under DJGPP (Pentium GCC). [John Stroebel]
+3 -3
View File
@@ -91,7 +91,7 @@ SUBDIRS = src test_verilated test_c test_sc test_sp test_regress test_vcs
INFOS = README verilator.txt verilator.html verilator.1 verilator.pdf
# Files that can be generated, but should be up to date for a distribution.
DISTDEP = $(INFOS) Makefile
DISTDEP = info Makefile
# Files to distribute.
DISTBIN = $(wildcard bin/verilator-*)
@@ -126,7 +126,7 @@ INST_PROJ_BIN_FILES = \
DISTFILES := $(DISTFILES_INC)
all: all_nomsg msg_test
all_nomsg: verilator_exe info
all_nomsg: verilator_exe
.PHONY:verilator_exe
verilator_exe verilator_bin verilator_bin_dbg:
@@ -218,7 +218,7 @@ installman:
$(INSTALL_PROGRAM) $$p $(mandir)/man1/$$p; \
done
install: all_nomsg info installdirs installbin installman install-msg
install: all_nomsg installdirs installbin installman install-msg
install-here: installman ftp
+84 -35
View File
@@ -113,7 +113,6 @@ if ($Opt_Sp eq 'sp' || $Opt_Trace) {
# Determine runtime flags
my $vcmd =(($opt_gdb?"$opt_gdb ":"")
.verilator_bin()
." --bin ".verilator_bin() # So we get binary name into .d file
." ".join(' ',@Opt_Verilator_Sw)
);
@@ -169,7 +168,7 @@ sub run {
warn "%Error: export VERILATOR_ROOT=$ENV{VERILATOR_ROOT}\n";
warn "%Error: $command\n";
}
die "%Error: Command Failed $command, $status, stopped";
die "%Error: Command Failed $command\n";
}
}
@@ -234,6 +233,13 @@ linking with make rules you write yourself.
Enable all assertions, includes enabling the --psl flag. (If psl is not
desired, but other assertions are, use --assert --nopsl.)
=item --bin I<filename>
Rarely needed. Override the default filename for Verilator itself. When a
dependancy (.d) file is created, this filename will become a source
dependency, such that a change in this binary will have make rebuild the
output files.
=item --cc
Specifies C++ without SystemC output mode; see also --sc and --sp.
@@ -283,8 +289,13 @@ the comment "DefaultClock":
=item --debug
Select the debug built image of Verilator (if available), and enable
debugging messages and intermediate form dump files.
Select the debug built image of Verilator (if available), and enable more
internal assertions, debugging messages, and intermediate form dump files.
=item --debug-check
Rarely needed. Enable internal debugging assertion checks, without
changing debug verbosity. Enabled automatically when --debug specified.
=item -E
@@ -303,10 +314,10 @@ Displays this message and program version and exits.
=item --inhibit-sim
Create a "inhibitSim(bool)" function to enable and disable evaluation.
This allows a upper level testbench to disable modules that are not
important in a given simulation, without needing to recompile or change the
SystemC modules instantiated.
Rarely needed. Create a "inhibitSim(bool)" function to enable and disable
evaluation. This allows a upper level testbench to disable modules that
are not important in a given simulation, without needing to recompile or
change the SystemC modules instantiated.
=item --inline-mult I<value>
@@ -339,8 +350,8 @@ the same as --prefix.
=item --no-skip-identical
Disables skipping execution of Verilator if all source files are identical,
and all output files exist with newer dates.
Rarely needed. Disables skipping execution of Verilator if all source
files are identical, and all output files exist with newer dates.
=item -O0
@@ -353,11 +364,11 @@ cost of compile time. This currently sets --inline-mult -1.
=item -OI<optimization-letter>
Enables or disables a specific optimizations, with the optimization
selected based on the letter passed. A lowercase letter disables an
optimization, an upper case letter enables it. This is intended for
debugging use only; see the source code for version-dependent mappings of
optimizations to -O letters.
Rarely needed. Enables or disables a specific optimizations, with the
optimization selected based on the letter passed. A lowercase letter
disables an optimization, an upper case letter enables it. This is
intended for debugging use only; see the source code for version-dependent
mappings of optimizations to -O letters.
=item --output-split I<bytes>
@@ -431,10 +442,10 @@ on during model execution.
=item --underline-zero
Signals starting with a underline should be initialized to zero, as was
done in Verilator 2. Default is for all signals including those with
underlines being randomized. This option may be depreciated in future
versions.
Rarely needed. Signals starting with a underline should be initialized to
zero, as was done in Verilator 2. Default is for all signals including
those with underlines being randomized. This option may be depreciated in
future versions.
=item -Werror-I<message>
@@ -555,7 +566,7 @@ And we get as output
Hello World
- our.v:2: Verilog $finish
Really, you're better off using a Makefile to do all this for you. Then,
Really, you're better off writing a Makefile to do all this for you. Then,
when your source changes it will automatically run all of these steps. See
the test_c directory in the distribution for an example.
@@ -709,7 +720,7 @@ In certain optimization modes, it also creates:
It also creates internal files that can be mostly ignored:
{each_verilog_module}.vpp // Post-processed verilog source code
{each_verilog_module}.vpp // Post-processed verilog (--debug)
{prefix}.flags_vbin // Verilator dependencies
{prefix}.flags_vpp // Pre-processor dependencies
{prefix}{misc}.d // Make dependencies (-MMD)
@@ -1077,9 +1088,9 @@ function. Any output arguments will become C++ reference arguments. Any
local registers/integers will become function automatic variables on the
stack.
Wide variables over 64 bits cannot be I/O to the module, to avoid exposing
complexities; generally the cleanest technique is to pass a word number to
the function, and do appropriate bit selection.
Wide variables over 64 bits cannot be function returns, to avoid exposing
complexities. However, wide variables can be input/outputs; they will be
passed as references to an array of 32 bit numbers.
This feature is still somewhat experimental. Generally, only the values of
stored state (flops) should be written, as the model will NOT notice
@@ -1486,18 +1497,32 @@ so your simulator shouldn't have to be -- and Verilator is closer to the
synthesis interpretation, so this is a good thing for getting working
silicon.
=item How do I generate waveforms (traces)?
=item How do I generate waveforms (traces) in C++?
See the next question for SystemC mode.
Add the --trace switch to Verilator, and make sure the SystemPerl package
is installed (SystemC itself isn't required for C++ only tracing.) In your
top level C code, call Verilated::traceEverOn(true).
is installed. SystemC itself does not need to be installed for C++ only
tracing. You do not even need to compile SystemPerl; you may simply untar
the SystemPerl kit and point the SYSTEMPERL environment variable to the
untarred directory.
Then, in SystemC mode, create a SpTraceFile object. For an example, see
the call to SpTraceFile in the test_sp/sc_main.cpp file of the
distribution.
In your top level C code, call Verilated::traceEverOn(true). Then create a
SpTraceVcdC object. For an example, see the call to SpTraceVcdC in the
test_c/sc_main.cpp file of the distribution.
Or, in C++ mode, create a SpTraceVcdCFile object, and see
test_c/sim_main.cpp.
You also need to compile SpTraceVcdC.cpp and add it to your link. This is
done for you if using the Verilator --exe flag.
=item How do I generate waveforms (traces) in SystemC?
Add the --trace switch to Verilator, and make sure the SystemPerl package
is installed.
In your top level C sc_main code, call Verilated::traceEverOn(true). Then
create a SpTraceFile object as you would create a normal SystemC trace
file. For an example, see the call to SpTraceFile in the
test_sp/sc_main.cpp file of the distribution.
=item Where is the translate_off command? (How do I ignore a construct?)
@@ -1516,6 +1541,11 @@ Call Verilated::assertOn(false) before you first call the model, then turn
it back on after reset. It defaults to true. When false, all assertions
controlled by --assert are disabled.
=item Why do I get "undefined reference to `sc_time_stamp()'"?
In C++ (non SystemC) code you need to define this function so that the
simulator knows the current time. See the "CONNECTING TO C++" examples.
=item Is the PLI supported?
No.
@@ -1575,6 +1605,25 @@ In this example, clk is a bool you can read or set as any other variable.
The value of normal signals may be set, though clocks shouldn't be changed
by your code or you'll get strange results.
=item Should a module be in Verilog or SystemC?
Sometimes there is a block that just interconnects cells, and have a choice
as to if you write it in Verilog or SystemC. Everything else being equal,
best performance is when Verilator sees all of the design. So, look at the
hierarchy of your design, labeling cells as to if they are SystemC or
Verilog. Then:
A module with only SystemC cells below must be SystemC.
A module with a mix of Verilog and SystemC cells below must be SystemC. (As
Verilator cannot connect to lower-level SystemC cells.)
A module with only Verilog cells below can be either, but for best
performance should be Verilog. (The exception is if you have a design that
is instantiated many times; in this case Verilating one of the lower
modules and instantiating that Verilated cells multiple times into a
SystemC module *may* be faster.)
=back
=head1 BUGS
@@ -1599,7 +1648,7 @@ outputs. Now, the following should fail:
cd test_regress
t/t_BUG.pl
Finally, Mail the bug report to C<[email protected]>
Finally, Mail the bug report to C<[email protected]>.
=head1 HISTORY
@@ -1626,8 +1675,8 @@ scratch in C++. This added many optimizations, yielding about a 2-5x
performance gain.
Currently, various language features and performance enhancements are added
as the need arises. Verilator is now about 2x faster then in 2002, and
as fast as most popular commercial simulators.
as the need arises. Verilator is now about 2x faster then in 2002, and is
faster then many popular commercial simulators.
=head1 CONTRIBUTORS
+1 -1
View File
@@ -192,5 +192,5 @@ C<verilator>
######################################################################
### Local Variables:
### compile-command: "$V4/bin/verilator_difftree ~/SandBox/workwsnyder/verilator/test_c/obj_dir/V*_03_*.tree $V4/test_c/obj_dir/V*_03_*.tree"
### compile-command: "$V4/bin/verilator_difftree $V4/test_c/obj_dir/V*_03_*.tree $V4N/test_c/obj_dir/V*_03_*.tree"
### End:
+2
View File
@@ -16,6 +16,8 @@ AC_PROG_CC
AC_PROG_CXX
AC_PROG_INSTALL
AC_PATH_PROG(PERL,perl)
AC_PATH_PROG(YACC,bison)
AC_PATH_PROG(LEX,flex)
dnl Checks for libraries.
+2 -1
View File
@@ -88,7 +88,8 @@ typedef unsigned int vluint32_t; ///< 32-bit unsigned type
typedef __int64 vlsint64_t; ///< 64-bit signed type
typedef unsigned __int64 vluint64_t; ///< 64-bit unsigned type
#else // Linux or compliant Unix flavors, -m64
# include <stdint.h>
# include <stdint.h> // Linux and most flavors
# include <inttypes.h> // Solaris
typedef uint8_t vluint8_t; ///< 32-bit unsigned type
typedef uint16_t vluint16_t; ///< 32-bit unsigned type
typedef int vlsint32_t; ///< 32-bit signed type
+3
View File
@@ -85,3 +85,6 @@ clean mostlyclean distclean maintainer-clean::
-rm -f *__gen*
-rm -f *.yy.* y.output y.tab.[cho] *_test
-rm -f .objcache*
distclean maintainer-clean::
-rm -f Makefile Makefile_obj
+3 -3
View File
@@ -48,10 +48,10 @@ COPT = -ggdb -DVL_DEBUG
endif
#################
LEX = flex
LEX = @LEX@
LFLAGS = -d
YACC = bison -y
YFLAGS = -d -v
YACC = @YACC@
YFLAGS = -y -d -v
#LIBS += -ldl
#CCMALLOC = /usr/local/lib/ccmalloc-gcc.o -lccmalloc -ldl
+2
View File
@@ -298,8 +298,10 @@ private:
// OPTIMIZE: We could substitute a constant for things in the sense list, for example
// always (posedge RESET) { if (RESET).... } we know RESET is true.
// Summarize a long list of combo inputs as just "combo"
#ifndef __COVERITY__ // Else dead code on next line.
if (combo) nodep->sensesp()->addSensesp
(new AstSenItem(nodep->fileline(),AstSenItem::Combo()));
#endif
wantactivep = m_namer.getActive(nodep->fileline(), nodep->sensesp());
}
+4 -2
View File
@@ -784,14 +784,16 @@ void AstNode::dumpTreeFile(const string& filename, bool append) {
dumpTree(*logsp);
}
}
}
if (v3Global.opt.debugCheck() || v3Global.opt.dumpTree()) {
// Error check
checkTree();
// Broken isn't part of check tree because it can munge iterp's
// set by other steps if it is called in the middle of other operations
if (AstNetlist* netp=this->castNetlist()) V3Broken::brokenAll(netp);
// Next dump can indicate start from here
editCountSetLast();
}
// Next dump can indicate start from here
editCountSetLast();
}
void AstNode::v3errorEnd(ostringstream& str) {
+2
View File
@@ -585,6 +585,7 @@ public:
virtual int instrCount() const { return 0; }
virtual V3Hash sameHash() const { return V3Hash(V3Hash::Illegal()); } // Not a node that supports it
virtual bool same(AstNode* otherp) const { return true; }
virtual bool maybePointedTo() const { return false; } // Another AstNode* may have a pointer into this node, other then normal front/back/etc.
virtual bool broken() const { return false; }
virtual bool emitWordForm() { return false; }
@@ -922,6 +923,7 @@ public:
virtual ~AstNodeFTask() {}
virtual void dump(ostream& str=cout);
virtual string name() const { return m_name; } // * = Var name
virtual bool maybePointedTo() const { return true; }
// {AstFunc only} op1 = Range output variable
// op3 = Statements/Ports/Vars
void name(const string& name) { m_name = name; }
+22 -5
View File
@@ -85,7 +85,7 @@ int AstVar::widthTotalBytes() const {
}
string AstVar::verilogKwd() const {
if (isTristate()) {
if (isInout()) {
return "inout";
} else if (isInput()) {
return "input";
@@ -93,6 +93,8 @@ string AstVar::verilogKwd() const {
return "output";
} else if (isInteger()) {
return "integer";
} else if (isTristate()) {
return "tri";
} else if (varType()==AstVarType::WIRE) {
return "wire";
} else {
@@ -101,6 +103,18 @@ string AstVar::verilogKwd() const {
}
string AstVar::cType() const {
if (widthMin() == 1) {
return "bool";
} else if (widthMin() <= VL_WORDSIZE) {
return "uint32_t";
} else if (isScWide()) {
return "uint32_t"; // []'s added later
} else {
return "uint64_t";
}
}
string AstVar::scType() const {
if (widthMin() == 1) {
return "bool";
} else if (widthMin() <= VL_WORDSIZE) {
@@ -130,7 +144,7 @@ uint32_t AstVar::arrayElements() const {
bool AstScope::broken() const {
return ((m_aboveScopep && !m_aboveScopep->brokeExists())
|| (m_aboveCellp && !m_aboveCellp->brokeExists())
|| !m_modp || !((AstNode*)m_modp)->brokeExists());
|| !m_modp || !m_modp->brokeExists());
}
void AstScope::cloneRelink() {
@@ -325,9 +339,12 @@ void AstVarRef::dump(ostream& str) {
void AstVar::dump(ostream& str) {
this->AstNode::dump(str);
if (isSc()) str<<" [SC]";
if (isInput()) str<<" [I]";
if (isPrimaryIO()) str<<(isInput()?" [PI]":" [PO]");
if (isOutput()) str<<" [O]";
if (isPrimaryIO()) str<<(isInout()?" [PIO]":(isInput()?" [PI]":" [PO]"));
else {
if (isInout()) str<<" [IO]";
else if (isInput()) str<<" [I]";
else if (isOutput()) str<<" [O]";
}
if (isUsedClock()) str<<" [C]";
if (isSigPublic()) str<<" [P]";
if (attrClockEn()) str<<" [aCLKEN]";
+26 -6
View File
@@ -286,8 +286,10 @@ public:
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
virtual void dump(ostream& str);
virtual string name() const { return m_name; } // * = Var name
virtual bool maybePointedTo() const { return true; }
AstVarType varType() const { return m_varType; } // * = Type of variable
string cType() const; // Return C type: bool, uint32_t, uint64_t, etc.
string cType() const; // Return C type for declaration: bool, uint32_t, uint64_t, etc.
string scType() const; // Return SysC type: bool, uint32_t, uint64_t, sc_bv
void combineType(AstVarType type);
AstRange* rangep() const { return op1p()->castRange(); } // op1 = Range of variable
AstRange* arraysp() const { return op2p()->castRange(); } // op2 = Array(s) of variable
@@ -314,10 +316,13 @@ public:
void name(const string& name) { m_name = name; }
bool isInput() const { return m_input; }
bool isOutput() const { return m_output; }
bool isTristate() const { return (m_tristate); }
bool isInOnly() const { return m_input && !m_output; }
bool isOutOnly() const { return m_output && !m_input; }
bool isInout() const { return m_input && m_output; }
bool isTristate() const { return m_tristate; }
bool isPrimaryIO() const { return m_primaryIO; }
bool isPrimaryIn() const { return isPrimaryIO() && isInput(); }
bool isIO() const { return (m_input||m_output||m_tristate); }
bool isIO() const { return (m_input||m_output); }
bool isSignal() const { return (varType()==AstVarType::WIRE || varType()==AstVarType::IMPLICIT
|| varType()==AstVarType::REG || varType()==AstVarType::INTEGER); }
bool isTemp() const { return (varType()==AstVarType::BLOCKTEMP || varType()==AstVarType::MODULETEMP
@@ -419,6 +424,7 @@ public:
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
virtual void cloneRelink();
virtual bool broken() const;
virtual bool maybePointedTo() const { return true; }
virtual string name() const { return m_name; } // * = Scope name
void name(const string& name) { m_name = name; }
string nameDotless() const;
@@ -480,6 +486,7 @@ public:
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
virtual bool broken() const { return ( (m_varp && !m_varp->brokeExists())
|| (m_scopep && !m_scopep->brokeExists())); }
virtual bool maybePointedTo() const { return true; }
virtual string name() const {return scopep()->name()+"->"+varp()->name();} // * = Var name
virtual void dump(ostream& str);
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
@@ -604,6 +611,7 @@ public:
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
virtual void dump(ostream& str);
virtual bool broken() const { return (m_clkReqVarp && !m_clkReqVarp->brokeExists()); }
virtual bool maybePointedTo() const { return true; }
virtual string name() const { return m_name; }
AstNode* stmtsp() const { return op2p()->castNode(); } // op2 = List of statements
AstActive* activesp() const { return op3p()->castActive(); } // op3 = List of i/sblocks
@@ -648,6 +656,7 @@ public:
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
virtual void dump(ostream& str);
virtual bool broken() const { return (m_modp && !m_modp->brokeExists()); }
virtual bool maybePointedTo() const { return true; }
// ACCESSORS
virtual string name() const { return m_name; } // * = Cell name
void name(const string& name) { m_name = name; }
@@ -806,7 +815,7 @@ public:
class Initial {}; // for creator type-overload selection
class Settle {}; // for creator type-overload selection
class Never {}; // for creator type-overload selection
AstSenItem(FileLine* fl, AstEdgeType edgeType, AstVarRef* varrefp)
AstSenItem(FileLine* fl, AstEdgeType edgeType, AstNodeVarRef* varrefp)
: AstNode(fl) {
m_edgeType = edgeType;
setOp1p(varrefp);
@@ -839,7 +848,7 @@ public:
AstEdgeType edgeType() const { return m_edgeType; } // * = Posedge/negedge
void edgeType(AstEdgeType type) { m_edgeType=type; editCountInc(); }// * = Posedge/negedge
AstNode* sensp() const { return op1p(); } // op1 = Signal sensitized
AstVarRef* varrefp() const { return op1p()->castVarRef(); } // op1 = Signal sensitized
AstNodeVarRef* varrefp() const { return op1p()->castNodeVarRef(); } // op1 = Signal sensitized
//
bool isClocked() const { return edgeType().clockedStmt(); }
bool isCombo() const { return edgeType()==AstEdgeType::COMBO; }
@@ -865,6 +874,7 @@ public:
virtual AstNode* clone() { return new AstSenTree(*this); }
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
virtual void dump(ostream& str);
virtual bool maybePointedTo() const { return true; }
bool isMulti() const { return m_multi; }
AstSenItem* sensesp() const { return op1p()->castSenItem(); } // op1 = Sensitivity list
void addSensesp(AstSenItem* nodep) { addOp1p(nodep); }
@@ -1050,6 +1060,7 @@ public:
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
virtual void dump(ostream& str);
virtual int instrCount() const { return 1+2*instrCountLd(); }
virtual bool maybePointedTo() const { return true; }
int column() const { return m_column; }
const string& comment() const { return m_text; } // text to insert in code
const string& typeText() const { return m_typeText; }
@@ -1503,6 +1514,7 @@ public:
virtual AstNode* clone() { return new AstTraceDecl(*this); }
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
virtual string name() const { return m_showname; }
virtual bool maybePointedTo() const { return true; }
string showname() const { return m_showname; } // * = Var name
virtual bool same(AstNode* samep) const { return false; }
// Details on what we're tracing
@@ -1594,7 +1606,8 @@ public:
bool hasClocked() const { return m_sensesp->hasClocked(); }
};
class AstAttrOf : public AstNode {
struct AstAttrOf : public AstNode {
private:
// Return a value of a attribute, for example a LSB or array LSB of a signal
AstAttrType m_attrType; // What sort of extraction
int m_dimension; // Dimension number (0 is leftmost), for ARRAY_LSB extractions
@@ -1736,6 +1749,7 @@ struct AstRedXor : public AstNodeUniop {
virtual int instrCount() const { return 1+V3Number::log2b(width()); }
};
struct AstRedXnor : public AstNodeUniop {
// AstRedXnors are replaced with AstRedXors in V3Const.
AstRedXnor(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
width(1,1); }
virtual ~AstRedXnor() {}
@@ -2773,6 +2787,7 @@ private:
bool m_funcPublic:1; // From user public task/function
bool m_isStatic:1; // Function is declared static (no this)
bool m_symProlog:1; // Setup symbol table for later instructions
bool m_entryPoint:1; // User may call into this top level function
public:
AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType="")
: AstNode(fl) {
@@ -2788,12 +2803,15 @@ public:
m_funcPublic = false;
m_isStatic = true; // Note defaults to static, later we see where thisp is needed
m_symProlog = false;
m_entryPoint = false;
}
virtual ~AstCFunc() {}
virtual AstType type() const { return AstType::CFUNC;}
virtual AstNode* clone() { return new AstCFunc(*this); }
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
virtual string name() const { return m_name; }
virtual bool broken() const { return ( (m_scopep && !m_scopep->brokeExists())); }
virtual bool maybePointedTo() const { return true; }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(AstNode* samep) const { return ((funcType()==samep->castCFunc()->funcType())
&& (rtnTypeVoid()==samep->castCFunc()->rtnTypeVoid())
@@ -2823,6 +2841,8 @@ public:
void isStatic(bool flag) { m_isStatic = flag; }
bool symProlog() const { return m_symProlog; }
void symProlog(bool flag) { m_symProlog = flag; }
bool entryPoint() const { return m_entryPoint; }
void entryPoint(bool flag) { m_entryPoint = flag; }
//
// If adding node accessors, see below
AstNode* argsp() const { return op1p()->castNode(); }
+6 -4
View File
@@ -81,13 +81,15 @@ private:
// // so userp and friends may not be used
// VISITORS
virtual void visit(AstNode* nodep, AstNUser*) {
BrokenTable::add(nodep);
if (nodep->maybePointedTo()) {
BrokenTable::add(nodep);
}
nodep->iterateChildren(*this);
}
public:
// CONSTUCTORS
BrokenMarkVisitor(AstNode* nodep) {
nodep->iterateAndNext(*this, NULL);
BrokenMarkVisitor(AstNetlist* nodep) {
nodep->accept(*this);
}
virtual ~BrokenMarkVisitor() {}
};
@@ -99,7 +101,7 @@ class BrokenCheckVisitor : public AstNVisitor {
private:
virtual void visit(AstNode* nodep, AstNUser*) {
if (nodep->broken()) {
nodep->v3fatalSrc("Broken link in node\n");
nodep->v3fatalSrc("Broken link in node (or something without maybePointedTo)\n");
}
if (v3Global.assertWidthsSame()) {
if (nodep->width() != nodep->widthMin()) {
+16 -15
View File
@@ -29,12 +29,12 @@
// (other items))
// body
// Or, converts to a if/else tree.
// Constants:
// RHS, Replace 5'bx_1_x with a module global we init to a random value
// CONST(5'bx_1_x) -> VARREF(_{numberedtemp})
// -> VAR(_{numberedtemp})
// -> INITIAL(VARREF(_{numberedtemp}), OR(5'bx_1_x,AND(random,5'b0_1_x))
// OPTIMIZE: Must not collapse this initial back into the equation.
// FUTURES:
// Large 16+ bit tables with constants and no masking (address muxes)
// Enter all into multimap, sort by value and use a tree of < and == compares.
// "Diagonal" find of {rightmost,leftmost} bit {set,clear}
// Ignoring mask, check each value is unique (using multimap as above?)
// Each branch is then mask-and-compare operation (IE <000000001_000000000 at midpoint.)
//
//*************************************************************************
@@ -49,7 +49,8 @@
#include "V3Ast.h"
#include "V3Stats.h"
#define CASE_OVERLAP_WIDTH 12 // Maximum width we can check for overlaps in
#define CASE_OVERLAP_WIDTH 12 // Maximum width we can check for overlaps in
#define CASE_BARF 999999 // Magic width when non-constant
//######################################################################
@@ -126,22 +127,22 @@ private:
//int debug() { return 9; }
// METHODS
bool checkCaseTree(AstCase* nodep) {
bool isCaseTreeFast(AstCase* nodep) {
int width = 0;
m_caseItems = 0;
m_caseNoOverlapsAllCovered = true;
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
if (icondp->width() > width) width = icondp->width();
if (!icondp->castConst()) width = 999; // Can't parse; not a constant
if (!icondp->castConst()) width = CASE_BARF; // Can't parse; not a constant
m_caseItems++;
}
}
m_caseWidth = width;
if (width==0 || width > CASE_OVERLAP_WIDTH) {
m_caseNoOverlapsAllCovered = false;
return false; // Too wide for analysis
}
m_caseWidth = width;
UINFO(8,"Simple case statement: "<<nodep<<endl);
// Zero list of items for each value
for (uint32_t i=0; i<(1UL<<m_caseWidth); i++) m_valueItem[i] = NULL;
@@ -172,7 +173,7 @@ private:
}
}
// Defaults were moved to last in the caseitem list by V3Link
if (!itemp->condsp()) { // Case statement's default... Fill the table
if (itemp->isDefault()) { // Case statement's default... Fill the table
for (uint32_t i=0; i<(1UL<<m_caseWidth); i++) {
if (!m_valueItem[i]) m_valueItem[i] = itemp;
}
@@ -207,7 +208,7 @@ private:
AstNode* tree1p = replaceCaseFastRecurse(cexprp, msb-1, upperValue | (1UL<<msb));
if (tree0p == tree1p) {
// Same logic on both sides, so we can just return one of em
// Same logic on both sides, so we can just return one of 'em
return tree0p;
}
// We could have a "checkerboard" with A B A B, we can use the same IF on both edges
@@ -357,7 +358,7 @@ private:
V3Case::caseLint(nodep);
nodep->iterateChildren(*this);
if (debug()>=9) nodep->dumpTree(cout," case_old: ");
if (checkCaseTree(nodep) && v3Global.opt.oCase()) {
if (isCaseTreeFast(nodep) && v3Global.opt.oCase()) {
// It's a simple priority encoder or complete statement
// we can make a tree of statements to avoid extra comparisons
m_statCaseFast++;
@@ -375,13 +376,13 @@ private:
public:
// CONSTUCTORS
CaseVisitor(AstNode* nodep) {
CaseVisitor(AstNetlist* nodep) {
m_caseNoOverlapsAllCovered = false;
nodep->accept(*this);
}
virtual ~CaseVisitor() {
V3Stats::addStat("Optimizations, Cases parallelized", m_statCaseFast);
V3Stats::addStat("Optimizations, Cases priority-encoded", m_statCaseSlow);
V3Stats::addStat("Optimizations, Cases complex", m_statCaseSlow);
}
};
+4
View File
@@ -192,6 +192,7 @@ private:
funcp->dontCombine(true);
funcp->symProlog(true);
funcp->isStatic(true);
funcp->entryPoint(true);
m_scopep->addActivep(funcp);
m_evalFuncp = funcp;
}
@@ -202,6 +203,7 @@ private:
funcp->slow(true);
funcp->symProlog(true);
funcp->isStatic(true);
funcp->entryPoint(true);
m_scopep->addActivep(funcp);
m_initFuncp = funcp;
}
@@ -211,6 +213,7 @@ private:
funcp->dontCombine(true);
funcp->slow(true);
funcp->isStatic(false);
funcp->entryPoint(true);
funcp->addInitsp(
new AstCStmt(nodep->fileline(),
" "+EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
@@ -225,6 +228,7 @@ private:
funcp->slow(true);
funcp->isStatic(true);
funcp->symProlog(true);
funcp->entryPoint(true);
m_scopep->addActivep(funcp);
m_settleFuncp = funcp;
}
+60 -16
View File
@@ -70,6 +70,16 @@ private:
if (!rnodep->lhsp()->castConst()) return false;
return true;
}
bool operandAsvSame (AstNode* nodep) {
// BIASV(SAMEa, BIASV(SAMEb,...)) -> BIASV( BIASV(SAMEa,SAMEb), ...)
AstNodeBiComAsv* bnodep = nodep->castNodeBiComAsv();
if (!bnodep) return false;
AstNodeBiComAsv* rnodep = bnodep->rhsp()->castNodeBiComAsv();
if (!rnodep) return false;
if (rnodep->type() != bnodep->type()) return false;
if (rnodep->width() != bnodep->width()) return false;
return operandsSame(bnodep->lhsp(), rnodep->lhsp());
}
bool operandHugeShiftL(AstNodeBiop* nodep) {
return (nodep->rhsp()->castConst()
&& nodep->rhsp()->castConst()->asInt() >= (uint32_t)(nodep->width()));
@@ -170,15 +180,10 @@ private:
static bool operandsSame(AstNode* node1p, AstNode* node2p) {
// For now we just detect constants & simple vars, though it could be more generic
if (node1p->castConst() && node2p->castConst()) {
// Match ignoring any X values
V3Number num (node1p->fileline(), 1);
num.opCaseEq(node1p->castConst()->num(), node2p->castConst()->num());
return num.isNeqZero();
return node1p->sameTree(node2p);
}
else if (node1p->castVarRef() && node2p->castVarRef()
&& node1p->sameTree(node2p)) {
// Same variable
return true;
else if (node1p->castVarRef() && node2p->castVarRef()) {
return node1p->sameTree(node2p);
} else {
return false;
}
@@ -239,6 +244,12 @@ private:
void replaceZero(AstNode* nodep) {
replaceNum(nodep, 0); nodep=NULL;
}
void replaceAllOnes (AstNode* nodep) {
V3Number num (nodep->fileline(), nodep->width(), 0);
V3Number ones (nodep->fileline(), nodep->width());
ones.opNot(num);
replaceNum(nodep, ones); nodep=NULL;
}
void replaceConst(AstNodeUniop* nodep) {
V3Number num (nodep->fileline(), nodep->width());
nodep->numberOperate(num, nodep->lhsp()->castConst()->num());
@@ -283,8 +294,9 @@ private:
// Keep RHS, remove LHS
replaceWChild(nodep, nodep->rhsp());
}
void replaceAsvConst (AstNodeBiop* nodep) {
void replaceAsv (AstNodeBiop* nodep) {
// BIASV(CONSTa, BIASV(CONSTb, c)) -> BIASV( BIASV_CONSTED(a,b), c)
// BIASV(SAMEa, BIASV(SAMEb, c)) -> BIASV( BIASV(SAMEa,SAMEb), c)
//nodep->dumpTree(cout, " repAsvConst_old: ");
AstNode* ap = nodep->lhsp();
AstNodeBiop* rp = nodep->rhsp()->castNodeBiop();
@@ -298,7 +310,7 @@ private:
nodep->rhsp(cp);
rp->lhsp(ap);
rp->rhsp(bp);
replaceConst(rp);
if (rp->lhsp()->castConst() && rp->rhsp()->castConst()) replaceConst(rp);
//nodep->dumpTree(cout, " repAsvConst_new: ");
}
void replaceExtend (AstNode* nodep, AstNode* arg0p) {
@@ -803,7 +815,7 @@ private:
}
UINFO(8,"senItem(NOT...) "<<nodep<<" "<<invert<<endl);
if (invert) nodep->edgeType( nodep->edgeType().invert() );
AstVarRef* senvarp = lastSensp->unlinkFrBack()->castVarRef();
AstNodeVarRef* senvarp = lastSensp->unlinkFrBack()->castNodeVarRef();
if (!senvarp) sensp->v3fatalSrc("Non-varref sensitivity variable");
sensp->replaceWith(senvarp);
sensp->deleteTree(); sensp=NULL;
@@ -945,6 +957,7 @@ private:
// }" # bracket not paren
// ,"function to call"
// or ,"AstREPLACEMENT_TYPE{ $accessor }"
// or ,"! # Print line number when matches, so can see operations
// Lint Checks
// v--- *1* These ops are always first, as we warn before replacing
@@ -969,6 +982,7 @@ private:
TREEOP("AstShiftR{$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
TREEOP("AstShiftRS{$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
TREEOP("AstXor {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
TREEOP("AstXnor {$lhsp.isZero, $rhsp}", "AstNot{$rhsp}");
TREEOP("AstSub {$lhsp.isZero, $rhsp}", "AstUnaryMin{$rhsp}");
TREEOP("AstAdd {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
TREEOP("AstAnd {$lhsp, $rhsp.isZero}", "replaceZero(nodep)");
@@ -982,6 +996,7 @@ private:
TREEOP("AstShiftRS{$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
TREEOP("AstSub {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
TREEOP("AstXor {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
TREEOP("AstXnor {$lhsp, $rhsp.isZero}", "AstNot{$lhsp}");
// Non-zero on one side or the other
TREEOP("AstAnd {$lhsp.isAllOnes, $rhsp}", "replaceWRhs(nodep)");
TREEOP("AstLogAnd{$lhsp.isNeqZero, $rhsp}", "replaceWRhs(nodep)");
@@ -992,6 +1007,7 @@ private:
TREEOP("AstOr {$lhsp, $rhsp.isAllOnes}", "replaceWRhs(nodep)"); //->allOnes
TREEOP("AstLogOr {$lhsp, $rhsp.isNeqZero}", "replaceNum(nodep,1)");
TREEOP("AstXor {$lhsp.isAllOnes, $rhsp}", "AstNot{$rhsp}");
TREEOP("AstXnor {$lhsp.isAllOnes, $rhsp}", "replaceWRhs(nodep)");
TREEOP("AstMul {$lhsp.isOne, $rhsp}", "replaceWRhs(nodep)");
TREEOP("AstMulS {$lhsp.isOne, $rhsp}", "replaceWRhs(nodep)");
TREEOP("AstDiv {$lhsp, $rhsp.isOne}", "replaceWLhs(nodep)");
@@ -1012,8 +1028,9 @@ private:
TREEOP("AstNodeCond{$condp.width1, $expr1p.width1, $expr1p.isZero, $expr2p}", "AstAnd{AstNot{$condp}, $expr2p}"); // a?0:b == ~a&b
TREEOP("AstNodeCond{!$condp.width1, operandBoolShift(nodep->condp())}", "replaceBoolShift(nodep->condp())");
// Prefer constants on left, since that often needs a shift, it lets constant red remove the shift
TREEOP("AstNodeBiCom{$lhsp, $rhsp.castConst}", "swapSides(nodep)");
TREEOP("AstNodeBiComAsv{operandAsvConst(nodep)}", "replaceAsvConst(nodep)");
TREEOP("AstNodeBiCom{!$lhsp.castConst, $rhsp.castConst}", "swapSides(nodep)");
TREEOP("AstNodeBiComAsv{operandAsvConst(nodep)}", "replaceAsv(nodep)");
TREEOP("AstNodeBiComAsv{operandAsvSame(nodep)}", "replaceAsv(nodep)");
// v--- *1* as These ops are always first, as we warn before replacing
TREEOP1("AstLt {$lhsp, $rhsp.isZero}", "replaceNumSigned(nodep,0)");
TREEOP1("AstGte {$lhsp, $rhsp.isZero}", "replaceNumSigned(nodep,1)");
@@ -1058,6 +1075,31 @@ private:
TREEOP ("AstShiftL{operandShiftShift(nodep)}", "replaceShiftShift(nodep)");
TREEOP ("AstShiftR{operandShiftShift(nodep)}", "replaceShiftShift(nodep)");
TREEOP ("AstWordSel{operandWordOOB(nodep)}", "replaceZero(nodep)");
// Identical operands on both sides
// AstLogAnd/AstLogOr already converted to AstAnd/AstOr for these rules
// AstAdd->ShiftL(#,1) but uncommon
TREEOP("AstAnd {operandsSame($lhsp,,$rhsp)}", "replaceWLhs(nodep)");
TREEOP("AstChangeXor{operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP("AstDiv {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP("AstDivS {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP("AstOr {operandsSame($lhsp,,$rhsp)}", "replaceWLhs(nodep)");
TREEOP("AstSub {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP("AstXnor {operandsSame($lhsp,,$rhsp)}", "replaceAllOnes(nodep)");
TREEOP("AstXor {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP("AstEq {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); // We let X==X -> 1, although in a true 4-state sim it's X.
TREEOP("AstEqCase {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP("AstGt {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP("AstGtS {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP("AstGte {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP("AstGteS {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP("AstLt {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP("AstLtS {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP("AstLte {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP("AstLteS {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP("AstNeq {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP("AstNeqCase{operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP("AstLogAnd {operandsSame($lhsp,,$rhsp), $lhsp.width1}", "replaceWLhs(nodep)");
TREEOP("AstLogOr {operandsSame($lhsp,,$rhsp), $lhsp.width1}", "replaceWLhs(nodep)");
///=== Verilog operators
// Comparison against 1'b0/1'b1; must be careful about widths.
// These use Not, so must be Verilog only
@@ -1075,7 +1117,6 @@ private:
TREEOPV("AstLte {$lhsp->width()==$rhsp->width(), $rhsp.isAllOnes}", "replaceNum(nodep,1)");
// Simplify reduction operators
// This also gets &{...,0,....} => const 0 (Common for unused_ok signals)
TREEOPV("AstRedXnor{$lhsp}", "AstNot{AstRedXor{$lhsp}}"); // Just eliminate XNOR's
TREEOPV("AstRedAnd{$lhsp, $lhsp.width1}", "replaceWLhs(nodep)");
TREEOPV("AstRedOr {$lhsp, $lhsp.width1}", "replaceWLhs(nodep)");
TREEOPV("AstRedXor{$lhsp, $lhsp.width1}", "replaceWLhs(nodep)");
@@ -1108,6 +1149,7 @@ private:
TREEOPV("AstSel{$fromp.castConcat, $lsbp.castConst, $widthp.castConst, }", "replaceSelConcat(nodep)");
TREEOPV("AstSel{$fromp.castReplicate, $lsbp.castConst, $widthp.isOne, }", "replaceSelReplicate(nodep)");
// Conversions
TREEOPV("AstRedXnor{$lhsp}", "AstNot{AstRedXor{$lhsp}}"); // Just eliminate XNOR's
TREEOPV("AstLogIf {$lhsp, $rhsp}", "AstLogOr{AstLogNot{$lhsp},$rhsp}");
TREEOPV("AstLogIff{$lhsp, $rhsp}", "AstLogNot{AstXor{$lhsp,$rhsp}}");
@@ -1171,12 +1213,14 @@ void V3Const::constifyAll(AstNetlist* nodep) {
visitor.main(nodep);
}
void V3Const::constifyAllLint(AstNode* nodep) {
void V3Const::constifyAllLint(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
ConstVisitor visitor (false,false,true,false);
visitor.main(nodep);
}
void V3Const::constifyCpp(AstNode* nodep) {
void V3Const::constifyCpp(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
ConstVisitor visitor (false,false,false,true);
visitor.main(nodep);
}
+2 -2
View File
@@ -34,9 +34,9 @@ public:
// Everything that's possible
static void constifyAll(AstNetlist* nodep);
// Also, warn
static void constifyAllLint(AstNode* nodep);
static void constifyAllLint(AstNetlist* nodep);
// C++ datatypes
static void constifyCpp(AstNode* nodep);
static void constifyCpp(AstNetlist* nodep);
// Only the current node and lower
static void constifyTree(AstNode* nodep);
};
+37 -3
View File
@@ -29,6 +29,7 @@
#include <stdarg.h>
#include <unistd.h>
#include <vector>
#include <map>
#include "V3Global.h"
#include "V3Dead.h"
@@ -70,10 +71,15 @@ private:
// AstVar::user() -> int. Count of number of references
// AstVarScope::user() -> int. Count of number of references
// TYPES
typedef multimap<AstVarScope*,AstNodeAssign*> AssignMap;
// STATE
vector<AstVar*> m_varsp; // List of all encountered to avoid another loop through tree
vector<AstVarScope*> m_vscsp; // List of all encountered to avoid another loop through tree
AssignMap m_assignMap; // List of all simple assignments for each variable
bool m_elimUserVars; // Allow removal of user's vars
bool m_sideEffect; // Side effects discovered in assign RHS
//int debug() { return 9; }
// METHODS
@@ -102,6 +108,25 @@ private:
m_varsp.push_back(nodep);
}
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
// See if simple assignments to variables may be eliminated because that variable is never used.
// Similar code in V3Life
m_sideEffect = false;
nodep->rhsp()->iterateAndNext(*this);
// Has to be direct assignment without any EXTRACTing.
AstVarRef* varrefp = nodep->lhsp()->castVarRef();
if (varrefp && !m_sideEffect
&& varrefp->varScopep()) { // For simplicity, we only remove post-scoping
m_assignMap.insert(make_pair(varrefp->varScopep(), nodep));
} else { // Track like any other statement
nodep->lhsp()->iterateAndNext(*this);
}
}
virtual void visit(AstUCFunc* nodep, AstNUser*) {
m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment
nodep->iterateChildren(*this);
}
//-----
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
@@ -131,14 +156,22 @@ private:
}
bool canElim(AstVar* nodep) {
return (!nodep->isSigPublic() // Can't elim publics!
&& !nodep->isIO()
&& (nodep->isTemp() || nodep->isParam() || m_elimUserVars));
}
void deadCheckVar() {
// Delete any unused varscopes
for (vector<AstVarScope*>::iterator it = m_vscsp.begin(); it!=m_vscsp.end(); ++it) {
if ((*it)->user() == 0 && canElim((*it)->varp())) {
UINFO(4," Dead "<<(*it)<<endl);
(*it)->unlinkFrBack()->deleteTree(); (*it)=NULL;
AstVarScope* vscp = *it;
if (vscp->user() == 0 && canElim(vscp->varp())) {
UINFO(4," Dead "<<vscp<<endl);
pair <AssignMap::iterator,AssignMap::iterator> eqrange = m_assignMap.equal_range(vscp);
for (AssignMap::iterator it = eqrange.first; it != eqrange.second; ++it) {
AstNodeAssign* assp = it->second;
UINFO(4," Dead assign "<<assp<<endl);
assp->unlinkFrBack()->deleteTree(); assp=NULL;
}
vscp->unlinkFrBack()->deleteTree(); vscp=NULL;
}
}
for (vector<AstVar*>::iterator it = m_varsp.begin(); it!=m_varsp.end(); ++it) {
@@ -153,6 +186,7 @@ public:
// CONSTRUCTORS
DeadVisitor(AstNetlist* nodep, bool elimUserVars) {
m_elimUserVars = elimUserVars;
m_sideEffect = false;
// Operate on whole netlist
AstNode::userClearTree(); // userp() used on entire tree
nodep->accept(*this);
+7 -6
View File
@@ -224,12 +224,13 @@ private:
if (m_scopep) {
nodep->unlinkFrBack();
m_modp->addStmtp(nodep);
}
if (nodep->funcPublic()) {
// There may be multiple public functions by the same name;
// record for later correction or making of shells
m_modFuncs.insert(make_pair(nodep->name(), nodep));
nodep->name(m_scopep->nameDotless() +"__" + nodep->name());
if (nodep->funcPublic()) {
// There may be multiple public functions by the same name;
// record for later correction or making of shells
m_modFuncs.insert(make_pair(nodep->name(), nodep));
nodep->name(m_scopep->nameDotless() +"__" + nodep->name());
}
}
}
}
+14 -10
View File
@@ -102,9 +102,16 @@ public:
if (AstVar* portp = stmtp->castVar()) {
if (portp->isIO() && !portp->isFuncReturn()) {
if (args != "") args+= ", ";
args += portp->cType();
if (portp->isOutput()) args += "&";
args += " "+portp->name();
if (portp->isWide()) {
if (portp->isInOnly()) args += "const ";
args += portp->cType();
args += " (& "+portp->name();
args += ")["+cvtToStr(portp->widthWords())+"]";
} else {
args += portp->cType();
if (portp->isOutput()) args += "&";
args += " "+portp->name();
}
}
}
}
@@ -702,19 +709,19 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
if (nodep->attrScClocked() && nodep->isInput()) {
puts("sc_in_clk\t");
} else {
if (nodep->isTristate()) puts("sc_inout<");
if (nodep->isInout()) puts("sc_inout<");
else if (nodep->isInput()) puts("sc_in<");
else if (nodep->isOutput()) puts("sc_out<");
else nodep->v3fatalSrc("Unknown type");
puts(nodep->cType());
puts(nodep->scType());
puts(">\t");
}
puts(nodep->name());
puts(";\n");
} else { // C++ signals
ofp()->putAlign(nodep->isStatic(), nodep->widthAlignBytes());
if (nodep->isTristate()) puts("VL_INOUT");
if (nodep->isInout()) puts("VL_INOUT");
else if (nodep->isInput()) puts("VL_IN");
else if (nodep->isOutput()) puts("VL_OUT");
else nodep->v3fatalSrc("Unknown type");
@@ -941,10 +948,7 @@ void EmitCStmts::displayArg(AstDisplay* dispp, AstNode** elistp, string fmt, cha
} else {
string func;
string nfmt = displayFormat(*elistp, fmt, fmtLetter, true, false);
if ((*elistp)->isQuad() && (fmtLetter=='d')) {
nfmt+="ll";
func="(long long)("; // Must match %ll to avoid warnings
}
// We don't need to check for fmtLetter=='d', as it is above.
if ((*elistp)->isQuad() && (fmtLetter=='u'||fmtLetter=='o'||fmtLetter=='x')) {
nfmt+="ll";
func="(unsigned long long)("; // Must match %ull to avoid warnings
+3
View File
@@ -96,6 +96,9 @@ public:
// Imply generating verilated.o
if (v3Global.opt.exe()) {
v3Global.opt.addCppFile("verilated.cpp");
if (v3Global.opt.trace()) {
v3Global.opt.addCppFile("SpTraceVcdC.cpp");
}
}
V3StringSet dirs;
+10 -2
View File
@@ -236,6 +236,9 @@ void V3Error::v3abort () {
}
void V3Error::v3errorEnd (ostringstream& sstr) {
#ifdef __COVERITY__
if (s_errorCode==V3ErrorCode::FATAL) __coverity_panic__(x);
#endif
if (s_errorCode!=V3ErrorCode::SUPPRESS || debug()) {
cerr<<msgPrefix()<<sstr.str();
if (sstr.str()[sstr.str().length()-1] != '\n') {
@@ -268,8 +271,13 @@ void V3Error::v3errorEnd (ostringstream& sstr) {
}
#endif
}
abort();
// exit(10);
if (V3Error::debugDefault()) {
cerr<<msgPrefix()<<"Aborting since under --debug"<<endl;
abort();
} else {
exit(10);
}
}
}
}
+1 -3
View File
@@ -111,7 +111,6 @@ private:
nodep->name(), nodep->modp()->origName());
m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells
// Create assignments to the pins
AstNode* assignlistsp = NULL;
for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) {
UINFO(6," Pin change from "<<pinp->modVarp()<<endl);
// First, simplify it
@@ -142,13 +141,11 @@ private:
// Cleanup var names, etc, to not conflict
m_cellp = nodep;
newmodp->iterateAndNext(*this);
if (assignlistsp) assignlistsp->iterateAndNext(*this); // And cleanup any varrefs under assigns we created...
m_cellp = NULL;
// Move statements to top module
if (debug()>=9) { newmodp->dumpTree(cout,"fixmod:"); }
AstNode* stmtsp = newmodp->stmtsp();
if (stmtsp) stmtsp->unlinkFrBackWithNext();
if (assignlistsp) m_modp->addStmtp(assignlistsp);
if (stmtsp) m_modp->addStmtp(stmtsp);
// Remove the cell
newmodp->deleteTree(); newmodp=NULL; // Clear any leftover ports, etc
@@ -353,6 +350,7 @@ private:
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
// Cleanup link until V3LinkDot can correct it
nodep->taskp(NULL);
nodep->iterateChildren(*this);
}
// Nop's to speed up the loop
virtual void visit(AstAlways* nodep, AstNUser*) {
+9 -5
View File
@@ -79,7 +79,7 @@ private:
// or ASSIGNW(expr,VARXREF(p)) (if sub's output)
UINFO(4," PIN "<<nodep<<endl);
if (debug()>=9) nodep->dumpTree(cout," Pin_oldb: ");
if (nodep->modVarp()->isOutput() && nodep->exprp()->castConst())
if (nodep->modVarp()->isOutOnly() && nodep->exprp()->castConst())
nodep->v3error("Output pin is assigned to a constant, electrical short");
// Use userp on the PIN to indicate we created an assign for this pin
if (!nodep->user()) {
@@ -90,7 +90,9 @@ private:
AstNode* exprp = nodep->exprp()->cloneTree(false);
if (nodep->width() != nodep->modVarp()->width())
nodep->v3fatalSrc("Width mismatch, should have been handled in pinReconnectSimple\n");
if (nodep->modVarp()->isOutput()) {
if (nodep->modVarp()->isInout()) {
nodep->v3fatalSrc("Unsupported: Verilator is a 2-state simulator");
} else if (nodep->modVarp()->isOutput()) {
AstNode* rhsp = new AstVarXRef (exprp->fileline(), nodep->modVarp(), m_cellp->name(), false);
rhsp->widthSignedFrom(nodep);
AstAssignW* assp = new AstAssignW (exprp->fileline(), exprp, rhsp);
@@ -236,12 +238,14 @@ void V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstModule* modp) {
} else {
// Make a new temp wire
//if (1||debug()>=9) { pinp->dumpTree(cout,"in_pin:"); }
AstAssignW* assignp;
AstAssignW* assignp = NULL;
AstNode* pinexprp = pinp->exprp()->unlinkFrBack();
string newvarname = "__Vcellinp__"+cellp->name()+"__"+pinp->name();
AstVar* newvarp = new AstVar (pinVarp->fileline(), AstVarType::MODULETEMP, newvarname, pinVarp);
modp->addStmtp(newvarp);
if (pinVarp->isOutput()) {
if (pinVarp->isInout()) {
pinVarp->v3fatalSrc("Unsupported: Inout connections to pins must be direct one-to-one connection (without any expression)");
} else if (pinVarp->isOutput()) {
// See also V3Inst
AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, false);
if (pinp->width() > rhsp->width()) {
@@ -265,7 +269,7 @@ void V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstModule* modp) {
pinp->exprp(new AstVarRef (pinexprp->fileline(), newvarp, false));
}
pinp->widthSignedFrom(pinp->exprp());
modp->addStmtp(assignp);
if (assignp) modp->addStmtp(assignp);
//if (1||debug()) { pinp->dumpTree(cout," out:"); }
//if (1||debug()) { assignp->dumpTree(cout," aout:"); }
}
+294 -135
View File
@@ -38,152 +38,243 @@
#include "V3Life.h"
#include "V3Stats.h"
#include "V3Ast.h"
#include "V3Const.h"
//######################################################################
// Life state, as a visitor of each AstNode
// Structure for global state
class LifeVarEntry {
AstNode* m_assignp; // Last assignment to this varscope
bool m_firstSet; // True if creation was a set (and thus block above may have a set that can be deleted
class LifeState {
// STATE
public:
LifeVarEntry() { // Construction for when a var is used
clearAssign();
m_firstSet = false;
V3Double0 m_statAssnDel; // Statistic tracking
V3Double0 m_statAssnCon; // Statistic tracking
public:
LifeState() {}
~LifeState() {
V3Stats::addStat("Optimizations, Lifetime assign deletions", m_statAssnDel);
V3Stats::addStat("Optimizations, Lifetime constant prop", m_statAssnCon);
}
LifeVarEntry(AstNode* assp) { // Construction for when a var is set
m_assignp = assp;
m_firstSet = true;
}
LifeVarEntry(bool) { // Construction for when a var is set, but ass isn't
m_assignp = NULL;
m_firstSet = true;
}
AstNode* assignp() const { return m_assignp; }
bool firstSet() const { return m_firstSet; }
void clearAssign() { m_assignp = NULL; }
void newerAssign(AstNode* assp) { m_assignp = assp; }
};
class LifeVisitor : public AstNVisitor {
private:
// NODE STATE
// AstVarScope::user() -> int. Used in combining to detect duplicates
//######################################################################
// Structure for each variable encountered
// STATE
//static int debug() { return 9; }
int m_ifCount; // If counter
V3Double0 m_statAssnDel; // Statistic tracking
class LifeVarEntry {
AstNodeAssign* m_assignp; // Last assignment to this varscope, NULL if no longer relevant
AstConst* m_constp; // Known constant value
bool m_setBeforeUse; // First access was a set (and thus block above may have a set that can be deleted
bool m_everSet; // Was ever assigned (and thus above block may not preserve constant propagation)
inline void init (bool setBeforeUse) {
m_assignp = NULL;
m_constp = NULL;
m_setBeforeUse = setBeforeUse;
m_everSet = false;
}
public:
class SIMPLEASSIGN {};
class COMPLEXASSIGN {};
class CONSUMED {};
LifeVarEntry(SIMPLEASSIGN, AstNodeAssign* assp) {
init(true); simpleAssign(assp);
}
LifeVarEntry(COMPLEXASSIGN) {
init(false); complexAssign();
}
LifeVarEntry(CONSUMED) {
init(false); consumed();
}
~LifeVarEntry() {}
inline void simpleAssign(AstNodeAssign* assp) { // New simple A=.... assignment
m_assignp = assp;
m_constp = NULL;
m_everSet = true;
if (assp->rhsp()->castConst()) m_constp = assp->rhsp()->castConst();
}
inline void complexAssign() { // A[x]=... or some complicated assignment
m_assignp = NULL;
m_constp = NULL;
m_everSet = true;
}
inline void consumed() { // Rvalue read of A
m_assignp = NULL;
}
AstNodeAssign* assignp() const { return m_assignp; }
AstConst* constNodep() const { return m_constp; }
bool setBeforeUse() const { return m_setBeforeUse; }
bool everSet() const { return m_everSet; }
};
//######################################################################
// Structure for all variables under a given meta-basic block
class LifeBlock {
// NODE STATE
// Cleared each AstIf:
// AstVarScope::user() -> int. Used in combining to detect duplicates
// LIFE MAP
// For each basic block, we'll make a new map of what variables that if/else is changing
typedef std::map<AstVarScope*, LifeVarEntry> LifeMap;
LifeMap *m_lifep; // Current active lifetime map for current scope
LifeMap m_map; // Current active lifetime map for current scope
LifeBlock* m_aboveLifep; // Upper life, or NULL
LifeState* m_statep; // Current global state
public:
LifeBlock(LifeBlock* aboveLifep, LifeState* statep) {
m_aboveLifep = aboveLifep; // Null if top
m_statep = statep;
}
~LifeBlock() {}
// METHODS
void checkRemoveAssign(LifeVarEntry* entp) {
// Check the var entry, and remove if appropriate
if (AstNode* oldassp = entp->assignp()) {
UINFO(7," PREV: "<<oldassp<<endl);
// Redundant assignment, in same level block
if (debug()>4) oldassp->dumpTree(cout, " REMOVE/SAMEBLK ");
entp->clearAssign();
oldassp->unlinkFrBack();
pushDeletep(oldassp);
m_statAssnDel++;
void checkRemoveAssign(const LifeMap::iterator& it) {
AstVar* varp = it->first->varp();
LifeVarEntry* entp = &(it->second);
if (!varp->isSigPublic()) {
// Rather then track what sigs AstUCFunc/AstUCStmt may change,
// we just don't optimize any public sigs
// Check the var entry, and remove if appropriate
if (AstNode* oldassp = entp->assignp()) {
UINFO(7," PREV: "<<oldassp<<endl);
// Redundant assignment, in same level block
if (debug()>4) oldassp->dumpTree(cout, " REMOVE/SAMEBLK ");
entp->complexAssign();
oldassp->unlinkFrBack()->deleteTree(); oldassp=NULL;
m_statep->m_statAssnDel++;
}
}
}
void setLast(AstVarScope* nodep, AstNode* assp) {
void simpleAssign(AstVarScope* nodep, AstNodeAssign* assp) {
// Do we have a old assignment we can nuke?
UINFO(4," ASSIGNof: "<<nodep<<endl);
UINFO(7," new: "<<assp<<endl);
LifeMap::iterator iter = m_lifep->find(nodep);
if (iter != m_lifep->end()) {
checkRemoveAssign(&(iter->second));
iter->second.newerAssign(assp);
LifeMap::iterator it = m_map.find(nodep);
if (it != m_map.end()) {
checkRemoveAssign(it);
it->second.simpleAssign(assp);
} else {
m_lifep->insert(make_pair(nodep,LifeVarEntry(assp)));
m_map.insert(make_pair(nodep,LifeVarEntry(LifeVarEntry::SIMPLEASSIGN(), assp)));
}
//lifeDump();
}
void clearLastAssign(AstVarScope* nodep) {
void complexAssign(AstVarScope* nodep) {
UINFO(4," clearof: "<<nodep<<endl);
LifeMap::iterator iter = m_lifep->find(nodep);
if (iter != m_lifep->end()) {
iter->second.clearAssign();
LifeMap::iterator it = m_map.find(nodep);
if (it != m_map.end()) {
it->second.complexAssign();
} else {
m_lifep->insert(make_pair(nodep,LifeVarEntry()));
m_map.insert(make_pair(nodep,LifeVarEntry(LifeVarEntry::COMPLEXASSIGN())));
}
}
void lifeDump(LifeMap* lifep) {
void varUsageReplace (AstVarScope* nodep, AstVarRef* varrefp) {
// Variable rvalue. If it references a constant, we can simply replace it
LifeMap::iterator it = m_map.find(nodep);
if (it != m_map.end()) {
if (AstConst* constp = it->second.constNodep()) {
if (!varrefp->varp()->isSigPublic()) {
// Aha, variable is constant; substitute in.
// We'll later constant propagate
UINFO(4," replaceconst: "<<varrefp<<endl);
varrefp->replaceWith(constp->cloneTree(false));
varrefp->deleteTree(); varrefp=NULL;
m_statep->m_statAssnCon++;
return; // **DONE, no longer a var reference**
}
}
UINFO(4," usage: "<<nodep<<endl);
it->second.consumed();
} else {
m_map.insert(make_pair(nodep,LifeVarEntry(LifeVarEntry::CONSUMED())));
}
}
void complexAssignFind(AstVarScope* nodep) {
LifeMap::iterator it = m_map.find(nodep);
if (it != m_map.end()) {
UINFO(4," casfind: "<<it->first<<endl);
it->second.complexAssign();
} else {
m_map.insert(make_pair(nodep,LifeVarEntry(LifeVarEntry::COMPLEXASSIGN())));
}
}
void consumedFind(AstVarScope* nodep) {
LifeMap::iterator it = m_map.find(nodep);
if (it != m_map.end()) {
it->second.consumed();
} else {
m_map.insert(make_pair(nodep,LifeVarEntry(LifeVarEntry::CONSUMED())));
}
}
void lifeToAbove() {
// Any varrefs under a if/else branch affect statements outside and after the if/else
if (!m_aboveLifep) v3fatalSrc("Pushing life when already at the top level");
for (LifeMap::iterator it = m_map.begin(); it!=m_map.end(); ++it) {
AstVarScope* nodep = it->first;
m_aboveLifep->complexAssignFind(nodep);
if (it->second.everSet()) {
// Record there may be an assignment, so we don't constant propagate across the if.
complexAssignFind(nodep);
} else {
// Record consumption, so we don't eliminate earlier assignments
consumedFind(nodep);
}
}
}
void dualBranch (LifeBlock* life1p, LifeBlock* life2p) {
// Find any common sets on both branches of IF and propagate upwards
//life1p->lifeDump();
//life2p->lifeDump();
AstNode::userClearTree(); // userp() used on entire tree
for (LifeMap::iterator it = life1p->m_map.begin(); it!=life1p->m_map.end(); ++it) {
// When the if branch sets a var before it's used, mark that variable
if (it->second.setBeforeUse()) it->first->user(1);
}
for (LifeMap::iterator it = life2p->m_map.begin(); it!=life2p->m_map.end(); ++it) {
// When the else branch sets a var before it's used
AstVarScope* nodep = it->first;
if (it->second.setBeforeUse() && nodep->user()) {
// Both branches set the var, we can remove the assignment before the IF.
UINFO(4,"DUALBRANCH "<<nodep<<endl);
LifeMap::iterator itab = m_map.find(nodep);
if (itab != m_map.end()) {
checkRemoveAssign(itab);
}
}
}
//this->lifeDump();
}
// DEBUG
void lifeDump() {
UINFO(5, " LifeMap:"<<endl);
for (LifeMap::iterator it = lifep->begin(); it!=lifep->end(); ++it) {
for (LifeMap::iterator it = m_map.begin(); it!=m_map.end(); ++it) {
UINFO(5, " Ent: "
<<(it->second.firstSet()?"[F] ":" ")
<<(it->second.setBeforeUse()?"[F] ":" ")
<<it->first<<endl);
if (it->second.assignp()) {
UINFO(5, " Ass: "<<it->second.assignp()<<endl);
}
}
}
void clearLifeFromSublife (LifeMap* sublifep) {
// Any varrefs under a if/else branch affect statements outside and after the if/else
for (LifeMap::iterator it = sublifep->begin(); it!=sublifep->end(); ++it) {
clearLastAssign(it->first);
}
}
void dualBranch (LifeMap* life1p, LifeMap* life2p) {
// Find any common sets on both branches of IF and propagate upwards
//lifeDump(life1p);
//lifeDump(life2p);
m_ifCount++;
for (LifeMap::iterator it = life1p->begin(); it!=life1p->end(); ++it) {
// When the if branch sets a var before it's used, mark that variable
if (it->second.firstSet()) it->first->user(m_ifCount);
}
for (LifeMap::iterator it = life2p->begin(); it!=life2p->end(); ++it) {
// When the else branch sets a var before it's used
AstVarScope* nodep = it->first;
if (it->second.firstSet()
&& nodep->user()==m_ifCount) { // And the if hit the same var
UINFO(4,"DUALBRANCH "<<nodep<<endl);
LifeMap::iterator iter = m_lifep->find(nodep);
if (iter != m_lifep->end()) {
checkRemoveAssign(&(iter->second));
iter->second.clearAssign();
} else {
m_lifep->insert(make_pair(nodep,LifeVarEntry(true)));
}
}
}
//lifeDump(m_lifep);
}
};
//######################################################################
// Life state, as a visitor of each AstNode
class LifeVisitor : public AstNVisitor {
private:
// STATE
LifeState* m_statep; // Current state
bool m_sideEffect; // Side effects discovered in assign RHS
//static int debug() { return 9; }
// LIFE MAP
// For each basic block, we'll make a new map of what variables that if/else is changing
typedef std::map<AstVarScope*, LifeVarEntry> LifeMap;
LifeBlock* m_lifep; // Current active lifetime map for current scope
// METHODS
// VISITORS
virtual void visit(AstModule* nodep, AstNUser*) {
// Only track the top scopes, not lower level functions
if (nodep->isTop()) nodep->iterateChildren(*this);
}
virtual void visit(AstTopScope* nodep, AstNUser*) {
AstNode::userClearTree(); // userp() used on entire tree
AstNode::user2ClearTree(); // userp() used on entire tree
AstNode::user3ClearTree(); // userp() used on entire tree
AstNode::user4ClearTree(); // userp() used on entire tree
AstScope* scopep = nodep->scopep();
if (!scopep) nodep->v3fatalSrc("TopScope has no scope\n");
AstCFunc* evalp = NULL;
for (AstNode* searchp = scopep->blocksp(); searchp; searchp=searchp->nextp()) {
if (AstCFunc* funcp = searchp->castCFunc()) {
if (funcp->name() == "_eval") {
evalp = funcp;
break;
}
}
}
if (!evalp) nodep->v3fatalSrc("Top _eval entry function not found\n");
evalp->iterateChildren(*this);
}
virtual void visit(AstVarRef* nodep, AstNUser*) {
// Consumption/generation of a variable,
// it's used so can't elim assignment before this use.
@@ -191,44 +282,61 @@ private:
//
AstVarScope* vscp = nodep->varScopep();
if (!vscp) nodep->v3fatalSrc("Scope not assigned");
clearLastAssign(vscp);
if (nodep->lvalue()) {
m_lifep->complexAssign(vscp);
} else {
m_lifep->varUsageReplace(vscp, nodep); nodep=NULL;
}
}
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
// Collect any used variables first, as lhs may also be on rhs
// Similar code in V3Dead
vluint64_t lastEdit = AstNode::editCountGbl(); // When it was last edited
m_sideEffect = false;
nodep->rhsp()->iterateAndNext(*this);
if (lastEdit != AstNode::editCountGbl()) {
// We changed something, try to constant propagate, but don't delete the
// assignment as we still need nodep to remain.
V3Const::constifyTree(nodep->rhsp());
}
// Has to be direct assignment without any EXTRACTing.
if (nodep->lhsp()->castVarRef()) {
if (nodep->lhsp()->castVarRef() && !m_sideEffect) {
AstVarScope* vscp = nodep->lhsp()->castVarRef()->varScopep();
if (!vscp) vscp->v3fatalSrc("Scope lost on variable");
setLast(vscp, nodep);
m_lifep->simpleAssign(vscp, nodep);
} else {
nodep->lhsp()->iterateAndNext(*this);
}
}
virtual void visit(AstAssignDly* nodep, AstNUser*) {
// Don't treat as normal assign; V3Life doesn't understand time sense
nodep->iterateChildren(*this);
}
//---- Track control flow changes
virtual void visit(AstNodeIf* nodep, AstNUser*) {
UINFO(4," IF "<<nodep<<endl);
// Condition is part of PREVIOUS block
nodep->condp()->iterateAndNext(*this);
LifeMap* prevLifeMapp = m_lifep;
LifeMap* ifLifep = new LifeMap;
LifeMap* elseLifep = new LifeMap;
LifeBlock* prevLifep = m_lifep;
LifeBlock* ifLifep = new LifeBlock (prevLifep, m_statep);
LifeBlock* elseLifep = new LifeBlock (prevLifep, m_statep);
{
m_lifep = ifLifep;
nodep->ifsp()->iterateAndNext(*this);
m_lifep = prevLifep;
}
{
m_lifep = elseLifep;
nodep->elsesp()->iterateAndNext(*this);
m_lifep = prevLifep;
}
UINFO(4," join "<<endl);
m_lifep = prevLifeMapp;
// Find sets on both flows
dualBranch (ifLifep, elseLifep);
m_lifep->dualBranch (ifLifep, elseLifep);
// For the next assignments, clear any variables that were read or written in the block
clearLifeFromSublife(ifLifep);
clearLifeFromSublife(elseLifep);
ifLifep->lifeToAbove();
elseLifep->lifeToAbove();
delete ifLifep;
delete elseLifep;
}
@@ -240,24 +348,25 @@ private:
// assignment in the body that's used in the cond. (And otherwise
// would because it only appears used after-the-fact. So, we model
// it as a IF statement, and just don't allow elimination of
// variables in the body.
LifeMap* prevLifeMapp = m_lifep;
LifeMap* condLifep = new LifeMap;
LifeMap* bodyLifep = new LifeMap;
// variables across the body.
LifeBlock* prevLifep = m_lifep;
LifeBlock* condLifep = new LifeBlock (prevLifep, m_statep);
LifeBlock* bodyLifep = new LifeBlock (prevLifep, m_statep);
{
m_lifep = condLifep;
nodep->precondsp()->iterateAndNext(*this);
nodep->condp()->iterateAndNext(*this);
m_lifep = prevLifep;
}
{
m_lifep = bodyLifep;
nodep->bodysp()->iterateAndNext(*this);
m_lifep = prevLifep;
}
UINFO(4," joinfor"<<endl);
m_lifep = prevLifeMapp;
// For the next assignments, clear any variables that were read or written in the block
clearLifeFromSublife(condLifep);
clearLifeFromSublife(bodyLifep);
condLifep->lifeToAbove();
bodyLifep->lifeToAbove();
delete condLifep;
delete bodyLifep;
}
@@ -267,6 +376,11 @@ private:
// Enter the function and trace it
nodep->funcp()->accept(*this);
}
virtual void visit(AstUCFunc* nodep, AstNUser*) {
m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment
nodep->iterateChildren(*this);
}
virtual void visit(AstVar*, AstNUser*) {} // Don't want varrefs under it
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
@@ -274,15 +388,60 @@ private:
public:
// CONSTRUCTORS
LifeVisitor(AstNetlist* nodep) {
m_ifCount = 1;
m_lifep = new LifeMap;
LifeVisitor(AstNode* nodep, LifeState* statep) {
UINFO(4," LifeVisitor on "<<nodep<<endl);
m_statep = statep;
m_sideEffect = false;
{
m_lifep = new LifeBlock (NULL, m_statep);
nodep->accept(*this);
delete m_lifep; m_lifep=NULL;
}
}
virtual ~LifeVisitor() {}
};
//######################################################################
class LifeTopVisitor : public AstNVisitor {
// Visit all top nodes searching for functions that are entry points we want to start
// finding code within.
private:
// STATE
LifeState* m_statep; // Current state
// VISITORS
virtual void visit(AstCFunc* nodep, AstNUser*) {
if (nodep->entryPoint()) {
// Usage model 1: Simulate all C code, doing lifetime analysis
LifeVisitor visitor (nodep, m_statep);
}
}
virtual void visit(AstAlways* nodep, AstNUser*) {
// Usage model 2: Cleanup basic blocks
LifeVisitor visitor (nodep, m_statep);
}
virtual void visit(AstInitial* nodep, AstNUser*) {
// Usage model 2: Cleanup basic blocks
LifeVisitor visitor (nodep, m_statep);
}
virtual void visit(AstFinal* nodep, AstNUser*) {
// Usage model 2: Cleanup basic blocks
LifeVisitor visitor (nodep, m_statep);
}
virtual void visit(AstVar*, AstNUser*) {} // Accelerate
virtual void visit(AstNodeStmt*, AstNUser*) {} // Accelerate
virtual void visit(AstNodeMath*, AstNUser*) {} // Accelerate
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
}
public:
// CONSTRUCTORS
LifeTopVisitor(AstNetlist* nodep, LifeState* statep) {
m_statep = statep;
nodep->accept(*this);
delete m_lifep;
}
virtual ~LifeVisitor() {
V3Stats::addStat("Optimizations, Lifetime assign deletions", m_statAssnDel);
}
virtual ~LifeTopVisitor() {}
};
//######################################################################
@@ -290,6 +449,6 @@ public:
void V3Life::lifeAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
// Delete lifelicate assignments
LifeVisitor visitor (nodep);
LifeState state;
LifeTopVisitor visitor (nodep, &state);
}
+1 -1
View File
@@ -140,7 +140,7 @@ void V3LinkLevel::wrapTop(AstNetlist* netlistp) {
AstVar* varp = oldvarp->cloneTree(false)->castVar();
newmodp->addStmtp(varp);
varp->sigPublic(true); // User needs to be able to get to it...
if (oldvarp->isInput() || oldvarp->isOutput()) {
if (oldvarp->isIO()) {
oldvarp->primaryIO(true);
varp->primaryIO(true);
}
+2 -2
View File
@@ -104,14 +104,14 @@ private:
nodep->v3error("Arrayed variables may not be inputs nor outputs");
}
if (m_ftaskp) nodep->funcLocal(true);
if (nodep && nodep->isSigPublic()) m_modp->modPublic(true); // Avoid flattening if signals are exposed
if (nodep->isSigPublic()) m_modp->modPublic(true); // Avoid flattening if signals are exposed
}
virtual void visit(AstNodeVarRef* nodep, AstNUser*) {
// VarRef: Resolve its reference
if (nodep->varp()) {
nodep->varp()->usedParam(true);
if (nodep->lvalue() && nodep->varp()->isInput()) {
if (nodep->lvalue() && nodep->varp()->isInOnly()) {
nodep->v3error("Assigning to input variable: "<<nodep->prettyName());
}
}
-2
View File
@@ -115,9 +115,7 @@ V3Number::V3Number (FileLine* fileline, const char* sourcep) {
// Otherwise...
else if (!m_sized) {
width(32, false); // Says the spec.
#ifndef VL_UNSIGNED
if (unbased) isSigned(true); // Also says the spec.
#endif
}
// Ignore leading blanks
+3
View File
@@ -366,6 +366,7 @@ void V3Options::parseOptsList(FileLine* fl, int argc, char** argv) {
else if ( onoff (sw, "-coverage-line", flag/*ref*/) ){ m_coverageLine = flag; }
else if ( onoff (sw, "-coverage-user", flag/*ref*/) ){ m_coverageUser = flag; }
else if ( onoff (sw, "-covsp", flag/*ref*/) ) { } // TBD
else if ( onoff (sw, "-debug-check", flag/*ref*/) ){ m_debugCheck = flag; }
else if ( onoff (sw, "-dump-tree", flag/*ref*/) ) { m_dumpTree = flag; }
else if ( onoff (sw, "-exe", flag/*ref*/) ) { m_exe = flag; }
else if ( onoff (sw, "-ignc", flag/*ref*/) ) { m_ignc = flag; }
@@ -557,6 +558,7 @@ V3Options::V3Options() {
m_coverageLine = false;
m_coverageUser = false;
m_debugCheck = false;
m_dumpTree = false;
m_exe = false;
m_ignc = false;
@@ -603,6 +605,7 @@ void V3Options::setDebugMode(int level) {
V3Error::debugDefault(level);
m_dumpTree = true;
m_stats = true;
m_debugCheck = true;
cout << "Starting "<<version()<<endl;
}
+3
View File
@@ -49,6 +49,7 @@ class V3Options {
bool m_assert; // main switch: --assert
bool m_coverageLine; // main switch: --coverage-block
bool m_coverageUser; // main switch: --coverage-func
bool m_debugCheck; // main switch: --debug-check
bool m_dumpTree; // main switch: --dump-tree
bool m_exe; // main switch: --exe
bool m_ignc; // main switch: --ignc
@@ -134,6 +135,7 @@ class V3Options {
bool coverage() const { return m_coverageUser || m_coverageLine; }
bool coverageLine() const { return m_coverageLine; }
bool coverageUser() const { return m_coverageUser; }
bool debugCheck() const { return m_debugCheck; }
bool dumpTree() const { return m_dumpTree; }
bool exe() const { return m_exe; }
bool trace() const { return m_trace; }
@@ -181,6 +183,7 @@ class V3Options {
static string version();
static string argString(int argc, char** argv); ///< Return list of arguments as simple string
string allArgsString(); ///< Return all passed arguments as simple string
void bin(const string& flag) { m_bin = flag; }
void parseOpts(FileLine* fl, int argc, char** argv);
void parseOptsList (FileLine* fl, int argc, char** argv);
void parseOptsFile (FileLine* fl, const string& filename);
+4
View File
@@ -91,6 +91,10 @@ void V3Read::readFile(FileLine* fileline, const string& modfilename, bool inLibr
if (!v3Global.opt.preprocOnly()) {
lexFile (vppfilename, modfilename);
}
if (!V3Error::debugDefault()) {
unlink (vppfilename.c_str());
}
}
void V3Read::lexFile(const string& vppfilename, const string& modname) {
-10
View File
@@ -284,9 +284,7 @@ private:
// VISITORS - defaults
virtual void visit(AstNodeMath* nodep, AstNUser*) {
#ifndef VL_UNSIGNED
nodep->v3fatalSrc("Visit function missing? Signedness unknown for this node: "<<nodep);
#endif
nodep->iterateChildren(*this);
}
virtual void visit(AstNode* nodep, AstNUser*) {
@@ -347,12 +345,6 @@ public:
class SignedRemoveVisitor : public AstNVisitor {
private:
// METHODS
void supportCheck(AstNode* nodep) {
#ifdef VL_UNSIGNED
if (nodep->isSigned()) nodep->v3error("Unsupported: signed numbers");
#endif
}
// VISITORS
virtual void visit(AstSigned* nodep, AstNUser*) {
replaceWithSignedVersion(nodep, nodep->lhsp()->unlinkFrBack()); nodep=NULL;
@@ -362,13 +354,11 @@ private:
}
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
supportCheck(nodep);
}
void replaceWithSignedVersion(AstNode* nodep, AstNode* newp) {
UINFO(6," Replace "<<nodep<<" w/ "<<newp<<endl);
nodep->replaceWith(newp);
newp->widthSignedFrom(nodep);
supportCheck(nodep);
pushDeletep(nodep); nodep=NULL;
}
public:
+10 -8
View File
@@ -227,8 +227,14 @@ private:
nextpinp = pinp->nextp();
pinp->unlinkFrBack(); // Relinked to assignment below
//
if (portp->isTristate()) {
refp->v3error("Unsupported: Inouts in functions/tasks");
if (portp->isInout()) {
if (AstVarRef* varrefp = pinp->castVarRef()) {
// Connect to this exact variable
AstVarScope* localVscp = varrefp->varScopep(); if (!localVscp) varrefp->v3fatalSrc("Null var scope");
portp->user2p(localVscp);
} else {
pinp->v3error("Unsupported: Function/task input argument is not simple variable");
}
}
else if (portp->isOutput() && outvscp) {
refp->v3error("Outputs not allowed in function declarations");
@@ -298,7 +304,7 @@ private:
AstVar* portp = NULL;
if (NULL!=(portp = nodep->castFunc()->fvarp()->castVar())) {
if (!portp->isFuncReturn()) nodep->v3error("Not marked as function return var");
if (portp->isWide()) nodep->v3error("Unsupported: Public functions/tasks with inputs or outputs > 64 bits wide.");
if (portp->isWide()) nodep->v3error("Unsupported: Public functions with return > 64 bits wide. (Make it a output instead.)");
portp->unlinkFrBack();
rtnvarp = portp;
rtnvarp->funcLocal(true);
@@ -315,6 +321,7 @@ private:
if (rtnvarp) funcp->addArgsp(rtnvarp);
funcp->dontCombine(true);
funcp->funcPublic(true);
funcp->entryPoint(true);
funcp->isStatic(false);
// We need to get a pointer to all of our variables (may have eval'ed something else earlier)
@@ -332,11 +339,6 @@ private:
portp->unlinkFrBack();
portp->funcLocal(true);
funcp->addArgsp(portp);
if (portp->isWide()) {
// As we don't want to export our WData arrays to users,
// and casting to sc_bv's is ugly, we'll just...
nodep->v3error("Unsupported: Public functions/tasks with inputs or outputs > 64 bits wide.");
}
} else {
// "Normal" variable, mark inside function
portp->funcLocal(true);
+2 -2
View File
@@ -298,9 +298,9 @@ private:
initp = NULL; if (nodep->backp()->nextp() == nodep) initp=nodep->backp();
// Grab assignment
AstNode* incp = NULL; // Should be last statement
for (incp = nodep->bodysp(); incp->nextp(); incp = incp->nextp()) {}
for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {}
if (incp) V3Const::constifyTree(incp);
for (incp = nodep->bodysp(); incp->nextp(); incp = incp->nextp()) {} // Again, as may have changed
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(),
+10
View File
@@ -248,7 +248,13 @@ void process () {
V3Case::caseAll(v3Global.rootp());
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("case.tree"));
// Push constants across variables and remove redundant assignments
V3Const::constifyAll(v3Global.rootp());
if (v3Global.opt.oLife()) {
V3Life::lifeAll(v3Global.rootp());
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("life.tree"));
}
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
// Make large low-fanin logic blocks into lookup tables
@@ -327,7 +333,9 @@ void process () {
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("clock.tree"));
// Cleanup any dly vars or other temps that are simple assignments
// Life must be done before Subst, as it assumes each CFunc under _eval is called only once.
if (v3Global.opt.oLife()) {
V3Const::constifyAll(v3Global.rootp());
V3Life::lifeAll(v3Global.rootp());
}
if (v3Global.opt.oLifePost()) {
@@ -459,9 +467,11 @@ int main(int argc, char** argv, char** env) {
srand( (int) randseed);
// Preprocessor
// Before command parsing so we can handle -Ds on command line.
V3PreShell::boot(env);
// Command option parsing
v3Global.opt.bin(argv[0]);
string argString = V3Options::argString(argc-1, argv+1);
v3Global.opt.parseOpts(new FileLine("COMMAND_LINE",0), argc-1, argv+1);
if (v3Global.opt.coverage() && !v3Global.opt.systemPerl()) {
+13 -10
View File
@@ -324,6 +324,7 @@ sub tree_line {
match_func => "match_${type}_${n}",
match_if => $mif,
exec_func => $exec_func,
uinfo_level => ($to =~ /^!/ ? 0:7),
};
($typefunc->{uinfo} = $func) =~ s/[ \t\"\{\}]+/ /g;
push @{$self->{treeop}{$type}}, $typefunc;
@@ -373,8 +374,11 @@ sub _exec_new_recurse {
sub treeop_exec_func {
my $self = shift;
my $func = shift;
my $out = "";
$func =~ s/^!//;
if ($func =~ /^\s*[a-zA-Z0-9]+\s*\(/) { # Function call
$func =~ s/\$([a-zA-Z0-9]+)/nodep->$1()/g;
(my $outl = $func) =~ s/\$([a-zA-Z0-9]+)/nodep->$1()/g;
$out .= $outl;
}
elsif ($func =~ /^\s*Ast([a-zA-Z0-9]+) \s*\{\s* (.*) \s* \}$/x) {
@@ -419,23 +423,22 @@ sub treeop_exec_func {
$_Exec_Nsyms = 0;
_exec_syms_recurse($aref);
$func = "";
foreach my $sym (sort {$_Exec_Syms{$a} cmp $_Exec_Syms{$b}} (keys %_Exec_Syms)) {
my $argnp = $_Exec_Syms{$sym};
my $arg = add_nodep($sym);
$func .= "AstNode* ${argnp} = ${arg}->unlinkFrBack();\n";
$out .= "AstNode* ${argnp} = ${arg}->unlinkFrBack();\n";
}
$func .= "AstNode* newp = " . _exec_new_recurse($aref).";\n";
$func .= "nodep->replaceWith(newp);";
$func .= "nodep->deleteTree(); nodep=NULL;";
#print "FF $func\n" if $Debug;
$out .= "AstNode* newp = " . _exec_new_recurse($aref).";\n";
$out .= "nodep->replaceWith(newp);";
$out .= "nodep->deleteTree(); nodep=NULL;";
#print "FF $out\n" if $Debug;
} elsif ($func eq "NEVER") {
$func = "nodep->v3fatalSrc(\"Executing transform that was NEVERed\");";
$out .= "nodep->v3fatalSrc(\"Executing transform that was NEVERed\");";
} else {
$self->error("Unknown execution function format: $func\n");
}
return $func;
return $out;
}
sub tree_match {
@@ -448,7 +451,7 @@ sub tree_match {
$self->print(" bool $typefunc->{match_func}(Ast${base}* nodep) {\n",
"\t// $typefunc->{comment}\n",);
$self->print( "\tif ($typefunc->{match_if}) {\n");
$self->print( "\t UINFO(7,(void*)(nodep)<<\" $typefunc->{uinfo}\\n\");\n");
$self->print( "\t UINFO($typefunc->{uinfo_level},(void*)(nodep)<<\" $typefunc->{uinfo}\\n\");\n");
$self->print( "\t $typefunc->{exec_func};\n");
$self->print( "\t return true;\n");
$self->print( "\t}\n");
+1 -1
View File
@@ -24,7 +24,7 @@
//**********************************************************************
//**** Version and host name
#define DTVERSION "Verilator 3.610 09/20/2006"
#define DTVERSION "Verilator 3.620 10/04/2006"
//**********************************************************************
//**** Functions
+3 -5
View File
@@ -627,11 +627,11 @@ senList: senitem { $$ = $1; }
;
senitem: senitemEdge { $$ = $1; }
| idVarRef ignoreRangeE { $$ = new AstSenItem(CRELINE(),AstEdgeType::ANYEDGE,$1); }
| idVarXRef ignoreRangeE { $$ = new AstSenItem(CRELINE(),AstEdgeType::ANYEDGE,$1); }
;
senitemEdge: yPOSEDGE idVarRef ignoreRangeE { $$ = new AstSenItem($1,AstEdgeType::POSEDGE,$2); }
| yNEGEDGE idVarRef ignoreRangeE { $$ = new AstSenItem($1,AstEdgeType::NEGEDGE,$2); }
senitemEdge: yPOSEDGE idVarXRef ignoreRangeE { $$ = new AstSenItem($1,AstEdgeType::POSEDGE,$2); }
| yNEGEDGE idVarXRef ignoreRangeE { $$ = new AstSenItem($1,AstEdgeType::NEGEDGE,$2); }
;
ignoreRangeE: /* empty */ { $$ = NULL; } /* ignored */
@@ -1086,9 +1086,7 @@ AstVar* V3Parse::createVariable(FileLine* fileline, string name, AstRange* array
rangep->cloneTree(false),
arrayp);
nodep->isSigned(V3Parse::s_varSigned);
#ifndef VL_UNSIGNED
if (type == AstVarType::INTEGER) nodep->isSigned(true);
#endif
if (V3Parse::s_varDecl != AstVarType::UNKNOWN) nodep->combineType(V3Parse::s_varDecl);
if (V3Parse::s_varIO != AstVarType::UNKNOWN) nodep->combineType(V3Parse::s_varIO);
+5 -3
View File
@@ -17,6 +17,8 @@ VERILATOR_ROOT := $(shell pwd)/..
export VERILATOR_ROOT
PWD := $(shell pwd)
PERL = perl
DEBUG_ON = --debug --trace-dups
#DEBUG = $(DEBUG_ON)
VALGRIND_ON = $(DEBUG_ON) --gdb "valgrind -v --leak-check=yes"
@@ -31,11 +33,11 @@ VERILATOR_FLAGS = --cc -f $(PWD)/../test_v/input.vc top.v
#VERILATOR_FLAGS += --trace
prep:
perl $(VERILATOR_ROOT)/bin/verilator $(DEBUG) $(VERILATOR_FLAGS)
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(DEBUG) $(VERILATOR_FLAGS)
prep_dbg:
perl $(VERILATOR_ROOT)/bin/verilator $(DEBUG_ON) $(VERILATOR_FLAGS)
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(DEBUG_ON) $(VERILATOR_FLAGS)
prep_vg:
perl $(VERILATOR_ROOT)/bin/verilator $(VALGRIND_ON) $(VERILATOR_FLAGS)
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(VALGRIND_ON) $(VERILATOR_FLAGS)
compile:
cd obj_dir ; $(MAKE) -j 3 -f ../Makefile_obj
+1 -1
View File
@@ -187,7 +187,7 @@ sub new {
make_top_shell => 1, # Make a default __top.v file
make_main => 1, # Make __main.cpp
# All compilers
v_flags => [split(/\s+/," -f input.vc")],
v_flags => [split(/\s+/," -f input.vc --debug-check")],
v_flags2 => [], # Overridden in some sim files
v_other_filenames => [], # After the filename so we can spec multiple files
# VCS
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
# $Id$
# 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
# General Public License or the Perl Artistic License.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+109
View File
@@ -0,0 +1,109 @@
// $Id$
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2006 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc; initial cyc=0;
reg [63:0] crc;
reg [63:0] sum;
reg out1;
sub sub (.in(crc[23:0]), .out1(out1));
always @ (posedge clk) begin
$write("[%0t] cyc==%0d crc=%x sum=%x out=%x\n",$time, cyc, crc, sum, out1);
cyc <= cyc + 1;
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
sum <= {sum[62:0], sum[63]^sum[2]^sum[0]} ^ {63'h0,out1};
if (cyc==1) begin
// Setup
crc <= 64'h00000000_00000097;
sum <= 64'h0;
end
else if (cyc==90) begin
if (sum != 64'h2e5cb972eb02b8a0) $stop;
end
else if (cyc==91) begin
end
else if (cyc==92) begin
end
else if (cyc==93) begin
end
else if (cyc==94) begin
end
else if (cyc==99) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module sub (/*AUTOARG*/
// Outputs
out1,
// Inputs
in
);
input [23:0] in;
output reg [0:0] out1;
parameter [1023:0] RANDOM = 1024'b101011010100011011100111101001000000101000001111111111100110000110011011010110011101000100110000110101111101000111100100010111001001110001010101000111000100010000010011100001100011110110110000101100011111000110111110010110011000011111111010101110001101010010001111110111100000110111101100110101110001110110000010000110101110111001111001100001101110001011100111001001110101001010000110101010100101111000010000010110100101110100110000110110101000100011101111100011000110011001100010010011001101100100101110010100110101001110011111110010000111001111000010001101100101101110111110001000010110010011100101001011111110011010110111110000110010011110001110110011010011010110011011111001110100010110100011100001011000101111000010011111010111001110110011101110101011111001100011000101000001000100111110010100111011101010101011001101000100000101111110010011010011010001111010001110000110010100011110110011001010000011001010010110111101010010011111111010001000101100010100100010011001100110000111111000001000000001001111101110000100101;
always @* begin
casez (in[17:16])
2'b00: casez (in[2:0])
3'h0: out1[0] = in[0]^RANDOM[0];
3'h1: out1[0] = in[0]^RANDOM[1];
3'h2: out1[0] = in[0]^RANDOM[2];
3'h3: out1[0] = in[0]^RANDOM[3];
3'h4: out1[0] = in[0]^RANDOM[4];
3'h5: out1[0] = in[0]^RANDOM[5];
3'h6: out1[0] = in[0]^RANDOM[6];
3'h7: out1[0] = in[0]^RANDOM[7];
endcase
2'b01: casez (in[2:0])
3'h0: out1[0] = RANDOM[10];
3'h1: out1[0] = RANDOM[11];
3'h2: out1[0] = RANDOM[12];
3'h3: out1[0] = RANDOM[13];
3'h4: out1[0] = RANDOM[14];
3'h5: out1[0] = RANDOM[15];
3'h6: out1[0] = RANDOM[16];
3'h7: out1[0] = RANDOM[17];
endcase
2'b1?: casez (in[4])
1'b1: casez (in[2:0])
3'h0: out1[0] = RANDOM[20];
3'h1: out1[0] = RANDOM[21];
3'h2: out1[0] = RANDOM[22];
3'h3: out1[0] = RANDOM[23];
3'h4: out1[0] = RANDOM[24];
3'h5: out1[0] = RANDOM[25];
3'h6: out1[0] = RANDOM[26];
3'h7: out1[0] = RANDOM[27];
endcase
1'b0: casez (in[2:0])
3'h0: out1[0] = RANDOM[30];
3'h1: out1[0] = RANDOM[31];
3'h2: out1[0] = RANDOM[32];
3'h3: out1[0] = RANDOM[33];
3'h4: out1[0] = RANDOM[34];
3'h5: out1[0] = RANDOM[35];
3'h6: out1[0] = RANDOM[36];
3'h7: out1[0] = RANDOM[37];
endcase
endcase
endcase
end
endmodule
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
# $Id$
# 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
# General Public License or the Perl Artistic License.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+93
View File
@@ -0,0 +1,93 @@
// $Id$
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2006 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc; initial cyc=0;
reg [63:0] crc;
reg [63:0] sum;
reg out1;
reg [4:0] out2;
sub sub (.in(crc[23:0]), .out1(out1), .out2(out2));
always @ (posedge clk) begin
//$write("[%0t] cyc==%0d crc=%x sum=%x out=%x,%x\n",$time, cyc, crc, sum, out1,out2);
cyc <= cyc + 1;
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
sum <= {sum[62:0], sum[63]^sum[2]^sum[0]} ^ {58'h0,out1,out2};
if (cyc==0) begin
// Setup
crc <= 64'h00000000_00000097;
sum <= 64'h0;
end
else if (cyc==90) begin
if (sum != 64'hf0afc2bfa78277c5) $stop;
end
else if (cyc==91) begin
end
else if (cyc==92) begin
end
else if (cyc==93) begin
end
else if (cyc==94) begin
end
else if (cyc==99) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module sub (/*AUTOARG*/
// Outputs
out1, out2,
// Inputs
in
);
input [23:0] in;
output reg out1;
output reg [4:0] out2;
always @* begin
casez (in)
24'b0000_0000_0000_0000_0000_0000 : {out1,out2} = {1'b0,5'h00};
24'b????_????_????_????_????_???1 : {out1,out2} = {1'b1,5'h00};
24'b????_????_????_????_????_??10 : {out1,out2} = {1'b1,5'h01};
24'b????_????_????_????_????_?100 : {out1,out2} = {1'b1,5'h02};
24'b????_????_????_????_????_1000 : {out1,out2} = {1'b1,5'h03};
24'b????_????_????_????_???1_0000 : {out1,out2} = {1'b1,5'h04};
24'b????_????_????_????_??10_0000 : {out1,out2} = {1'b1,5'h05};
24'b????_????_????_????_?100_0000 : {out1,out2} = {1'b1,5'h06};
24'b????_????_????_????_1000_0000 : {out1,out2} = {1'b1,5'h07};
// Same pattern, but reversed to test we work OK.
24'b1000_0000_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h17};
24'b?100_0000_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h16};
24'b??10_0000_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h15};
24'b???1_0000_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h14};
24'b????_1000_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h13};
24'b????_?100_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h12};
24'b????_??10_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h11};
24'b????_???1_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h10};
24'b????_????_1000_0000_0000_0000 : {out1,out2} = {1'b1,5'h0f};
24'b????_????_?100_0000_0000_0000 : {out1,out2} = {1'b1,5'h0e};
24'b????_????_??10_0000_0000_0000 : {out1,out2} = {1'b1,5'h0d};
24'b????_????_???1_0000_0000_0000 : {out1,out2} = {1'b1,5'h0c};
24'b????_????_????_1000_0000_0000 : {out1,out2} = {1'b1,5'h0b};
24'b????_????_????_?100_0000_0000 : {out1,out2} = {1'b1,5'h0a};
24'b????_????_????_??10_0000_0000 : {out1,out2} = {1'b1,5'h09};
24'b????_????_????_???1_0000_0000 : {out1,out2} = {1'b1,5'h08};
endcase
end
endmodule
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
# $Id$
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2006 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# General Public License or the Perl Artistic License.
$golden_out ||= "t/$Last_Self->{name}.out";
compile (
v_flags2 => [$Last_Self->{v3}?"--stats --O3 -x-assign 0":""],
);
execute (
check_finished=>1,
);
ok(files_identical("obj_dir/$Last_Self->{name}_logger.log", $golden_out));
1;
+44
View File
@@ -0,0 +1,44 @@
// $Id$
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2006 by Wilson Snyder.
`include "verilated.v"
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
reg [63:0] crc;
`verilator_file_descriptor fd;
t_case_write_tasks tasks ();
integer cyc; initial cyc=0;
always @ (posedge clk) begin
$fwrite(fd, "[%03d] ", cyc);
tasks.big_case(fd, crc[31:0]);
$fwrite(fd, "\n");
end
always @ (posedge clk) begin
//$write("[%0t] cyc==%0d crc=%x\n",$time, cyc, crc);
cyc <= cyc + 1;
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
if (cyc==1) begin
crc <= 64'h00000000_00000097;
$write("Open obj_dir/t_case_write_logger.log\n");
fd = $fopen("obj_dir/t_case_write_logger.log", "w");
end
if (cyc==90) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
File diff suppressed because it is too large Load Diff
+16 -1
View File
@@ -1,4 +1,4 @@
// $Id:$
// $Id$
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
@@ -22,6 +22,11 @@ module t;
if (global != 32'h17) $stop;
nop(32'h11);
global = 32'h00000001;
flipupperbit(global,4'd4);
flipupperbit(global,4'd12);
if (global !== 32'h10100001) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
@@ -70,4 +75,14 @@ module t;
end
endtask
task flipupperbit;
inout [31:0] vector;
input [3:0] bitnum;
reg [4:0] bitnum2;
begin
bitnum2 = {1'b1, bitnum}; // A little math to test constant propagation
vector[bitnum2] = vector[bitnum2] ^ 1'b1;
end
endtask
endmodule
+28 -2
View File
@@ -37,6 +37,11 @@ module t (/*AUTOARG*/
if (ma0.mb0.mc0.getP3(1'b0) !== 32'h0) $stop;
if (ma0.mb0.mc1.getP3(1'b0) !== 32'h1) $stop;
end
if (cyc==5) begin
ma0. checkName(ma0. getName(1'b0));
ma0.mb0. checkName(ma0.mb0. getName(1'b0));
ma0.mb0.mc0.checkName(ma0.mb0.mc0.getName(1'b0));
end
if (cyc==9) begin
$write("*-* All Finished *-*\n");
$finish;
@@ -72,7 +77,9 @@ module ma ();
`INLINE_MODULE
mb #(0) mb0 ();
reg [31:0] gName; initial gName = "ma ";
function [31:0] getName; input fake; getName = "ma "; endfunction
task checkName; input [31:0] name; if (name !== "ma ") $stop; endtask
initial begin
if (ma.getName(1'b0) !== "ma ") $stop;
@@ -89,13 +96,23 @@ module mb ();
mc #(P2,1) mc1 ();
global_mod #(32'hf33d) global_cell2 ();
reg [31:0] gName; initial gName = "mb ";
function [31:0] getName; input fake; getName = "mb "; endfunction
function [31:0] getP2 ; input fake; getP2 = P2; endfunction
task checkName; input [31:0] name; if (name !== "mb ") $stop; endtask
initial begin
if (ma.getName(1'b0) !== "ma ") $stop;
if (getName(1'b0) !== "mb ") $stop;
`ifndef verilator #1; `endif
if (ma. getName(1'b0) !== "ma ") $stop;
if ( getName(1'b0) !== "mb ") $stop;
if (mc1.getName(1'b0) !== "mc ") $stop;
ma. checkName (ma. gName);
/**/checkName ( gName);
mc1.checkName (mc1.gName);
ma. checkName (ma. getName(1'b0));
/**/checkName ( getName(1'b0));
mc1.checkName (mc1.getName(1'b0));
end
endmodule
@@ -104,12 +121,21 @@ module mc ();
parameter P2 = 0;
parameter P3 = 0;
reg [31:0] gName; initial gName = "mc ";
function [31:0] getName; input fake; getName = "mc "; endfunction
function [31:0] getP3 ; input fake; getP3 = P3; endfunction
task checkName; input [31:0] name; if (name !== "mc ") $stop; endtask
initial begin
`ifndef verilator #1; `endif
if (ma.getName(1'b0) !== "ma ") $stop;
if (mb.getName(1'b0) !== "mb ") $stop;
if (mc.getName(1'b0) !== "mc ") $stop;
ma.checkName (ma.gName);
mb.checkName (mb.gName);
mc.checkName (mc.gName);
ma.checkName (ma.getName(1'b0));
mb.checkName (mb.getName(1'b0));
mc.checkName (mc.getName(1'b0));
end
endmodule
+4 -4
View File
@@ -103,8 +103,8 @@ module tpub (
if (24'h11bca != got_long) $stop;
$c("{ uint64_t qq; publicGetQuad(qq); got_quad=qq; }");
if (60'haaaa_bbbb_cccc != got_quad) $stop;
//Unsupported: $c("publicGetWide(got_wide);");
//Unsupported: if (72'hac_abca_aaaa_bbbb_1234 != got_wide) $stop;
$c("{ WData gw[3]; publicGetWide(gw); VL_ASSIGN_W(72,got_wide,gw); }");
if (72'hac_abca_aaaa_bbbb_1234 != got_wide) $stop;
//Below doesn't work, because we're calling it inside the loop that sets var_flop
// if (12'h321 != var_flop) $stop;
end
@@ -154,7 +154,7 @@ module tpub (
endtask
task publicSetWide;
// Can't be public, as no wide return types in C++
// verilator public
input [71:0] in_wide;
var_wide = in_wide;
endtask
@@ -178,7 +178,7 @@ module tpub (
endtask
task publicGetWide;
// Can't be public, as no wide return types in C++
// verilator public
output [71:0] out_wide;
out_wide = var_wide;
endtask
+1 -2
View File
@@ -141,10 +141,9 @@ module mc (output reg [31:0] out);
end
// Can we look from the top module name down?
wire reach_up_clk = t.clk;
wire [31:0] reach_up_cyc = t.cyc;
always @ (posedge reach_up_clk) begin
always @ (posedge t.clk) begin
//$write("[%0t] %m: Got reachup, cyc=%0d\n", $time, reach_up_cyc);
if (reach_up_cyc==2) begin
if (global_cell.global != 32'hf00d) $stop;
+2 -1
View File
@@ -12,7 +12,8 @@ compile (
);
if ($Last_Self->{v3}) {
file_grep ($Last_Self->{stats}, qr/Optimizations, Lifetime assign deletions\s+3/i);
file_grep ($Last_Self->{stats}, qr/Optimizations, Lifetime assign deletions\s+4/i);
file_grep ($Last_Self->{stats}, qr/Optimizations, Lifetime constant prop\s+2/i);
}
execute (
+5 -3
View File
@@ -17,6 +17,8 @@ VERILATOR_ROOT := $(shell pwd)/..
export VERILATOR_ROOT
PWD := $(shell pwd)
PERL = perl
DEBUG_ON = --debug
######################################################################
@@ -32,11 +34,11 @@ obj_dir/sc_main.cpp: ../test_sp/sc_main.cpp
cp $^ $@
prep:
perl $(VERILATOR_ROOT)/bin/verilator $(VERILATOR_FLAGS)
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(VERILATOR_FLAGS)
prep_dbg:
perl $(VERILATOR_ROOT)/bin/verilator $(DEBUG_ON) $(VERILATOR_FLAGS)
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(DEBUG_ON) $(VERILATOR_FLAGS)
prep_dbg_np:
perl $(VERILATOR_ROOT)/bin/verilator $(DEBUG_ON) $(VERILATOR_FLAGS) --nopublic
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(DEBUG_ON) $(VERILATOR_FLAGS) --nopublic
preproc:
cd obj_dir ; $(MAKE) -j 1 -f ../Makefile_obj preproc
+5 -3
View File
@@ -17,6 +17,8 @@ VERILATOR_ROOT := $(shell pwd)/..
export VERILATOR_ROOT
PWD := $(shell pwd)
PERL = perl
DEBUG_ON = --debug --trace-dups --output-split 100
######################################################################
@@ -28,11 +30,11 @@ V_FLAGS = -f $(PWD)/../test_v/input.vc
VERILATOR_FLAGS = --public --sp --coverage --stats --trace $(V_FLAGS) top.v
prep:
perl $(VERILATOR_ROOT)/bin/verilator $(VERILATOR_FLAGS)
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(VERILATOR_FLAGS)
prep_dbg:
perl $(VERILATOR_ROOT)/bin/verilator $(DEBUG_ON) $(VERILATOR_FLAGS)
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(DEBUG_ON) $(VERILATOR_FLAGS)
prep_dbg_np:
perl $(VERILATOR_ROOT)/bin/verilator $(DEBUG_ON) $(VERILATOR_FLAGS) --nopublic
$(PERL) $(VERILATOR_ROOT)/bin/verilator $(DEBUG_ON) $(VERILATOR_FLAGS) --nopublic
preproc:
cd obj_dir ; $(MAKE) -j 1 -f ../Makefile_obj preproc
+27 -2
View File
@@ -54,6 +54,7 @@ our $Raise_Weight_Max = 50;
'VCONST'=> {weight=>1&&20, width=>0, sc=>1, terminal=>1, v=>'%v', },
'VIDNEW'=> {weight=>1&&10, width=>0, sc=>1, terminal=>0, v=>'%i', },
'VIDOLD'=> {weight=>1&&20, width=>0, sc=>1, terminal=>0, v=>'%i', },
'VIDSAME'=> {weight=>1&&20, width=>0, sc=>1, terminal=>0, v=>'%i', },
'VRANGE'=> {weight=>1&&30, width=>0, signed=>0,sc=>0, terminal=>0, v=>'%i[%2:%3]', },
'VBITSEL'=> {weight=>1&&10, width=>1, signed=>0,sc=>0, terminal=>0, v=>'%i[%2]', },
'VBITSELP'=> {weight=>1&&10, width=>0, signed=>0,sc=>0, terminal=>0, v=>'%i[%2+:%3]', },
@@ -119,7 +120,8 @@ my %ops2 =
'VCONST'=> {pl=>'', rnd=>'rnd_const(%tr);'},
'VIDNEW'=> {pl=>'%tv=$Vars{%i}{val};',
rnd=>'%i=next_id(%tw); $Vars{%i}=gen_leaf(width=>%tw,trunc=>1,signed=>%tg); id_commit(%tr,"%i");1;',},
'VIDOLD'=> {pl=>'%tv=$Vars{%i}{val};', rnd=>'%i=old_id(%tr);', ok_id_width=>1,},
'VIDOLD'=> {pl=>'%tv=$Vars{%i}{val};', rnd=>'%i=id_old(%tr);', ok_id_width=>1,},
'VIDSAME'=> {pl=>'%tv=$Vars{%i}{val};', rnd=>'%i=id_same(%tr);', ok_id_width=>1,},
'VRANGE'=> {pl=>'VRANGE(%tr,$Vars{%i}{val},%2v,%3v);', rnd=>'%i=next_id(%tw); my $lsb=rnd(128-%tw); my $msb=$lsb+%tw-1; %2r=val_leaf($msb); %3r=val_leaf($lsb); $Vars{%i}=gen_leaf(width=>($msb+1));'},
'VBITSEL'=> {pl=>'VRANGE(%tr,$Vars{%i}{val},%2v,%2v);', rnd=>'%i=next_id(%tw); my $wid=min(128,rnd_width()|3); %2r=gen_leaf(width=>(log2($wid)-1),signed=>0); $Vars{%i}=gen_leaf(width=>$wid);'},
'VBITSELP'=> {pl=>'VBITSELP(%tr,$Vars{%i}{val},%2v,%3v);', rnd=>'%i=next_id(%tw); my $wid=min(128,(%tw+rnd_width()|3)); %3r=val_leaf(%tw); my $maxval = $wid-%tw; %2r=(($maxval<4)?val_leaf($maxval):gen_leaf(width=>(log2($maxval)-1),signed=>0)); $Vars{%i}=gen_leaf(width=>$wid);'},
@@ -421,7 +423,7 @@ sub id_commit {
};
}
sub old_id {
sub id_old {
my $treeref = shift;
my $width = $treeref->{width};
my $signed = $treeref->{signed};
@@ -433,6 +435,29 @@ sub old_id {
return $id;
}
sub id_same {
my $treeref = shift;
my $width = $treeref->{width};
my $signed = $treeref->{signed};
my @possible;
foreach my $id (keys %VarsBlock) {
next if !$VarsBlock{$id}{used};
my $varref = $Vars{$id};
next if $varref->{signed} != $signed;
next if $varref->{width} != $width;
push @possible, $id;
}
my $n = $#possible + 1;
if ($n<1) { # Nothing, grab another!
return id_old($treeref,$width,$signed);
}
my $idn = rnd($n);
my $id = $possible[$idn];
$VarsBlock{$id}{used} = 1;
return $id;
}
sub write_output_v {
my $filename = shift;