mirror of
https://github.com/verilator/verilator.git
synced 2026-10-02 16:13:34 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3f17e7853 | ||
|
|
73c897ac69 | ||
|
|
a4db880809 | ||
|
|
f9697463cc | ||
|
|
f283076570 | ||
|
|
e15228498d | ||
|
|
53155b3a36 | ||
|
|
12ae70ba95 | ||
|
|
88809587f9 | ||
|
|
1b20481100 | ||
|
|
21eb939f37 | ||
|
|
0a765fbb54 | ||
|
|
749fdaae31 | ||
|
|
6f48185a1f | ||
|
|
7f1b16837e |
@@ -3,9 +3,23 @@ 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.60**
|
||||
* Verilator 3.610 09/20/2006
|
||||
|
||||
*** Changed how internal functions are invoked to avoid aliasing in GCC 3.3+.
|
||||
*** Verilator now works under DJGPP (Pentium GCC). [John Stroebel]
|
||||
|
||||
**** Add default define for VL_PRINTF. [John Stroebel]
|
||||
|
||||
**** Removed coverage request variable; see Coverage limitations in docs.
|
||||
|
||||
**** Fix DOS carrage returns in multiline defines. [Ralf Karge]
|
||||
|
||||
**** Fix printf format warnings on 64-bit linux.
|
||||
|
||||
* Verilator 3.602 09/11/2006 Stable
|
||||
|
||||
**** Fix function references under top inlined module. [David Hewson]
|
||||
|
||||
* Verilator 3.601 09/06/2006 Beta
|
||||
|
||||
*** Added --inhibit-sim flag for environments using old __Vm_inhibitSim.
|
||||
|
||||
@@ -13,13 +27,22 @@ indicates the contributor was also the author of the fix; Thanks!
|
||||
|
||||
*** Added -MP to make phony dependencies, ala GCC's.
|
||||
|
||||
**** Declare optimized lookup tables as 'static', to reduce D-Cache miss rate.
|
||||
*** Changed how internal functions are invoked to reduce aliasing.
|
||||
Useful when using GCC's -O2 or -fstrict-aliasing, to gain another ~4%.
|
||||
|
||||
**** Fix memory leak when destroying modules. [John Stroebel]
|
||||
|
||||
**** Fix coredump when unused modules have unused cells. [David Hewson]
|
||||
|
||||
**** Fix 3.600 internal error with arrayed instances. [David Hewson]
|
||||
|
||||
**** Fix 3.600 internal error with non-unrolled function loops. [David Hewson]
|
||||
|
||||
**** Fix $display %m name not matching Verilog name inside SystemC modules.
|
||||
|
||||
* Verilator 3.600 08/28/2006
|
||||
**** Declare optimized lookup tables as 'static', to reduce D-Cache miss rate.
|
||||
|
||||
* Verilator 3.600 08/28/2006 Beta
|
||||
|
||||
** Support dotted cross-hierarchy variable and task references.
|
||||
|
||||
|
||||
@@ -97,6 +97,7 @@ Performance:
|
||||
Track recirculation and convert into clock-enables
|
||||
Clock enables should become new clocking domains for speed
|
||||
If floped(a) & flopped(b) and no other a&b, then instead flop(a&b).
|
||||
Sort by output bitselects so can combine more assignments (see DDP example dx_dm signal)
|
||||
|
||||
//**********************************************************************
|
||||
//* Detailed notes on 'todo' features
|
||||
|
||||
+45
-12
@@ -248,9 +248,9 @@ Specifies basic block line coverage analysis code should be inserted.
|
||||
|
||||
Coverage analysis adds statements at each code flow change point, which are
|
||||
the branches of IF and CASE statements, a superset of normal Verilog Line
|
||||
Coverage. At each such branch a C++ macro is called, which SystemPerl uses
|
||||
to increment an array. At the end of a test, logs/coverage.pl is written
|
||||
with the data from the array.
|
||||
Coverage. At each such branch a unique counter is incremented. At the end
|
||||
of a test, the counters along with the filename and line number
|
||||
corresponding to each counter are written into logs/coverage.pl.
|
||||
|
||||
After running multiple tests, the vcoverage utility (from the SystemPerl
|
||||
package) is executed. Vcoverage reads the logs/coverage.pl file(s), and
|
||||
@@ -261,6 +261,10 @@ them, as it is assumed $stop branches contain an error check that should
|
||||
not occur. A /*verilator coverage_block_off*/ comment will perform a
|
||||
similar function on any code in that block or below.
|
||||
|
||||
Note Verilator may over-count combinatorial (non-clocked) blocks when those
|
||||
blocks receive signals which have had the UNOPTFLAT warning disabled; for
|
||||
most accurate results do not disable this warning when using coverage.
|
||||
|
||||
For an example, after running 'make test' in the Verilator distribution,
|
||||
see the test_sp/logs/coverage_source directory. Grep for lines starting
|
||||
with '%' to see what lines Verilator believes need more coverage.
|
||||
@@ -398,11 +402,14 @@ enable functional coverage.
|
||||
|
||||
=item --public
|
||||
|
||||
This is only for debug, and may result in mis-simulation of generated
|
||||
clocks.
|
||||
|
||||
Declares all signals and modules public. This will turn off signal
|
||||
optimizations as if all signals had a /*verilator public*/ comments. This
|
||||
will also turn off inlining as if all modules had a /*verilator
|
||||
public_module*/, unless the module specifically enabled it with /*verilator
|
||||
inline_module*/.
|
||||
optimizations as if all signals had a /*verilator public*/ comments and
|
||||
inlining. This will also turn off inlining as if all modules had a
|
||||
/*verilator public_module*/, unless the module specifically enabled it with
|
||||
/*verilator inline_module*/.
|
||||
|
||||
=item --sc
|
||||
|
||||
@@ -936,9 +943,9 @@ each different output width.
|
||||
|
||||
=item $display, $write, $fdisplay, $fwrite
|
||||
|
||||
$display format arguments may use C fprintf sizes after the % escape. Per
|
||||
the Verilog standard, %x prints a number with the natural width, %0x prints
|
||||
a number with minimum width, however %5x prints 5 digits per the C standard
|
||||
Format arguments may use C fprintf sizes after the % escape. Per the
|
||||
Verilog standard, %x prints a number with the natural width, %0x prints a
|
||||
number with minimum width, however %5x prints 5 digits per the C standard
|
||||
(it's unspecified in Verilog).
|
||||
|
||||
=item $fopen, $fclose, $fdisplay, $fwrite
|
||||
@@ -1057,7 +1064,7 @@ Re-enable waveform tracing for all future signals that are declared.
|
||||
|
||||
Used after a input, output, register, or wire declaration to indicate the
|
||||
signal should be declared so that C code may read or write the value
|
||||
of the signal. Set for all signals when using the --public switch.
|
||||
of the signal.
|
||||
|
||||
=item /*verilator public*/ (task/function)
|
||||
|
||||
@@ -1116,7 +1123,25 @@ always @* to prevent these issues.)
|
||||
|
||||
Verilator supports dotted references to variables, functions and tasks in
|
||||
different modules. However, references into named blocks and function-local
|
||||
variables are not supported.
|
||||
variables are not supported. References into arrayed and generated
|
||||
instances work, but still require some work-arounds in the Verilog code:
|
||||
|
||||
References into arrayed instances use different names from the Verilog
|
||||
standard; arrayed instances are named {cellName}__{instanceNumber}. For
|
||||
example a[2] is instead a__2. Thus you cannot use a parameter or variable
|
||||
to select the index number; expand it into a case statement manually.
|
||||
|
||||
References into generate statements also use different names from the
|
||||
Verilog standard; the top level generate, any begin statement, and any
|
||||
place where there is a implied begin statement (under each generate-if or
|
||||
generate-case) adds a hierarchy level named genblkI<instanceNumber>. And
|
||||
each generate-for adds genforI<loopCount>. The best bet is to comment out
|
||||
the references and run with --debug and look in the at the _begin.tree
|
||||
file, and see the hierarchy by looking at the names of all of the CELLs in
|
||||
question. Replace __DOT__ with . in your program. For example most cells
|
||||
under a for loop would be something like
|
||||
"genblk__DOT__genfor0__DOT__I<cellname>"; so use genblk.genfor0.I<cellname> to
|
||||
see inside that cell.
|
||||
|
||||
=head2 Latches
|
||||
|
||||
@@ -1230,6 +1255,11 @@ will give a width warning and wrap around the power-of-2 size. For
|
||||
non-power-of-2 sizes, it will return a unspecified constant of the
|
||||
appropriate width.
|
||||
|
||||
=item $display, $write, $fdisplay, $fwrite
|
||||
|
||||
$display and friends must have a constant format string as the first
|
||||
argument (as with C's printf), you cannot simply list variables standalone.
|
||||
|
||||
=head1 ERRORS
|
||||
|
||||
Warnings may be disabled in two ways. First, when the warning is
|
||||
@@ -1351,6 +1381,9 @@ For significantly better performance, split this into 2 separate signals:
|
||||
wire [2:1] x_21 = x[1:0];
|
||||
wire [0:0] x_0 = shift_in;
|
||||
|
||||
This warning may also be due to clock enables. To fix these, use the
|
||||
clock_enable meta comment described above.
|
||||
|
||||
=item UNSIGNED
|
||||
|
||||
Warns that you are comparing a unsigned value in a way that implies it is
|
||||
|
||||
+12
-5
@@ -40,11 +40,11 @@ using namespace std;
|
||||
//=========================================================================
|
||||
// Basic types
|
||||
|
||||
typedef uint8_t CData; ///< Verilated data, 1-8 bits
|
||||
typedef uint16_t SData; ///< Verilated data, 9-16 bits
|
||||
typedef uint32_t IData; ///< Verilated data, 17-32 bits
|
||||
typedef vluint64_t QData; ///< Verilated data, 33-64 bits
|
||||
typedef uint32_t WData; ///< Verilated data, >64 bits, as an array
|
||||
typedef vluint8_t CData; ///< Verilated data, 1-8 bits
|
||||
typedef vluint16_t SData; ///< Verilated data, 9-16 bits
|
||||
typedef vluint32_t IData; ///< Verilated data, 17-32 bits
|
||||
typedef vluint64_t QData; ///< Verilated data, 33-64 bits
|
||||
typedef vluint32_t WData; ///< Verilated data, >64 bits, as an array
|
||||
|
||||
typedef const WData* WDataInP; ///< Array input to a function
|
||||
typedef WData* WDataOutP; ///< Array output from a function
|
||||
@@ -115,6 +115,13 @@ public:
|
||||
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
// Functions overridable by user defines
|
||||
|
||||
#ifndef VL_PRINTF
|
||||
# define VL_PRINTF printf ///< Print ala printf; may redefine if desired
|
||||
#endif
|
||||
|
||||
//===========================================================================
|
||||
/// Verilator global static information class
|
||||
|
||||
|
||||
+20
-11
@@ -68,24 +68,33 @@
|
||||
#ifdef VL_UINTS_DEFINED
|
||||
#elif defined(__CYGWIN__)
|
||||
# include <stdint.h>
|
||||
typedef unsigned char uint8_t; ///< 8-bit basic type
|
||||
typedef unsigned short int uint16_t; ///< 16-bit basic type
|
||||
typedef unsigned long uint32_t; ///< 32-bit basic type
|
||||
typedef unsigned long long vluint64_t; ///< 64-bit basic type
|
||||
typedef unsigned char uint8_t; ///< 8-bit unsigned type (backward compatibility)
|
||||
typedef unsigned short int uint16_t; ///< 16-bit unsigned type (backward compatibility)
|
||||
typedef unsigned long uint32_t; ///< 32-bit unsigned type (backward compatibility)
|
||||
typedef unsigned char vluint8_t; ///< 8-bit unsigned type
|
||||
typedef unsigned short int vluint16_t; ///< 16-bit unsigned type
|
||||
typedef long vlsint32_t; ///< 32-bit signed type
|
||||
typedef unsigned long vluint32_t; ///< 32-bit unsigned type
|
||||
typedef long long vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
#elif defined(_WIN32)
|
||||
typedef unsigned char uint8_t; ///< 8-bit basic type
|
||||
typedef unsigned short int uint16_t; ///< 16-bit basic type
|
||||
typedef unsigned int uint32_t; ///< 32-bit basic type
|
||||
typedef unsigned __int64 vluint64_t; ///< 64-bit basic type
|
||||
typedef unsigned char uint8_t; ///< 8-bit unsigned type (backward compatibility)
|
||||
typedef unsigned short int uint16_t; ///< 16-bit unsigned type (backward compatibility)
|
||||
typedef unsigned long uint32_t; ///< 32-bit unsigned type (backward compatibility)
|
||||
typedef unsigned char vluint8_t; ///< 8-bit unsigned type
|
||||
typedef unsigned short int vluint16_t; ///< 16-bit unsigned type
|
||||
typedef int vlsint32_t; ///< 32-bit signed type
|
||||
typedef unsigned int vluint32_t; ///< 32-bit unsigned type
|
||||
typedef __int64 vlsint64_t; ///< 64-bit signed type
|
||||
#else // Linux or compliant Unix flavors
|
||||
typedef unsigned __int64 vluint64_t; ///< 64-bit unsigned type
|
||||
#else // Linux or compliant Unix flavors, -m64
|
||||
# include <stdint.h>
|
||||
typedef unsigned long long vluint64_t; ///< 64-bit basic type
|
||||
typedef long vlsint32_t; ///< 32-bit signed type
|
||||
typedef uint8_t vluint8_t; ///< 32-bit unsigned type
|
||||
typedef uint16_t vluint16_t; ///< 32-bit unsigned type
|
||||
typedef int vlsint32_t; ///< 32-bit signed type
|
||||
typedef uint32_t vluint32_t; ///< 32-bit signed type
|
||||
typedef long long vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
|
||||
+1
-1
@@ -88,7 +88,7 @@ private:
|
||||
bodysp = newFireAssert(nodep,message);
|
||||
// We assert the property is always true... so report when it fails
|
||||
// (Note this is opposite the behavior of coverage statements.)
|
||||
//FIX 'never' operator: not hold in current or any future cycle
|
||||
// Need: 'never' operator: not hold in current or any future cycle
|
||||
propp = new AstLogNot (nodep->fileline(), propp);
|
||||
} else {
|
||||
nodep->v3fatalSrc("Unknown node type");
|
||||
|
||||
+2
-2
@@ -33,8 +33,8 @@
|
||||
//======================================================================
|
||||
// Statics
|
||||
|
||||
uint64_t AstNode::s_editCntGbl=0;
|
||||
uint64_t AstNode::s_editCntLast=0;
|
||||
vluint64_t AstNode::s_editCntGbl=0;
|
||||
vluint64_t AstNode::s_editCntLast=0;
|
||||
|
||||
// To allow for fast clearing of all user pointers, we keep a "timestamp"
|
||||
// along with each userp, and thus by bumping this count we can make it look
|
||||
|
||||
+10
-10
@@ -391,9 +391,9 @@ private:
|
||||
static int s_cloneCntGbl; // Count of which userp is set
|
||||
|
||||
FileLine* m_fileline; // Where it was declared
|
||||
uint64_t m_editCount; // When it was last edited
|
||||
static uint64_t s_editCntGbl;// Global edit counter
|
||||
static uint64_t s_editCntLast;// Global edit counter, last value for printing * near node #s
|
||||
vluint64_t m_editCount; // When it was last edited
|
||||
static vluint64_t s_editCntGbl; // Global edit counter
|
||||
static vluint64_t s_editCntLast;// Global edit counter, last value for printing * near node #s
|
||||
|
||||
// Attributes
|
||||
bool m_signed; // Node is signed
|
||||
@@ -539,10 +539,10 @@ public:
|
||||
void user5(int val) { user5p(AstNUser::fromInt(val)); }
|
||||
static void user5ClearTree() { s_user5CntGbl++; } // Clear userp()'s across the entire tree
|
||||
|
||||
uint64_t editCount() const { return m_editCount; }
|
||||
vluint64_t editCount() const { return m_editCount; }
|
||||
void editCountInc() { m_editCount = s_editCntGbl++; }
|
||||
static uint64_t editCountLast() { return s_editCntLast; }
|
||||
static uint64_t editCountGbl() { return s_editCntGbl; }
|
||||
static vluint64_t editCountLast() { return s_editCntLast; }
|
||||
static vluint64_t editCountGbl() { return s_editCntGbl; }
|
||||
static void editCountSetLast() { s_editCntLast = editCountGbl(); }
|
||||
|
||||
// ACCESSORS for specific types
|
||||
@@ -774,14 +774,14 @@ struct AstNodeAssign : public AstNodeStmt {
|
||||
|
||||
struct AstNodeFor : public AstNodeStmt {
|
||||
AstNodeFor(FileLine* fileline, AstNode* initsp, AstNode* condp,
|
||||
AstNode* assignsp, AstNode* bodysp)
|
||||
AstNode* incsp, AstNode* bodysp)
|
||||
: AstNodeStmt(fileline) {
|
||||
addNOp1p(initsp); setOp2p(condp); addNOp3p(assignsp); addNOp4p(bodysp);
|
||||
addNOp1p(initsp); setOp2p(condp); addNOp3p(incsp); addNOp4p(bodysp);
|
||||
}
|
||||
virtual ~AstNodeFor() {}
|
||||
AstNode* initsp() const { return op1p()->castNode(); } // op1= initial statement
|
||||
AstNode* initsp() const { return op1p()->castNode(); } // op1= initial statements
|
||||
AstNode* condp() const { return op2p()->castNode(); } // op2= condition to continue
|
||||
AstNode* assignsp() const { return op3p()->castNode(); } // op3= final statements
|
||||
AstNode* incsp() const { return op3p()->castNode(); } // op3= increment statements
|
||||
AstNode* bodysp() const { return op4p()->castNode(); } // op4= body of loop
|
||||
virtual bool isGateOptimizable() const { return false; }
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
|
||||
+10
-9
@@ -650,17 +650,18 @@ public:
|
||||
virtual bool broken() const { return (m_modp && !m_modp->brokeExists()); }
|
||||
// ACCESSORS
|
||||
virtual string name() const { return m_name; } // * = Cell name
|
||||
void name(const string& name) { m_name = name; }
|
||||
string origName() const { return m_origName; } // * = Original name
|
||||
void origName(const string& name) { m_origName = name; }
|
||||
string modName() const { return m_modName; } // * = Instance name
|
||||
void modName(const string& name) { m_modName = name; }
|
||||
AstPin* pinsp() const { return op1p()->castPin(); } // op1 = List of cell ports
|
||||
AstPin* paramsp() const { return op2p()->castPin(); } // op2 = List of parameter #(##) values
|
||||
AstRange* rangep() const { return op3p()->castRange(); } // op3 = Range of arrayed instants (NULL=not ranged)
|
||||
AstModule* modp() const { return m_modp; } // [AfterLink] = Pointer to module instantiated
|
||||
void addPinsp(AstPin* pinp) { addOp1p(pinp); }
|
||||
void addParamsp(AstPin* pinp) { addOp2p(pinp); }
|
||||
void modp(AstModule* modp) { m_modp = modp; }
|
||||
void modName(const string& name) { m_modName = name; }
|
||||
void name(const string& name) { m_name = name; }
|
||||
void addPinsp(AstPin* nodep) { addOp1p(nodep); }
|
||||
void addParamsp(AstPin* nodep) { addOp2p(nodep); }
|
||||
void modp(AstModule* nodep) { m_modp = nodep; }
|
||||
};
|
||||
|
||||
struct AstCellInline : public AstNode {
|
||||
@@ -1241,8 +1242,8 @@ struct AstFOpen : public AstNodeStmt {
|
||||
|
||||
struct AstGenFor : public AstNodeFor {
|
||||
AstGenFor(FileLine* fileline, AstNode* initsp, AstNode* condp,
|
||||
AstNode* assignsp, AstNode* bodysp)
|
||||
: AstNodeFor(fileline, initsp, condp, assignsp, bodysp) {
|
||||
AstNode* incsp, AstNode* bodysp)
|
||||
: AstNodeFor(fileline, initsp, condp, incsp, bodysp) {
|
||||
}
|
||||
virtual ~AstGenFor() {}
|
||||
virtual AstType type() const { return AstType::GENFOR;}
|
||||
@@ -1252,8 +1253,8 @@ struct AstGenFor : public AstNodeFor {
|
||||
|
||||
struct AstFor : public AstNodeFor {
|
||||
AstFor(FileLine* fileline, AstNode* initsp, AstNode* condp,
|
||||
AstNode* assignsp, AstNode* bodysp)
|
||||
: AstNodeFor(fileline, initsp, condp, assignsp, bodysp) {
|
||||
AstNode* incsp, AstNode* bodysp)
|
||||
: AstNodeFor(fileline, initsp, condp, incsp, bodysp) {
|
||||
}
|
||||
virtual ~AstFor() {}
|
||||
virtual AstType type() const { return AstType::FOR;}
|
||||
|
||||
+18
-29
@@ -23,6 +23,7 @@
|
||||
// Each module:
|
||||
// Look for BEGINs
|
||||
// BEGIN(VAR...) -> VAR ... {renamed}
|
||||
// FOR -> WHILEs
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
@@ -48,25 +49,6 @@ private:
|
||||
string m_beginScope; // Name of begin blocks above us
|
||||
//int debug() { return 9; }
|
||||
|
||||
bool nameMatchesGen(const char* namep, string& numr) {
|
||||
numr = "";
|
||||
bool needbar = false;
|
||||
for (const char* cp=namep; *cp; ) {
|
||||
if (0==strncmp(cp,"genblk",6) || 0==strncmp(cp,"genfor",6)) {
|
||||
cp += 6;
|
||||
} else if (isdigit(*cp)) {
|
||||
if (needbar) { numr += '_'; needbar = false; }
|
||||
numr += *cp++;
|
||||
} else if (*cp=='_') {
|
||||
cp++;
|
||||
needbar = true;
|
||||
} else {
|
||||
return false; // Not exact match
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
m_modp = nodep;
|
||||
@@ -83,15 +65,6 @@ private:
|
||||
UINFO(8," "<<nodep<<endl);
|
||||
string oldScope = m_beginScope;
|
||||
{
|
||||
//string nameNum;
|
||||
//string oldNum;
|
||||
//if (nameMatchesGen(oldScope.c_str(), oldNum/*ref*/)
|
||||
// && nameMatchesGen(nodep->name().c_str(), nameNum/*ref*/)
|
||||
// && 0) { // Messes up V3Link
|
||||
// // Need to leave the dot or we mess up later V3LinkDot
|
||||
// // gen[blk|for]##_gen[blk|for]## -> gen[blk|for]##__DOT__##...
|
||||
// m_beginScope = oldScope + "__DOT__"+nameNum;
|
||||
|
||||
//UINFO(8,"nname "<<m_beginScope<<endl);
|
||||
// Create data for dotted variable resolution
|
||||
string dottedname = nodep->name() + "__DOT__"; // So always found
|
||||
@@ -99,7 +72,7 @@ private:
|
||||
while ((pos=dottedname.find("__DOT__")) != string::npos) {
|
||||
string ident = dottedname.substr(0,pos);
|
||||
dottedname = dottedname.substr(pos+strlen("__DOT__"));
|
||||
if (m_beginScope=="") m_beginScope = nodep->name();
|
||||
if (m_beginScope=="") m_beginScope = ident;
|
||||
else m_beginScope = m_beginScope + "__DOT__"+ident;
|
||||
// Create CellInline for dotted resolution
|
||||
AstCellInline* inlinep = new AstCellInline(nodep->fileline(),
|
||||
@@ -141,6 +114,22 @@ private:
|
||||
m_modp->addStmtp(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstFor* nodep, AstNUser*) {
|
||||
// So later optimizations don't need to deal with them,
|
||||
// FOR(init,cond,assign,body) -> init,WHILE(cond) { body, assign }
|
||||
AstNode* initsp = nodep->initsp(); if (initsp) initsp->unlinkFrBackWithNext();
|
||||
AstNode* condp = nodep->condp(); if (condp) condp->unlinkFrBackWithNext();
|
||||
AstNode* incsp = nodep->incsp(); if (incsp) incsp->unlinkFrBackWithNext();
|
||||
AstNode* bodysp = nodep->bodysp(); if (bodysp) bodysp->unlinkFrBackWithNext();
|
||||
bodysp = bodysp->addNext(incsp);
|
||||
AstNode* newp = new AstWhile(nodep->fileline(),
|
||||
condp,
|
||||
bodysp);
|
||||
initsp = initsp->addNext(newp);
|
||||
newp = initsp;
|
||||
nodep->replaceWith(newp);
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
+30
-2
@@ -87,6 +87,10 @@ private:
|
||||
return (nodep->castConst()
|
||||
&& !nodep->castConst()->num().isFourState());
|
||||
}
|
||||
bool operandIsPowTwo(AstNode* nodep) {
|
||||
if (!operandIsTwostate(nodep)) return false;
|
||||
return (1==nodep->castConst()->num().countOnes());
|
||||
}
|
||||
bool operandShiftOp(AstNodeBiop* nodep) {
|
||||
if (!nodep->rhsp()->castConst()) return false;
|
||||
AstNodeBiop* lhsp = nodep->lhsp()->castNodeBiop();
|
||||
@@ -317,6 +321,24 @@ private:
|
||||
newp->lhsp()->widthSignedFrom(nodep);
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
void replaceMulShift (AstMul* nodep) { // Mul, but not MulS as not simple shift
|
||||
UINFO(5,"MUL(2^n,b)->SHIFTL(b,n) "<<nodep<<endl);
|
||||
int amount = nodep->lhsp()->castConst()->num().mostSetBitP1()-1; // 2^n->n+1
|
||||
AstNode* opp = nodep->rhsp()->unlinkFrBack();
|
||||
AstShiftL* newp = new AstShiftL(nodep->fileline(),
|
||||
opp, new AstConst(nodep->fileline(), amount));
|
||||
newp->widthSignedFrom(nodep);
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
void replaceDivShift (AstDiv* nodep) { // Mul, but not MulS as not simple shift
|
||||
UINFO(5,"DIV(b,2^n)->SHIFTR(b,n) "<<nodep<<endl);
|
||||
int amount = nodep->rhsp()->castConst()->num().mostSetBitP1()-1; // 2^n->n+1
|
||||
AstNode* opp = nodep->lhsp()->unlinkFrBack();
|
||||
AstShiftR* newp = new AstShiftR(nodep->fileline(),
|
||||
opp, new AstConst(nodep->fileline(), amount));
|
||||
newp->widthSignedFrom(nodep);
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
void replaceShiftOp (AstNodeBiop* nodep) {
|
||||
UINFO(5,"SHIFT(AND(a,b),CONST)->AND(SHIFT(a,CONST),SHIFT(b,CONST)) "<<nodep<<endl);
|
||||
AstNRelinker handle;
|
||||
@@ -970,8 +992,14 @@ 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("AstPow {operandIsTwo($lhsp), $rhsp}","replacePowShift(nodep)"); // 2**a == 1<<a
|
||||
TREEOP("AstPowS {operandIsTwo($lhsp), $rhsp}","replacePowShift(nodep)"); // 2**a == 1<<a
|
||||
TREEOP("AstMul {$lhsp.isOne, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP("AstMulS {$lhsp.isOne, $rhsp}", "replaceWRhs(nodep)");
|
||||
TREEOP("AstDiv {$lhsp, $rhsp.isOne}", "replaceWLhs(nodep)");
|
||||
TREEOP("AstDivS {$lhsp, $rhsp.isOne}", "replaceWLhs(nodep)");
|
||||
TREEOP("AstMul {operandIsPowTwo($lhsp), $rhsp}", "replaceMulShift(nodep)"); // a*2^n -> a<<n
|
||||
TREEOP("AstDiv {$lhsp, operandIsPowTwo($rhsp)}", "replaceDivShift(nodep)"); // a/2^n -> a>>n
|
||||
TREEOP("AstPow {operandIsTwo($lhsp), $rhsp}", "replacePowShift(nodep)"); // 2**a == 1<<a
|
||||
TREEOP("AstPowS {operandIsTwo($lhsp), $rhsp}", "replacePowShift(nodep)"); // 2**a == 1<<a
|
||||
// Trinary ops
|
||||
// Note V3Case::Sel requires Cond to always be conditionally executed in C to prevent core dump!
|
||||
TREEOP("AstNodeCond{$condp.isZero, $expr1p, $expr2p}", "replaceWChild(nodep,$expr2p)");
|
||||
|
||||
+33
-9
@@ -34,6 +34,31 @@
|
||||
#include "V3Dead.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
//######################################################################
|
||||
|
||||
class DeadModVisitor : public AstNVisitor {
|
||||
// In a module that is dead, cleanup the in-use counts of the modules
|
||||
private:
|
||||
// NODE STATE
|
||||
// ** Shared with DeadVisitor **
|
||||
// VISITORS
|
||||
virtual void visit(AstCell* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->modp()->user(nodep->modp()->user() - 1);
|
||||
}
|
||||
//-----
|
||||
virtual void visit(AstNodeMath* nodep, AstNUser*) {} // Accelerate
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
DeadModVisitor(AstModule* nodep) {
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~DeadModVisitor() {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Dead state, as a visitor of each AstNode
|
||||
|
||||
@@ -46,8 +71,8 @@ private:
|
||||
// AstVarScope::user() -> int. Count of number of references
|
||||
|
||||
// STATE
|
||||
vector<AstVar*> m_varsp; // List of all encountered to avoid another loop through three
|
||||
vector<AstVarScope*> m_vscsp; // List of all encountered to avoid another loop through three
|
||||
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
|
||||
bool m_elimUserVars; // Allow removal of user's vars
|
||||
//int debug() { return 9; }
|
||||
|
||||
@@ -85,6 +110,8 @@ private:
|
||||
// METHODS
|
||||
void deadCheckMod() {
|
||||
// Kill any unused modules
|
||||
// V3LinkCells has a graph that is capable of this too, but we need to do it
|
||||
// after we've done all the generate blocks
|
||||
for (bool retry=true; retry; ) {
|
||||
retry=false;
|
||||
AstModule* nextmodp;
|
||||
@@ -93,14 +120,11 @@ private:
|
||||
if (modp->level()>2 && modp->user()==0) {
|
||||
// > 2 because L1 is the wrapper, L2 is the top user module
|
||||
UINFO(4," Dead module "<<modp<<endl);
|
||||
// And its children may now be killable too....
|
||||
for (AstNode* nodep = modp->stmtsp(); nodep; nodep=nodep->nextp()) {
|
||||
if (AstCell* cellp=nodep->castCell()) {
|
||||
cellp->modp()->user( cellp->modp()->user() - 1);
|
||||
retry = true;
|
||||
}
|
||||
}
|
||||
// And its children may now be killable too; correct counts
|
||||
// Recurse, as cells may not be directly under the module but in a generate
|
||||
DeadModVisitor visitor(modp);
|
||||
modp->unlinkFrBack()->deleteTree(); modp=NULL;
|
||||
retry = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
-9
@@ -217,8 +217,7 @@ public:
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstCoverInc* nodep, AstNUser*) {
|
||||
puts("if (VL_LIKELY(vlSymsp->__Vm_coverageRequest))");
|
||||
puts(" ++this->__Vcoverage[");
|
||||
puts("++this->__Vcoverage[");
|
||||
puts(cvtToStr(m_coverIds.remap(nodep->declp()))); puts("];\n");
|
||||
}
|
||||
virtual void visit(AstCReturn* nodep, AstNUser*) {
|
||||
@@ -910,7 +909,6 @@ string EmitCStmts::displayFormat(AstNode* widthNodep, string in,
|
||||
} else {
|
||||
fmt=in;
|
||||
}
|
||||
if (widthNodep->isQuad() && fmtLetter!='c' && fmtLetter!='s' && !reallyString) fmt+="ll";
|
||||
return fmt;
|
||||
}
|
||||
|
||||
@@ -941,10 +939,20 @@ void EmitCStmts::displayArg(AstDisplay* dispp, AstNode** elistp, string fmt, cha
|
||||
emitDispState.pushFormat(pfmt);
|
||||
emitDispState.pushArg(*elistp,func);
|
||||
} 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
|
||||
}
|
||||
if ((*elistp)->isQuad() && (fmtLetter=='u'||fmtLetter=='o'||fmtLetter=='x')) {
|
||||
nfmt+="ll";
|
||||
func="(unsigned long long)("; // Must match %ull to avoid warnings
|
||||
}
|
||||
string pfmt = "%"+nfmt+fmtLetter;
|
||||
|
||||
emitDispState.pushFormat(pfmt);
|
||||
emitDispState.pushArg(*elistp,"");
|
||||
emitDispState.pushArg(*elistp,func);
|
||||
}
|
||||
// Next parameter
|
||||
*elistp = (*elistp)->nextp();
|
||||
@@ -1246,12 +1254,8 @@ void EmitCImp::emitWrapEval(AstModule* modp) {
|
||||
puts("while (VL_LIKELY(__Vchange)) {\n");
|
||||
puts( "VL_DEBUG_IF(cout<<\" Clock loop\"<<endl;);\n");
|
||||
#endif
|
||||
// Not exactly correct for coverage. w/combo logic interspersed, this is complicated. Punt.
|
||||
// Perhaps have temp & each _combo_ turn it on or off
|
||||
if (v3Global.opt.coverage()) puts( "vlSymsp->__Vm_coverageRequest = true;\n");
|
||||
puts( "vlSymsp->__Vm_activity = true;\n");
|
||||
puts( "_eval(vlSymsp);\n");
|
||||
if (v3Global.opt.coverage()) puts( "vlSymsp->__Vm_coverageRequest = false;\n");
|
||||
#ifndef NEW_ORDERING
|
||||
puts( "__Vchange = _change_request(vlSymsp);\n");
|
||||
puts( "if (++__VclockLoop > 100) vl_fatal(__FILE__,__LINE__,__FILE__,\"Verilated model didn't converge\");\n");
|
||||
@@ -1284,7 +1288,7 @@ void EmitCImp::emitWrapEval(AstModule* modp) {
|
||||
|
||||
void EmitCStmts::emitVarList(AstNode* firstp, EisWhich which, const string& prefixIfImp) {
|
||||
// Put out a list of signal declarations
|
||||
// in order of 0:clocks, 1:uint8, 2:uint16, 4:uint32, 5:uint64, 6:wide, 7:arrays
|
||||
// in order of 0:clocks, 1:vluint8, 2:vluint16, 4:vluint32, 5:vluint64, 6:wide, 7:arrays
|
||||
// This aids cache packing and locality
|
||||
// Largest->smallest reduces the number of pad variables.
|
||||
// But for now, Smallest->largest makes it more likely a small offset will allow access to the signal.
|
||||
|
||||
+2
-7
@@ -124,18 +124,14 @@ void EmitCSyms::emitInt() {
|
||||
//puts("\n// STATIC STATE\n");
|
||||
|
||||
puts("\n// LOCAL STATE\n");
|
||||
ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(uint64_t));
|
||||
ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(vluint64_t));
|
||||
puts("const char* __Vm_namep;\n"); // Must be before subcells, as constructor order needed before _vlCoverInsert.
|
||||
ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(bool));
|
||||
puts("bool\t__Vm_activity;\t\t///< Used by trace routines to determine change occurred\n");
|
||||
ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(bool));
|
||||
puts("bool\t__Vm_didInit;\n");
|
||||
if (v3Global.opt.coverage()) {
|
||||
ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(bool));
|
||||
puts("bool __Vm_coverageRequest;\n");
|
||||
}
|
||||
|
||||
ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(uint64_t));
|
||||
ofp()->putAlign(V3OutFile::AL_AUTO, sizeof(vluint64_t));
|
||||
puts("\n// SUBCELL STATE\n");
|
||||
for (vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
|
||||
AstScope* scopep = it->first; AstModule* modp = it->second;
|
||||
@@ -184,7 +180,6 @@ void EmitCSyms::emitImp() {
|
||||
puts("\t: __Vm_namep(namep)\n"); // No leak, as we get destroyed when the top is destroyed
|
||||
puts("\t, __Vm_activity(false)\n");
|
||||
puts("\t, __Vm_didInit(false)\n");
|
||||
if (v3Global.opt.coverage()) puts("\t, __Vm_coverageRequest(false)\n");
|
||||
puts("\t// Setup submodule names\n");
|
||||
char comma=',';
|
||||
for (vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
|
||||
|
||||
+1
-1
@@ -199,7 +199,7 @@ public:
|
||||
puts(";");
|
||||
nodep->condp()->iterateAndNext(*this);
|
||||
puts(";");
|
||||
nodep->assignsp()->iterateAndNext(*this);
|
||||
nodep->incsp()->iterateAndNext(*this);
|
||||
m_suppressSemi = false;
|
||||
puts(") {\n");
|
||||
nodep->bodysp()->iterateAndNext(*this);
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ class GraphNfaToDfa : GraphAlg {
|
||||
private:
|
||||
// TYPES
|
||||
typedef deque<DfaVertex*> DfaStates;
|
||||
typedef multimap<uint64_t,DfaVertex*> HashMap;
|
||||
typedef multimap<vluint64_t,DfaVertex*> HashMap;
|
||||
|
||||
// MEMBERS
|
||||
uint32_t m_step; // Processing step, so we can avoid clearUser all the time
|
||||
|
||||
@@ -157,7 +157,11 @@ private:
|
||||
nodep->addNextHere(newp);
|
||||
// Remove ranging and fix name
|
||||
newp->rangep()->unlinkFrBack()->deleteTree();
|
||||
// Somewhat illogically, we need to rename the orignal name of the cell too.
|
||||
// as that is the name users expect for dotting
|
||||
// The spec says we add [x], but that won't work in C...
|
||||
newp->name(newp->name()+"__"+cvtToStr(m_instNum));
|
||||
newp->origName(newp->origName()+"__"+cvtToStr(m_instNum));
|
||||
// Fixup pins
|
||||
newp->pinsp()->iterateAndNext(*this);
|
||||
if (debug()==9) { newp->dumpTree(cout,"newcell: "); cout<<endl; }
|
||||
|
||||
+38
-25
@@ -68,12 +68,18 @@ public:
|
||||
void insertSubcellName(const string& name, LinkDotBaseVertex* toVertexp) {
|
||||
m_nameToVtxMap.insert(make_pair(name,toVertexp));
|
||||
}
|
||||
LinkDotBaseVertex* findSubcell(const string& name) {
|
||||
LinkDotBaseVertex* findSubcell(const string& name, const string& altname) {
|
||||
// Find a vertex under this one by name.
|
||||
// We could walk the edge top() list, but that would be O(n) for large lists of cells
|
||||
NameVtxMap::iterator iter = m_nameToVtxMap.find(name);
|
||||
if (iter == m_nameToVtxMap.end()) return NULL;
|
||||
else return iter->second;
|
||||
{
|
||||
NameVtxMap::iterator iter = m_nameToVtxMap.find(name);
|
||||
if (iter != m_nameToVtxMap.end()) return iter->second;
|
||||
}
|
||||
if (altname != "") {
|
||||
NameVtxMap::iterator iter = m_nameToVtxMap.find(altname);
|
||||
if (iter != m_nameToVtxMap.end()) return iter->second;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -134,18 +140,20 @@ private:
|
||||
// MEMBERS
|
||||
LinkDotGraph m_graph; // Graph of hiearchy
|
||||
NameScopeMap m_nameScopeMap; // Hash of scope referenced by textual name
|
||||
bool m_forPrearray; // Compress cell__[array] refs
|
||||
bool m_forScopeCreation; // Remove VarXRefs for V3Scope
|
||||
public:
|
||||
static int debug() { return V3Error::debugDefault(); }
|
||||
// static int debug() { return 9; }
|
||||
|
||||
// CONSTRUCTORS
|
||||
LinkDotState(bool forScopeCreation) {
|
||||
LinkDotState(bool forPrearray, bool forScopeCreation) {
|
||||
UINFO(4,__FUNCTION__<<": "<<endl);
|
||||
m_forPrearray = forPrearray;
|
||||
m_forScopeCreation = forScopeCreation;
|
||||
//VV***** We reset all userp() on each netlist!!!
|
||||
AstNode::userClearTree();
|
||||
AstNode::user2ClearTree();
|
||||
m_forScopeCreation = forScopeCreation;
|
||||
}
|
||||
~LinkDotState() {}
|
||||
|
||||
@@ -234,18 +242,26 @@ public:
|
||||
leftname = "";
|
||||
}
|
||||
baddot = ident; // So user can see where they botched it
|
||||
string altIdent = "";
|
||||
if (m_forPrearray) {
|
||||
// Cell foo__[array] before we've expanded arrays is just foo.
|
||||
if ((pos = ident.find("__")) != string::npos) {
|
||||
altIdent = ident.substr(0,pos);
|
||||
}
|
||||
}
|
||||
UINFO(8," id "<<ident<<" left "<<leftname<<" at "<<cellVxp<<endl);
|
||||
// Spec says; Look at exiting module (cellnames then modname),
|
||||
// then look up (inst name or modname)
|
||||
if (firstId) {
|
||||
// Check this module - subcellnames
|
||||
if (LinkDotBaseVertex* findVxp = cellVxp->findSubcell(ident)) {
|
||||
if (LinkDotBaseVertex* findVxp = cellVxp->findSubcell(ident, altIdent)) {
|
||||
cellVxp = findVxp;
|
||||
}
|
||||
// Check this module - cur modname
|
||||
else if (cellVxp->modName() == ident) {}
|
||||
// Check this module - cur cellname
|
||||
else if (cellVxp->cellName() == ident) {}
|
||||
else if (cellVxp->cellName() == altIdent) {}
|
||||
// Move up and check cellname + modname
|
||||
else {
|
||||
while (cellVxp) {
|
||||
@@ -253,10 +269,11 @@ public:
|
||||
if (cellVxp) {
|
||||
UINFO(9,"\t\tUp to "<<cellVxp<<endl);
|
||||
if (cellVxp->modName() == ident
|
||||
|| cellVxp->cellName() == ident) {
|
||||
|| cellVxp->cellName() == ident
|
||||
|| cellVxp->cellName() == altIdent) {
|
||||
break;
|
||||
}
|
||||
else if (LinkDotBaseVertex* findVxp = cellVxp->findSubcell(ident)) {
|
||||
else if (LinkDotBaseVertex* findVxp = cellVxp->findSubcell(ident, altIdent)) {
|
||||
cellVxp = findVxp;
|
||||
break;
|
||||
}
|
||||
@@ -265,7 +282,7 @@ public:
|
||||
if (!cellVxp) return NULL; // Not found
|
||||
}
|
||||
} else { // Searching for middle submodule, must be a cell name
|
||||
if (LinkDotBaseVertex* findVxp = cellVxp->findSubcell(ident)) {
|
||||
if (LinkDotBaseVertex* findVxp = cellVxp->findSubcell(ident, altIdent)) {
|
||||
cellVxp = findVxp;
|
||||
} else {
|
||||
return NULL; // Not found
|
||||
@@ -529,7 +546,8 @@ private:
|
||||
string baddot;
|
||||
LinkDotBaseVertex* dotVxp = m_cellVxp; // Start search at current scope
|
||||
if (nodep->inlinedDots()!="") { // Correct for current scope
|
||||
dotVxp = m_statep->findDotted(dotVxp, nodep->inlinedDots(), baddot);
|
||||
string inl = AstNode::prettyName(nodep->inlinedDots());
|
||||
dotVxp = m_statep->findDotted(dotVxp, inl, baddot);
|
||||
if (!dotVxp) nodep->v3fatalSrc("Couldn't resolve inlined scope '"<<baddot<<"' in: "<<nodep->inlinedDots());
|
||||
}
|
||||
dotVxp = m_statep->findDotted(dotVxp, nodep->dotted(), baddot); // Maybe NULL
|
||||
@@ -572,7 +590,9 @@ private:
|
||||
string baddot;
|
||||
LinkDotBaseVertex* dotVxp = m_cellVxp; // Start search at current scope
|
||||
if (nodep->inlinedDots()!="") { // Correct for current scope
|
||||
dotVxp = m_statep->findDotted(dotVxp, nodep->inlinedDots(), baddot);
|
||||
string inl = AstNode::prettyName(nodep->inlinedDots());
|
||||
UINFO(8,"\t\tInlined "<<inl<<endl);
|
||||
dotVxp = m_statep->findDotted(dotVxp, inl, baddot);
|
||||
if (!dotVxp) nodep->v3fatalSrc("Couldn't resolve inlined scope '"<<baddot<<"' in: "<<nodep->inlinedDots());
|
||||
}
|
||||
dotVxp = m_statep->findDotted(dotVxp, nodep->dotted(), baddot); // Maybe NULL
|
||||
@@ -606,22 +626,15 @@ public:
|
||||
//######################################################################
|
||||
// Link class functions
|
||||
|
||||
void V3LinkDot::linkDot(AstNetlist* rootp) {
|
||||
void V3LinkDot::linkDotGuts(AstNetlist* rootp, bool prearray, bool scoped) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
if (LinkDotState::debug()>=5) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot.tree"));
|
||||
LinkDotState state (false);
|
||||
LinkDotState state (prearray,scoped);
|
||||
LinkDotFindVisitor visitor(rootp,&state);
|
||||
state.dump();
|
||||
LinkDotResolveVisitor visitorb(rootp,&state);
|
||||
}
|
||||
|
||||
void V3LinkDot::linkDotScope(AstNetlist* rootp) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
if (LinkDotState::debug()>=5) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot.tree"));
|
||||
LinkDotState state (true);
|
||||
LinkDotFindVisitor visitor(rootp,&state);
|
||||
// Process AstScope's. This needs to be separate pass after whole hiearchy graph created.
|
||||
LinkDotScopeVisitor visitors(rootp,&state);
|
||||
if (scoped) {
|
||||
// Process AstScope's. This needs to be separate pass after whole hierarchy graph created.
|
||||
LinkDotScopeVisitor visitors(rootp,&state);
|
||||
}
|
||||
state.dump();
|
||||
LinkDotResolveVisitor visitorb(rootp,&state);
|
||||
}
|
||||
|
||||
+5
-2
@@ -28,9 +28,12 @@
|
||||
//============================================================================
|
||||
|
||||
class V3LinkDot {
|
||||
private:
|
||||
static void linkDotGuts(AstNetlist* nodep, bool preparam, bool scoped);
|
||||
public:
|
||||
static void linkDot(AstNetlist* nodep);
|
||||
static void linkDotScope(AstNetlist* nodep);
|
||||
static void linkDotPrearrayed(AstNetlist* nodep) { linkDotGuts(nodep,true,false); }
|
||||
static void linkDotArrayed(AstNetlist* nodep) { linkDotGuts(nodep,false,false); }
|
||||
static void linkDotScope(AstNetlist* nodep) { linkDotGuts(nodep,false,true); }
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+4
-4
@@ -62,7 +62,7 @@ private:
|
||||
// "this" must be a element inside of *basep
|
||||
// Use that to determine a structure offset, then apply to the new base
|
||||
// to get our new pointer information
|
||||
return (V3ListEnt*) ( ((uint8_t*)newbasep) + offset);
|
||||
return (V3ListEnt*) ( ((vluint8_t*)newbasep) + offset);
|
||||
}
|
||||
public:
|
||||
V3ListEnt()
|
||||
@@ -78,7 +78,7 @@ public:
|
||||
// METHODS
|
||||
void pushBack (V3List<T>& listr, T newp) {
|
||||
// "this" must be a element inside of *newp
|
||||
uint32_t offset = (uint8_t*)(this) - (uint8_t*)(newp);
|
||||
uint32_t offset = (vluint8_t*)(this) - (vluint8_t*)(newp);
|
||||
m_nextp = NULL;
|
||||
if (!listr.m_headp) listr.m_headp = newp;
|
||||
m_prevp = listr.m_tailp;
|
||||
@@ -87,7 +87,7 @@ public:
|
||||
}
|
||||
void pushFront (V3List<T>& listr, T newp) {
|
||||
// "this" must be a element inside of *newp
|
||||
uint32_t offset = (uint8_t*)(this) - (uint8_t*)(newp);
|
||||
uint32_t offset = (vluint8_t*)(this) - (vluint8_t*)(newp);
|
||||
m_nextp = listr.m_headp;
|
||||
if (m_nextp) baseToListEnt(m_nextp,offset)->m_prevp = newp;
|
||||
listr.m_headp = newp;
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
// Unlink from side
|
||||
void unlink (V3List<T>& listr, T oldp) {
|
||||
// "this" must be a element inside of *oldp
|
||||
uint32_t offset = (uint8_t*)(this) - (uint8_t*)(oldp);
|
||||
uint32_t offset = (vluint8_t*)(this) - (vluint8_t*)(oldp);
|
||||
if (m_nextp) baseToListEnt(m_nextp,offset)->m_prevp = m_prevp;
|
||||
else listr.m_tailp = m_prevp;
|
||||
if (m_prevp) baseToListEnt(m_prevp,offset)->m_nextp = m_nextp;
|
||||
|
||||
@@ -430,6 +430,12 @@ uint32_t V3Number::countOnes() const {
|
||||
return n;
|
||||
}
|
||||
|
||||
uint32_t V3Number::mostSetBitP1() const {
|
||||
for (int bit=this->width()-1; bit>=0; bit--) {
|
||||
if (bitIs1(bit)) return bit+1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//======================================================================
|
||||
|
||||
V3Number& V3Number::opBitsNonX (const V3Number& lhs) { // 0/1->1, X/Z->0
|
||||
|
||||
@@ -130,6 +130,7 @@ public:
|
||||
uint32_t asHash() const;
|
||||
uint32_t dataWord(int word) const;
|
||||
uint32_t countOnes() const;
|
||||
uint32_t mostSetBitP1() const; // Highest bit set plus one, IE for 16 return 5, for 0 return 0.
|
||||
|
||||
// STATICS
|
||||
static int log2b(uint32_t num);
|
||||
|
||||
+7
-3
@@ -127,10 +127,14 @@ private:
|
||||
nodep->iterateChildren(*this);
|
||||
// After expanding the generate, all statements under it can be moved
|
||||
// up, and the generate block deleted as it's not relevant
|
||||
AstNode* stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
|
||||
nodep->replaceWith(stmtsp);
|
||||
if (AstNode* stmtsp = nodep->stmtsp()) {
|
||||
stmtsp->unlinkFrBackWithNext();
|
||||
nodep->replaceWith(stmtsp);
|
||||
if (debug()>=9) stmtsp->dumpTree(cout,"-genout: ");
|
||||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
if (debug()>=9) stmtsp->dumpTree(cout,"-genout: ");
|
||||
}
|
||||
virtual void visit(AstGenIf* nodep, AstNUser*) {
|
||||
V3Width::widthParams(nodep); // Param typed widthing will NOT recurse the body
|
||||
|
||||
+24
-24
@@ -58,8 +58,9 @@ static void pslMoreNeeded(bool flag) { V3PreLex::s_currentLexp->m_pslMoreNeeded
|
||||
%x ARGMODE
|
||||
%x INCMODE
|
||||
|
||||
ws [ \t\r\f]
|
||||
newline [\n]
|
||||
ws [ \t\f\r]
|
||||
wsn [ \t\f]
|
||||
crnl [\r]*[\n]
|
||||
quote [\"]
|
||||
backslash [\\]
|
||||
symb [a-zA-Z_][a-zA-Z0-9_$]*
|
||||
@@ -68,7 +69,7 @@ psl [p]sl
|
||||
/**************************************************************/
|
||||
%%
|
||||
|
||||
<INITIAL>^{ws}*"`line"{ws}+.*{newline} { V3PreLex::s_currentLexp->lineDirective(yytext); }
|
||||
<INITIAL>^{ws}*"`line"{ws}+.*{crnl} { V3PreLex::s_currentLexp->lineDirective(yytext); }
|
||||
|
||||
/* Special directives we recognise */
|
||||
<INITIAL>"`include" { return(VP_INCLUDE); }
|
||||
@@ -95,7 +96,7 @@ psl [p]sl
|
||||
/* Pass-through strings */
|
||||
<INITIAL,PSLMULM,PSLONEM>{quote} { yy_push_state(STRMODE); yymore(); }
|
||||
<STRMODE><<EOF>> { linenoInc(); yyerror("EOF in unterminated string"); yyleng=0; yyterminate(); }
|
||||
<STRMODE>{newline} { linenoInc(); yyerror("Unterminated string"); BEGIN(INITIAL); }
|
||||
<STRMODE>{crnl} { linenoInc(); yyerror("Unterminated string"); BEGIN(INITIAL); }
|
||||
<STRMODE>[^\"\\] { yymore(); }
|
||||
<STRMODE>{backslash}. { yymore(); }
|
||||
<STRMODE>{quote} { yy_pop_state();
|
||||
@@ -104,28 +105,26 @@ psl [p]sl
|
||||
|
||||
/* Pass-through include <> filenames */
|
||||
<INCMODE><<EOF>> { linenoInc(); yyerror("EOF in unterminated include filename"); yyleng=0; yyterminate(); }
|
||||
<INCMODE>{newline} { linenoInc(); yyerror("Unterminated include filename"); BEGIN(INITIAL); }
|
||||
<INCMODE>{crnl} { linenoInc(); yyerror("Unterminated include filename"); BEGIN(INITIAL); }
|
||||
<INCMODE>[^\>\\] { yymore(); }
|
||||
<INCMODE>{backslash}. { yymore(); }
|
||||
<INCMODE>[\>] { yy_pop_state(); return (VP_STRING); }
|
||||
|
||||
/* Reading definition */
|
||||
<DEFMODE>"/*" { yy_push_state(CMTMODE); yymore(); }
|
||||
<DEFMODE>"//"[^\n]* { return (VP_COMMENT);}
|
||||
<DEFMODE>"//"[^\n\r]* { return (VP_COMMENT);}
|
||||
<DEFMODE><<EOF>> { linenoInc(); yyerror("EOF (missing return?) in define value"); yyleng=0; yyterminate(); }
|
||||
<DEFMODE>{newline} { linenoInc();
|
||||
yy_pop_state();
|
||||
return (VP_DEFVALUE); } /* Note contains a return */
|
||||
<DEFMODE>[^\/\*\n\m\\]+ |
|
||||
<DEFMODE>[\\][^\n] |
|
||||
<DEFMODE>{crnl} { linenoInc(); yy_pop_state(); yytext="\n"; yyleng=1; return (VP_DEFVALUE); }
|
||||
<DEFMODE>[\\]{crnl} { linenoInc(); appendDefValue("\n",1); } /* Include return so can maintain output line count */
|
||||
<DEFMODE>[^\/\*\n\r\\]+ |
|
||||
<DEFMODE>[\\][^\n\r] |
|
||||
<DEFMODE>. { appendDefValue(yytext,yyleng); }
|
||||
<DEFMODE>[\\]\n { linenoInc(); appendDefValue("\n",1); }
|
||||
|
||||
/* Define arguments */
|
||||
<ARGMODE>"/*" { yy_push_state(CMTMODE); yymore(); }
|
||||
<ARGMODE>"//"[^\n]* { return (VP_COMMENT);}
|
||||
<ARGMODE>"//"[^\n\r]* { return (VP_COMMENT);}
|
||||
<ARGMODE><<EOF>> { yyerror("EOF in define argument list\n"); yyleng = 0; yyterminate(); }
|
||||
<ARGMODE>{newline} { linenoInc(); yytext="\n"; yyleng=1; return(VP_WHITE); }
|
||||
<ARGMODE>{crnl} { linenoInc(); yytext="\n"; yyleng=1; return(VP_WHITE); }
|
||||
<ARGMODE>{quote} { yy_push_state(STRMODE); yymore(); }
|
||||
<ARGMODE>[(] { V3PreLex::s_currentLexp->m_parenLevel++; appendDefValue(yytext,yyleng); }
|
||||
<ARGMODE>[,)] { if (V3PreLex::s_currentLexp->m_parenLevel>1) {
|
||||
@@ -134,26 +133,26 @@ psl [p]sl
|
||||
} else {
|
||||
unput(yytext[0]); yy_pop_state(); return (VP_DEFARG);
|
||||
}}
|
||||
<ARGMODE>[^\/\*\n\m\\(,)\"]+ |
|
||||
<ARGMODE>[^\/\*\n\r\\(,)\"]+ |
|
||||
<ARGMODE>. { appendDefValue(yytext,yyleng); }
|
||||
|
||||
/* One line comments. */
|
||||
<INITIAL>"//"{ws}*{psl} { if (optPsl()) { pslMoreNeeded(true); yy_push_state(PSLONEM); return(VP_PSL); }
|
||||
else { yy_push_state(CMTONEM); yymore(); } }
|
||||
<INITIAL>"//"{newline} { linenoInc(); yytext="\n"; yyleng=1; return (VP_WHITE); }
|
||||
<INITIAL>"//"{ws}*{crnl} { linenoInc(); yytext="\n"; yyleng=1; return (VP_WHITE); }
|
||||
<INITIAL>"//" { if (pslMoreNeeded()) { pslMoreNeeded(true); yy_push_state(PSLONEM); return(VP_PSL); }
|
||||
else { yy_push_state(CMTONEM); yymore(); } }
|
||||
<CMTONEM>[^\n]* { yy_pop_state(); return (VP_COMMENT); }
|
||||
<CMTONEM>[^\n\r]* { yy_pop_state(); return (VP_COMMENT); }
|
||||
|
||||
/* Psl oneline comments */
|
||||
<PSLONEM>[{(] { pslParenLevelInc(); return (VP_TEXT); }
|
||||
<PSLONEM>[})] { pslParenLevelDec(); return (VP_TEXT); }
|
||||
<PSLONEM>[;] { if (!pslParenLevel()) {BEGIN PSLONEE; pslMoreNeeded(false);} return (VP_TEXT); }
|
||||
<PSLONEM><<EOF>> { yyerror("EOF in '/* ... */' psl comment\n"); yyleng=0; yyterminate(); }
|
||||
<PSLONEM>{newline} { linenoInc(); yy_pop_state(); return(VP_WHITE); }
|
||||
<PSLONEM>{crnl} { linenoInc(); yy_pop_state(); yytext="\n"; yyleng=1; return(VP_WHITE); }
|
||||
|
||||
/* Completed psl oneline comments */
|
||||
<PSLONEE>{newline} { linenoInc(); yy_pop_state(); return(VP_WHITE); }
|
||||
<PSLONEE>{crnl} { linenoInc(); yy_pop_state(); yytext="\n"; yyleng=1; return(VP_WHITE); }
|
||||
<PSLONEE>{ws}+ { yymore(); }
|
||||
<PSLONEE>. { yyerror("Unexpected text following psl assertion\n"); }
|
||||
|
||||
@@ -163,24 +162,25 @@ psl [p]sl
|
||||
<CMTBEGM>{psl} { yyleng -= 3; BEGIN PSLMUL1; return (VP_COMMENT); }
|
||||
<CMTBEGM>{ws}+ { yymore(); }
|
||||
<CMTBEGM,CMTMODE>"*/" { yy_pop_state(); return(VP_COMMENT); }
|
||||
<CMTBEGM,CMTMODE>{newline} { linenoInc(); yymore(); }
|
||||
<CMTBEGM,CMTMODE>{crnl} { linenoInc(); yymore(); }
|
||||
<CMTBEGM,CMTMODE><<EOF>> { yyerror("EOF in '/* ... */' block comment\n"); yyleng=0; yyterminate(); }
|
||||
<CMTBEGM>. { BEGIN CMTMODE; yymore(); } /* Non 'psl' beginning in comment */
|
||||
<CMTMODE>. { yymore(); }
|
||||
|
||||
/* Psl C-style comments. */
|
||||
<PSLMUL1>.|{newline} { yyless(0); BEGIN PSLMULM; return(VP_PSL); }
|
||||
<PSLMUL1>.|{crnl} { yyless(0); BEGIN PSLMULM; return(VP_PSL); }
|
||||
<PSLMULM>"*/" { yy_pop_state(); return(VP_COMMENT); }
|
||||
<PSLMULM>"//"[^\n]* { return (VP_COMMENT); } /* Comments inside block comments get literal inclusion (later removal) */
|
||||
<PSLMULM>"//"[^\n\r]* { return (VP_COMMENT); } /* Comments inside block comments get literal inclusion (later removal) */
|
||||
<PSLMULM><<EOF>> { yyerror("EOF in '/* ... */' psl comment\n"); yyleng=0; yyterminate(); }
|
||||
|
||||
/* Define calls */
|
||||
<INITIAL,PSLMULM,PSLONEM>"`"{symb} { return (VP_DEFREF); }
|
||||
|
||||
/* Generics */
|
||||
<INITIAL,PSLMULM>{newline} { linenoInc(); return(VP_WHITE); }
|
||||
<INITIAL,PSLMULM>{crnl} { linenoInc(); yytext="\n"; yyleng=1; return(VP_WHITE); }
|
||||
<INITIAL,PSLMULM,PSLONEM>{symb} { return (VP_SYMBOL); }
|
||||
<INITIAL,PSLMULM,PSLONEM>{ws}+ { return (VP_WHITE); }
|
||||
<INITIAL,PSLMULM,PSLONEM>[\r] { }
|
||||
<INITIAL,PSLMULM,PSLONEM>{wsn}+ { return (VP_WHITE); }
|
||||
<INITIAL,PSLMULM,PSLONEM>. { return (VP_TEXT); }
|
||||
%%
|
||||
|
||||
|
||||
+10
-8
@@ -537,10 +537,12 @@ int V3PreProcImp::getRawToken() {
|
||||
int tok = yylex();
|
||||
|
||||
if (debug()>4) {
|
||||
char buf[10000]; strncpy(buf, yytext, yyleng); buf[yyleng] = '\0';
|
||||
for (char* cp=buf; *cp; cp++) if (*cp=='\n') *cp='$';
|
||||
string buf = string (yytext, yyleng);
|
||||
string::size_type pos;
|
||||
while ((pos=buf.find("\n")) != string::npos) { buf.replace(pos, 1, "\\n"); }
|
||||
while ((pos=buf.find("\r")) != string::npos) { buf.replace(pos, 1, "\\r"); }
|
||||
fprintf (stderr, "%d: RAW %d %d: %-10s: %s\n",
|
||||
fileline()->lineno(), m_off, m_state, tokenName(tok), buf);
|
||||
fileline()->lineno(), m_off, m_state, tokenName(tok), buf.c_str());
|
||||
}
|
||||
|
||||
// On EOF, try to pop to upper level includes, as needed.
|
||||
@@ -867,12 +869,12 @@ string V3PreProcImp::getline() {
|
||||
while (NULL==(rtnp=strchr(m_lineChars.c_str(),'\n'))) {
|
||||
int tok = getToken();
|
||||
if (debug()>4) {
|
||||
char buf[100000];
|
||||
strncpy(buf, yytext, yyleng);
|
||||
buf[yyleng] = '\0';
|
||||
for (char* cp=buf; *cp; cp++) if (*cp=='\n') *cp='$';
|
||||
string buf = string (yytext, yyleng);
|
||||
string::size_type pos;
|
||||
while ((pos=buf.find("\n")) != string::npos) { buf.replace(pos, 1, "\\n"); }
|
||||
while ((pos=buf.find("\r")) != string::npos) { buf.replace(pos, 1, "\\r"); }
|
||||
fprintf (stderr,"%d: GETFETC: %-10s: %s\n",
|
||||
fileline()->lineno(), tokenName(tok), buf);
|
||||
fileline()->lineno(), tokenName(tok), buf.c_str());
|
||||
}
|
||||
if (tok==VP_EOF) {
|
||||
// Add a final newline, in case the user forgot the final \n.
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ public:
|
||||
~V3Double0() {}
|
||||
|
||||
// Implicit conversion operators:
|
||||
inline V3Double0 (const uint64_t v) : m_d(v) { };
|
||||
inline V3Double0 (const vluint64_t v) : m_d(v) { };
|
||||
inline operator const double () const { return m_d; };
|
||||
|
||||
// Explicit operators:
|
||||
|
||||
+92
-33
@@ -52,6 +52,7 @@ private:
|
||||
typedef std::map<pair<AstScope*,AstVar*>,AstVarScope*> VarToScopeMap;
|
||||
// MEMBERS
|
||||
VarToScopeMap m_varToScopeMap; // Map for Var -> VarScope mappings
|
||||
AstAssignW* m_assignwp; // Current assignment
|
||||
public:
|
||||
// METHODS
|
||||
AstScope* getScope(AstNodeFTask* nodep) {
|
||||
@@ -85,10 +86,25 @@ private:
|
||||
taskp->user3p(nodep);
|
||||
}
|
||||
}
|
||||
// No iterateChildren for speed
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep, AstNUser*) {
|
||||
m_assignwp = nodep;
|
||||
nodep->iterateChildren(*this); // May delete nodep.
|
||||
m_assignwp = NULL;
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
|
||||
if (m_assignwp) {
|
||||
// Wire assigns must become always statements to deal with insertion
|
||||
// of multiple statements. Perhaps someday make all wassigns into always's?
|
||||
UINFO(5," IM_WireRep "<<m_assignwp<<endl);
|
||||
AstNode* lhsp = m_assignwp->lhsp()->unlinkFrBack();
|
||||
AstNode* rhsp = m_assignwp->rhsp()->unlinkFrBack();
|
||||
AstNode* assignp = new AstAssign (m_assignwp->fileline(), lhsp, rhsp);
|
||||
AstNode* alwaysp = new AstAlways (m_assignwp->fileline(), NULL, assignp);
|
||||
m_assignwp->replaceWith(alwaysp); pushDeletep(m_assignwp); m_assignwp=NULL;
|
||||
}
|
||||
}
|
||||
//--------------------
|
||||
virtual void visit(AstNodeMath* nodep, AstNUser*) {} // Speedup
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
@@ -97,6 +113,7 @@ private:
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
TaskStateVisitor(AstNode* nodep) {
|
||||
m_assignwp = NULL;
|
||||
AstNode::user3ClearTree();
|
||||
nodep->iterateAndNext(*this, NULL);
|
||||
}
|
||||
@@ -148,11 +165,20 @@ private:
|
||||
// AstNodeFTask::user // True if its been expanded
|
||||
// Each funccall
|
||||
// AstVar::user2p // AstVarScope* to replace varref with
|
||||
|
||||
// TYPES
|
||||
enum InsertMode {
|
||||
IM_BEFORE, // Pointing at statement ref is in, insert before this
|
||||
IM_AFTER, // Pointing at last inserted stmt, insert after
|
||||
IM_WHILE_PRECOND // Pointing to for loop, add to body end
|
||||
};
|
||||
|
||||
// STATE
|
||||
TaskStateVisitor* m_statep; // Common state between visitors
|
||||
AstModule* m_modp; // Current module
|
||||
AstScope* m_scopep; // Current scope
|
||||
AstNode* m_lastStmtp; // Proceeding statement
|
||||
InsertMode m_insMode; // How to insert
|
||||
AstNode* m_insStmtp; // Where to insert statement
|
||||
int m_modNCalls; // Incrementing func # for making symbols
|
||||
//int debug() { return 9; }
|
||||
|
||||
@@ -344,18 +370,46 @@ private:
|
||||
nodep->accept(*this);
|
||||
m_scopep = oldscopep;
|
||||
}
|
||||
void insertBeforeStmt(AstNode* nodep, AstNode* newp) {
|
||||
if (debug()>=9) { nodep->dumpTree(cout,"-newstmt:"); }
|
||||
if (!m_insStmtp) nodep->v3fatalSrc("Function not underneath a statement");
|
||||
if (m_insMode == IM_BEFORE) {
|
||||
// Add the whole thing before insertAt
|
||||
UINFO(5," IM_Before "<<m_insStmtp<<endl);
|
||||
AstNRelinker handle;
|
||||
m_insStmtp->unlinkFrBackWithNext(&handle);
|
||||
if (debug()>=9) { newp->dumpTree(cout,"-newfunc:"); }
|
||||
newp->addNext(m_insStmtp);
|
||||
handle.relink(newp);
|
||||
}
|
||||
else if (m_insMode == IM_AFTER) {
|
||||
UINFO(5," IM_After "<<m_insStmtp);
|
||||
m_insStmtp->addNextHere(newp);
|
||||
}
|
||||
else if (m_insMode == IM_WHILE_PRECOND) {
|
||||
UINFO(5," IM_While_Precond "<<m_insStmtp);
|
||||
AstWhile* whilep = m_insStmtp->castWhile();
|
||||
if (!whilep) nodep->v3fatalSrc("Insert should be under WHILE");
|
||||
whilep->addPrecondsp(newp);
|
||||
}
|
||||
else {
|
||||
nodep->v3fatalSrc("Unknown InsertMode");
|
||||
}
|
||||
m_insMode = IM_AFTER;
|
||||
m_insStmtp = newp;
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
m_modp = nodep;
|
||||
m_lastStmtp = NULL;
|
||||
m_insStmtp = NULL;
|
||||
m_modNCalls = 0;
|
||||
nodep->iterateChildren(*this);
|
||||
m_modp = NULL;
|
||||
}
|
||||
virtual void visit(AstScope* nodep, AstNUser*) {
|
||||
m_scopep = nodep;
|
||||
m_lastStmtp = NULL;
|
||||
m_insStmtp = NULL;
|
||||
nodep->iterateChildren(*this);
|
||||
m_scopep = NULL;
|
||||
}
|
||||
@@ -372,27 +426,12 @@ private:
|
||||
}
|
||||
virtual void visit(AstFuncRef* nodep, AstNUser*) {
|
||||
UINFO(4," Func REF "<<nodep<<endl);
|
||||
if (debug()>=9) { m_lastStmtp->dumpTree(cout,"-prestmt:"); }
|
||||
if (debug()>=9) { nodep->dumpTree(cout,"-preref:"); }
|
||||
// First, do hierarchical funcs
|
||||
AstFunc* funcp = nodep->taskp()->castFunc();
|
||||
if (!funcp) nodep->v3fatalSrc("unlinked");
|
||||
AstNode* insertAtp = m_lastStmtp;
|
||||
if (AstAssignW* awp = insertAtp->castAssignW()) {
|
||||
// Wire assigns must become always statements to deal with insertion
|
||||
// of multiple statements. Perhaps someday make all wassigns into always's?
|
||||
AstNode* lhsp = awp->lhsp()->unlinkFrBack();
|
||||
AstNode* rhsp = awp->rhsp()->unlinkFrBack();
|
||||
AstNode* assignp = new AstAssign (awp->fileline(), lhsp, rhsp);
|
||||
AstNode* alwaysp = new AstAlways (awp->fileline(), NULL, assignp);
|
||||
m_lastStmtp = assignp; insertAtp = assignp;
|
||||
awp->replaceWith(alwaysp); pushDeletep(awp); awp=NULL;
|
||||
}
|
||||
// Inline func refs in the function
|
||||
iterateIntoFTask(funcp);
|
||||
// Inline this reference
|
||||
if (debug()>=9) { m_lastStmtp->dumpTree(cout,"-inlstmt:"); }
|
||||
if (!insertAtp) nodep->v3fatalSrc("Function not underneath a statement");
|
||||
UINFO(5," Under "<<insertAtp<<endl);
|
||||
// Create output variabls
|
||||
string namePrefix = "__Vfunc_"+funcp->shortName()+"__"+cvtToStr(m_modNCalls++);
|
||||
AstVarScope* outvscp = createVarScope (funcp->fvarp()->castVar(),
|
||||
@@ -402,22 +441,20 @@ private:
|
||||
if (!nodep->taskp()) nodep->v3fatalSrc("Unlinked?");
|
||||
|
||||
AstNode* beginp = createInlinedFTask(nodep, namePrefix, outvscp);
|
||||
// Add the whole thing before insertAt
|
||||
AstNRelinker handle;
|
||||
insertAtp->unlinkFrBackWithNext(&handle);
|
||||
if (debug()>=9) { beginp->dumpTree(cout,"-newfunc:"); }
|
||||
beginp->addNext(insertAtp);
|
||||
handle.relink(beginp);
|
||||
// Replace the ref
|
||||
AstVarRef* outrefp = new AstVarRef (nodep->fileline(), outvscp, false);
|
||||
nodep->replaceWith(outrefp);
|
||||
// Insert new statements
|
||||
insertBeforeStmt(nodep, beginp);
|
||||
// Cleanup
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
if (debug()>=9) { insertAtp->dumpTree(cout,"-newstmt:"); }
|
||||
UINFO(4," Done.\n");
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
||||
AstNode* prevLastStmtp = m_lastStmtp;
|
||||
m_lastStmtp = nodep->stmtsp();
|
||||
InsertMode prevInsMode = m_insMode;
|
||||
AstNode* prevInsStmtp = m_insStmtp;
|
||||
m_insMode = IM_BEFORE;
|
||||
m_insStmtp = nodep->stmtsp(); // Might be null if no statements, but we won't use it
|
||||
if (!nodep->user()) {
|
||||
// Expand functions in it & Mark for later delete
|
||||
nodep->user(true);
|
||||
@@ -452,11 +489,32 @@ private:
|
||||
// Just push, as other references to func may remain until visitor exits
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
m_lastStmtp = prevLastStmtp;
|
||||
m_insMode = prevInsMode;
|
||||
m_insStmtp = prevInsStmtp;
|
||||
}
|
||||
virtual void visit(AstWhile* nodep, AstNUser*) {
|
||||
// Special, as statements need to be put in different places
|
||||
// Preconditions insert first just before themselves (the normal rule for other statement types)
|
||||
m_insStmtp = NULL; // First thing should be new statement
|
||||
nodep->precondsp()->iterateAndNext(*this);
|
||||
// Conditions insert first at end of precondsp.
|
||||
m_insMode = IM_WHILE_PRECOND;
|
||||
m_insStmtp = nodep;
|
||||
nodep->condp()->iterateAndNext(*this);
|
||||
// Body insert just before themselves
|
||||
m_insStmtp = NULL; // First thing should be new statement
|
||||
nodep->bodysp()->iterateAndNext(*this);
|
||||
// Done the loop
|
||||
m_insStmtp = NULL; // Next thing should be new statement
|
||||
}
|
||||
virtual void visit(AstNodeFor* nodep, AstNUser*) {
|
||||
nodep->v3fatalSrc("For statements should have been converted to while statements in V3Begin.cpp\n");
|
||||
}
|
||||
virtual void visit(AstNodeStmt* nodep, AstNUser*) {
|
||||
m_lastStmtp = nodep;
|
||||
m_insMode = IM_BEFORE;
|
||||
m_insStmtp = nodep;
|
||||
nodep->iterateChildren(*this);
|
||||
m_insStmtp = NULL; // Next thing should be new statement
|
||||
}
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
@@ -470,6 +528,7 @@ public:
|
||||
: m_statep(statep) {
|
||||
m_modp = NULL;
|
||||
m_scopep = NULL;
|
||||
m_insStmtp = NULL;
|
||||
AstNode::userClearTree();
|
||||
nodep->accept(*this);
|
||||
}
|
||||
|
||||
+140
-80
@@ -50,6 +50,7 @@ private:
|
||||
AstVar* m_forVarp; // Iterator variable
|
||||
AstVarScope* m_forVscp; // Iterator variable scope (NULL for generate pass)
|
||||
AstConst* m_varValuep; // Current value of loop
|
||||
AstNode* m_ignoreIncp; // Increment node to ignore
|
||||
bool m_varModeCheck; // Just checking RHS assignments
|
||||
bool m_varModeReplace; // Replacing varrefs
|
||||
bool m_varAssignHit; // Assign var hit
|
||||
@@ -66,7 +67,7 @@ private:
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
bool cantUnroll(AstNodeFor* nodep, const char* reason) {
|
||||
bool cantUnroll(AstNode* nodep, const char* reason) {
|
||||
if (m_generate) {
|
||||
nodep->v3error("Unsupported: Can't unroll generate for; "<<reason);
|
||||
}
|
||||
@@ -75,36 +76,44 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool forUnrollCheck(AstNodeFor* nodep) {
|
||||
// Do only the body; ignore the loop variable as a dependency.
|
||||
// Return if we did the replacement or not
|
||||
if (m_varModeCheck || m_varModeReplace) return false;
|
||||
// See if we can make it simple enough to process
|
||||
if (nodep->initsp()) V3Const::constifyTree(nodep->initsp()); // May change what is under init, leave here
|
||||
V3Const::constifyTree(nodep->condp());
|
||||
if (nodep->assignsp()) V3Const::constifyTree(nodep->assignsp());
|
||||
|
||||
AstAssign* initp = nodep->initsp()->castAssign();
|
||||
if (!initp) nodep->v3fatalSrc("no initial assignment");
|
||||
m_forVarp = initp->lhsp()->castVarRef()->varp();
|
||||
m_forVscp = initp->lhsp()->castVarRef()->varScopep();
|
||||
bool forUnrollCheck(AstNode* nodep,
|
||||
AstNode* initp, // Maybe under nodep (no nextp), or standalone (ignore nextp)
|
||||
AstNode* precondsp, AstNode* condp,
|
||||
AstNode* incp, // Maybe under nodep or in bodysp
|
||||
AstNode* bodysp) {
|
||||
// To keep the IF levels low, we return as each test fails.
|
||||
UINFO(4, " FOR Check "<<nodep<<endl);
|
||||
if (initp) UINFO(6, " Init "<<initp<<endl);
|
||||
if (precondsp) UINFO(6, " Pcon "<<precondsp<<endl);
|
||||
if (condp) UINFO(6, " Cond "<<condp<<endl);
|
||||
if (incp) UINFO(6, " Inc "<<incp<<endl);
|
||||
// Initial value check
|
||||
AstAssign* initAssp = initp->castAssign();
|
||||
if (!initAssp) return cantUnroll(nodep, "no initial assignment");
|
||||
if (initp->nextp() && initp->nextp()!=nodep) nodep->v3fatalSrc("initial assignment shouldn't be a list");
|
||||
m_forVarp = initAssp->lhsp()->castVarRef()->varp();
|
||||
m_forVscp = initAssp->lhsp()->castVarRef()->varScopep();
|
||||
if (nodep->castGenFor() && !m_forVarp->isGenVar()) {
|
||||
nodep->v3error("Non-genvar used in generate for: "<<m_forVarp->name()<<endl);
|
||||
}
|
||||
AstNodeBiop* condp = nodep->condp()->castNodeBiop();
|
||||
AstAssign* assignp = nodep->assignsp()->castAssign();
|
||||
AstNodeBiop* incInstrp = assignp->rhsp()->castNodeBiop();
|
||||
if (!assignp) nodep->v3fatalSrc("no increment assignment");
|
||||
UINFO(4, " FOR Check "<<nodep<<endl);
|
||||
if (m_generate) V3Const::constifyParam(initAssp->rhsp());
|
||||
AstConst* constInitp = initAssp->rhsp()->castConst();
|
||||
if (!constInitp) return cantUnroll(nodep, "non-constant initializer");
|
||||
//
|
||||
// Condition check
|
||||
if (condp->nextp()) nodep->v3fatalSrc("conditional shouldn't be a list");
|
||||
//
|
||||
// Assignment of next value check
|
||||
AstAssign* incAssp = incp->castAssign();
|
||||
if (!incAssp) return cantUnroll(nodep, "no increment assignment");
|
||||
if (incAssp->nextp()) nodep->v3fatalSrc("increment shouldn't be a list");
|
||||
AstNodeBiop* incInstrp = incAssp->rhsp()->castNodeBiop();
|
||||
//
|
||||
if (m_forVscp) { UINFO(8, " Loop Variable: "<<m_forVscp<<endl); }
|
||||
else { UINFO(8, " Loop Variable: "<<m_forVarp<<endl); }
|
||||
if (debug()>=9) nodep->dumpTree(cout," for: ");
|
||||
if (debug()>=9) nodep->dumpTree(cout,"- for: ");
|
||||
//
|
||||
// Extract the constant loop bounds
|
||||
// To keep the IF levels low, we return as each test fails.
|
||||
if (m_generate) V3Const::constifyParam(initp->rhsp());
|
||||
AstConst* constInitp = initp->rhsp()->castConst();
|
||||
if (!constInitp) return cantUnroll(nodep, "non-constant initializer");
|
||||
bool subtract = incInstrp->castSub();
|
||||
{
|
||||
if (!subtract && !incInstrp->castAdd()) return cantUnroll(nodep, "missing add/sub for incrementer");
|
||||
@@ -134,13 +143,14 @@ private:
|
||||
bool gte = condp->castGte() || condp->castGteS();
|
||||
if (!lt && !lte && !gt && !gte)
|
||||
return cantUnroll(nodep, "condition not <= or <");
|
||||
if (!condp->lhsp()->castVarRef())
|
||||
AstNodeBiop* condBip = condp->castNodeBiop();
|
||||
if (!condBip->lhsp()->castVarRef())
|
||||
return cantUnroll(nodep, "no variable on lhs of condition");
|
||||
if (condp->lhsp()->castVarRef()->varp() != m_forVarp
|
||||
|| condp->lhsp()->castVarRef()->varScopep() != m_forVscp)
|
||||
if (condBip->lhsp()->castVarRef()->varp() != m_forVarp
|
||||
|| condBip->lhsp()->castVarRef()->varScopep() != m_forVscp)
|
||||
return cantUnroll(nodep, "different variable in condition");
|
||||
if (m_generate) V3Const::constifyParam(condp->rhsp());
|
||||
AstConst* constStopp = condp->rhsp()->castConst();
|
||||
if (m_generate) V3Const::constifyParam(condBip->rhsp());
|
||||
AstConst* constStopp = condBip->rhsp()->castConst();
|
||||
if (!constStopp) return cantUnroll(nodep, "non-constant final value");
|
||||
UINFO(8, " Stop expr ok: "<<constStopp<<endl);
|
||||
//
|
||||
@@ -162,7 +172,10 @@ private:
|
||||
|
||||
// Less then 10 statements in the body?
|
||||
int bodySize = 0;
|
||||
for (AstNode* bodp = nodep->bodysp(); bodp; bodp=bodp->nextp()) {
|
||||
for (AstNode* bodp = precondsp; bodp; bodp=bodp->nextp()) {
|
||||
bodySize++;
|
||||
}
|
||||
for (AstNode* bodp = bodysp; bodp; bodp=bodp->nextp()) {
|
||||
bodySize++;
|
||||
}
|
||||
if (bodySize > v3Global.opt.unrollStmts())
|
||||
@@ -172,30 +185,52 @@ private:
|
||||
// Now, make sure there's no assignment to this variable in the loop
|
||||
m_varModeCheck = true;
|
||||
m_varAssignHit = false;
|
||||
nodep->bodysp()->iterateAndNext(*this);
|
||||
m_ignoreIncp = incp;
|
||||
precondsp->iterateAndNext(*this);
|
||||
bodysp->iterateAndNext(*this);
|
||||
m_varModeCheck = false;
|
||||
m_ignoreIncp = NULL;
|
||||
if (m_varAssignHit) return cantUnroll(nodep, "genvar assigned *inside* loop");
|
||||
//
|
||||
// Finally, we can do it
|
||||
forUnroller(nodep, constInitp->num(),
|
||||
condp, constStopp->num(),
|
||||
forUnroller(nodep, initp, precondsp, condp, incp, bodysp,
|
||||
constInitp->num(),
|
||||
condBip, constStopp->num(),
|
||||
incInstrp, constIncp->num()); nodep = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
void forUnroller(AstNodeFor* nodep, const V3Number& numInit,
|
||||
void forUnroller(AstNode* nodep,
|
||||
AstNode* initp,
|
||||
AstNode* precondsp, AstNode* condp,
|
||||
AstNode* incp, AstNode* bodysp,
|
||||
const V3Number& numInit,
|
||||
AstNodeBiop* cmpInstrp, const V3Number& numStop,
|
||||
AstNodeBiop* incInstrp, const V3Number& numInc) {
|
||||
UINFO(4, " Unroll for var="<<numInit<<"; var<"<<numStop<<"; var+="<<numInc<<endl);
|
||||
AstNode* bodysp = nodep->bodysp(); // Maybe null if no body
|
||||
if (bodysp) bodysp->unlinkFrBackWithNext();
|
||||
|
||||
AstNode* newbodysp = NULL;
|
||||
UINFO(6, " cmpI "<<cmpInstrp<<endl);
|
||||
UINFO(6, " IncI "<<incInstrp<<endl);
|
||||
AstNode* stmtsp = NULL;
|
||||
if (initp) {
|
||||
initp->unlinkFrBack(); // Always a single statement; nextp() may be nodep
|
||||
// Don't add to list, we do it once, and setting loop index isn't needed as we're constant propagating it
|
||||
}
|
||||
if (precondsp) {
|
||||
precondsp->unlinkFrBackWithNext();
|
||||
stmtsp = stmtsp->addNextNull(precondsp);
|
||||
}
|
||||
if (bodysp) {
|
||||
bodysp->unlinkFrBackWithNext();
|
||||
stmtsp = stmtsp->addNextNull(bodysp); // Maybe null if no body
|
||||
}
|
||||
// If it's a While, then incp is already part of bodysp.
|
||||
V3Number loopValue(nodep->fileline(), m_forVarp->width()); // May differ in size from numInitp
|
||||
loopValue.opAssign(numInit);
|
||||
|
||||
AstNode* newbodysp = NULL;
|
||||
AstNode* clonedIncsp = NULL; // Last cloned incp() statements
|
||||
m_statLoops++;
|
||||
if (bodysp) {
|
||||
if (stmtsp) {
|
||||
int times = 0;
|
||||
while (1) {
|
||||
UINFO(8," Looping "<<loopValue<<endl);
|
||||
@@ -205,7 +240,21 @@ private:
|
||||
if (contin.isEqZero()) {
|
||||
break; // Done with the loop
|
||||
} else {
|
||||
AstNode* oneloopp = bodysp->cloneTree(true);
|
||||
// Replace iterator values with constant.
|
||||
AstNode* oneloopp = stmtsp->cloneTree(true);
|
||||
|
||||
// A nicer way to propage the loop constant would be to set the variable to the value
|
||||
// and call a constant-propagator like V3Table, so temp values
|
||||
// that are calculated propagate down.
|
||||
// If we do this, we can remove the below
|
||||
if (nodep->castWhile() && incp) {
|
||||
if (clonedIncsp) {
|
||||
// Previous iteration of loop set the variable.
|
||||
// This set is redundant with this next iteration and can be removed.
|
||||
clonedIncsp->unlinkFrBack()->deleteTree();
|
||||
}
|
||||
clonedIncsp = incp->clonep(); if (!clonedIncsp) nodep->v3fatalSrc("inc failed");
|
||||
}
|
||||
|
||||
m_varValuep = new AstConst(nodep->fileline(), loopValue);
|
||||
m_varModeReplace = true;
|
||||
@@ -228,55 +277,60 @@ private:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// And, leave the iterator at the right final value.
|
||||
if (!nodep->castGenFor()) {
|
||||
AstVarRef* newrefp = (m_forVscp
|
||||
? new AstVarRef(nodep->fileline(), m_forVscp, true)
|
||||
: new AstVarRef(nodep->fileline(), m_forVarp, true));
|
||||
AstAssign* finalAssignp = new AstAssign
|
||||
(nodep->fileline(),
|
||||
newrefp,
|
||||
new AstConst(nodep->fileline(), loopValue));
|
||||
if (newbodysp) newbodysp->addNext(finalAssignp);
|
||||
else newbodysp = finalAssignp;
|
||||
}
|
||||
|
||||
// Leaving the iterator at the final value is handled by the increment statements being left the final body
|
||||
// Replace the FOR()
|
||||
if (newbodysp) nodep->replaceWith(newbodysp);
|
||||
else nodep->unlinkFrBack();
|
||||
if (debug()>=9) newbodysp->dumpTree(cout," _new: ");
|
||||
if (debug()>=9) newbodysp->dumpTree(cout,"- _new: ");
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeFor* nodep, AstNUser*) {
|
||||
if (!m_generate || m_varModeReplace) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstWhile* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (m_varModeCheck || m_varModeReplace) {
|
||||
} else {
|
||||
if (forUnrollCheck(nodep)) {
|
||||
// Constify before unroll call, as it may change what is underneath.
|
||||
if (nodep->precondsp()) V3Const::constifyTree(nodep->precondsp());
|
||||
if (nodep->condp()) V3Const::constifyTree(nodep->condp());
|
||||
// Grab initial value
|
||||
AstNode* initp = NULL; // Should be statement before the while.
|
||||
if (nodep->backp()->nextp() == nodep) initp=nodep->backp();
|
||||
if (initp) V3Const::constifyTree(initp);
|
||||
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()) {}
|
||||
if (incp) V3Const::constifyTree(incp);
|
||||
for (incp = nodep->bodysp(); incp->nextp(); incp = incp->nextp()) {} // Again, as may have changed
|
||||
// And check it
|
||||
if (forUnrollCheck(nodep, initp,
|
||||
nodep->precondsp(), nodep->condp(),
|
||||
incp, nodep->bodysp())) {
|
||||
nodep=NULL; // Did replacement
|
||||
} else if (m_generate || nodep->castGenFor()) {
|
||||
nodep->v3error("For loop doesn't have genvar index, or is misformed");
|
||||
} else {
|
||||
// So later optimizations don't need to deal with them,
|
||||
// convert leftover FOR's:
|
||||
// FOR(init,cond,assign,body) -> init,WHILE(cond) { body, assign }
|
||||
AstNode* initsp = nodep->initsp(); if (initsp) initsp->unlinkFrBackWithNext();
|
||||
AstNode* condp = nodep->condp(); if (condp) condp->unlinkFrBackWithNext();
|
||||
AstNode* assignsp = nodep->assignsp(); if (assignsp) assignsp->unlinkFrBackWithNext();
|
||||
AstNode* bodysp = nodep->bodysp(); if (bodysp) bodysp->unlinkFrBackWithNext();
|
||||
bodysp = bodysp->addNext(assignsp);
|
||||
AstNode* newp = new AstWhile(nodep->fileline(),
|
||||
condp,
|
||||
bodysp);
|
||||
initsp = initsp->addNext(newp);
|
||||
newp = initsp;
|
||||
nodep->replaceWith(newp);
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstGenFor* nodep, AstNUser*) {
|
||||
if (!m_generate || m_varModeReplace) {
|
||||
nodep->iterateChildren(*this);
|
||||
} // else V3Param will recursively call each for loop to be unrolled for us
|
||||
if (m_varModeCheck || m_varModeReplace) {
|
||||
} else {
|
||||
// Constify before unroll call, as it may change what is underneath.
|
||||
if (nodep->initsp()) V3Const::constifyTree(nodep->initsp());
|
||||
if (nodep->condp()) V3Const::constifyTree(nodep->condp());
|
||||
if (nodep->incsp()) V3Const::constifyTree(nodep->incsp());
|
||||
if (forUnrollCheck(nodep, nodep->initsp(),
|
||||
NULL, nodep->condp(),
|
||||
nodep->incsp(), nodep->bodysp())) {
|
||||
nodep=NULL; // Did replacement
|
||||
} else {
|
||||
nodep->v3error("For loop doesn't have genvar index, or is misformed");
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeFor* nodep, AstNUser*) {
|
||||
nodep->v3error("V3Task should have removed standard FORs");
|
||||
}
|
||||
|
||||
virtual void visit(AstBegin* nodep, AstNUser*) {
|
||||
// Naming inside loop body; must have been a generate for.
|
||||
@@ -307,7 +361,8 @@ private:
|
||||
}
|
||||
if (m_varModeReplace
|
||||
&& nodep->varp() == m_forVarp
|
||||
&& nodep->varScopep() == m_forVscp) {
|
||||
&& nodep->varScopep() == m_forVscp
|
||||
&& !nodep->lvalue()) {
|
||||
AstNode* newconstp = m_varValuep->cloneTree(false);
|
||||
nodep->replaceWith(newconstp);
|
||||
}
|
||||
@@ -316,7 +371,11 @@ private:
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (m_varModeCheck && nodep == m_ignoreIncp) {
|
||||
// Ignore subtree that is the increment
|
||||
} else {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -324,6 +383,7 @@ public:
|
||||
UnrollVisitor(AstNode* nodep, bool generate) {
|
||||
m_forVarp = NULL;
|
||||
m_forVscp = NULL;
|
||||
m_ignoreIncp = NULL;
|
||||
m_varModeCheck = false;
|
||||
m_varModeReplace = false;
|
||||
m_inBegin = false;
|
||||
|
||||
+1
-1
@@ -492,7 +492,7 @@ private:
|
||||
nodep->initsp()->iterateAndNext(*this);
|
||||
nodep->condp()->iterateAndNext(*this,WidthVP(1,1,BOTH).p());
|
||||
if (!nodep->castGenFor()) nodep->bodysp()->iterateAndNext(*this);
|
||||
nodep->assignsp()->iterateAndNext(*this);
|
||||
nodep->incsp()->iterateAndNext(*this);
|
||||
widthCheckReduce(nodep,"For Test Condition",nodep->condp(),1,1); // it's like a if() condition.
|
||||
}
|
||||
virtual void visit(AstWhile* nodep, AstNUser*) {
|
||||
|
||||
+11
-5
@@ -109,7 +109,7 @@ void process () {
|
||||
// Cross-link signal names
|
||||
V3Link::link(v3Global.rootp());
|
||||
// Cross-link dotted hierarchical references
|
||||
V3LinkDot::linkDot(v3Global.rootp());
|
||||
V3LinkDot::linkDotPrearrayed(v3Global.rootp());
|
||||
// Correct state we couldn't know at parse time, repair SEL's, set lvalue's
|
||||
V3LinkResolve::linkResolve(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("link.tree"));
|
||||
@@ -120,7 +120,7 @@ void process () {
|
||||
// Remove parameters by cloning modules to de-parameterized versions
|
||||
// This requires some width calculations and constant propagation
|
||||
V3Param::param(v3Global.rootp());
|
||||
V3LinkDot::linkDot(v3Global.rootp()); // Cleanup as made new modules
|
||||
V3LinkDot::linkDotPrearrayed(v3Global.rootp()); // Cleanup as made new modules
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param.tree"));
|
||||
V3Error::abortIfErrors();
|
||||
|
||||
@@ -169,7 +169,7 @@ void process () {
|
||||
V3Const::constifyAllLint(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||
|
||||
// Remove cell arrays (must be between V3Width and tasking)
|
||||
// Remove cell arrays (must be between V3Width and scoping)
|
||||
V3Inst::dearrayAll(v3Global.rootp());
|
||||
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("dearray.tree"));
|
||||
|
||||
@@ -189,7 +189,7 @@ void process () {
|
||||
if (v3Global.opt.oInline()) {
|
||||
V3Inline::inlineAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("inline.tree"));
|
||||
V3LinkDot::linkDot(v3Global.rootp()); // Cleanup as made new modules
|
||||
V3LinkDot::linkDotArrayed(v3Global.rootp()); // Cleanup as made new modules
|
||||
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkdot.tree"));
|
||||
}
|
||||
|
||||
@@ -286,8 +286,14 @@ void process () {
|
||||
if (v3Global.opt.oGate()) {
|
||||
V3Gate::gateAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("gate.tree"));
|
||||
// V3Gate calls constant propagation itself.
|
||||
}
|
||||
|
||||
// Remove unused vars
|
||||
V3Const::constifyAll(v3Global.rootp());
|
||||
V3Dead::deadifyAll(v3Global.rootp(), true);
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||
|
||||
// Reorder assignments in pipelined blocks
|
||||
if (v3Global.opt.oReorder()) {
|
||||
V3Split::splitReorderAll(v3Global.rootp());
|
||||
@@ -333,7 +339,7 @@ void process () {
|
||||
|
||||
// Remove unused vars
|
||||
V3Const::constifyAll(v3Global.rootp());
|
||||
V3Dead::deadifyAll(v3Global.rootp(), false);
|
||||
V3Dead::deadifyAll(v3Global.rootp(), true);
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
|
||||
|
||||
#ifndef NEW_ORDERING
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
//**********************************************************************
|
||||
//**** Version and host name
|
||||
|
||||
#define DTVERSION "Verilator 3.600 08/28/2006"
|
||||
#define DTVERSION "Verilator 3.610 09/20/2006"
|
||||
|
||||
//**********************************************************************
|
||||
//**** Functions
|
||||
|
||||
+3
-3
@@ -222,7 +222,7 @@ class AstSenTree;
|
||||
%type<nodep> v2kPort ioDecl varDecl
|
||||
%type<nodep> modParDecl modParList modParE
|
||||
%type<nodep> modItem modItemList modItemListOrNone modOrGenItem
|
||||
%type<nodep> genItem genItemList genItemBegin genItemBlock genItemsBlock genCaseList
|
||||
%type<nodep> genItem genItemList genItemBegin genItemBlock genTopBlock genCaseList
|
||||
%type<nodep> dterm
|
||||
%type<varp> onesig sigId sigIdRange paramId sigList regsig regsigList regSigId
|
||||
%type<varp> netSig netSigList
|
||||
@@ -399,7 +399,7 @@ modItemList: modItem { $$ = $1; }
|
||||
;
|
||||
|
||||
modItem: modOrGenItem { $$ = $1; }
|
||||
| yGENERATE genItemsBlock yENDGENERATE { $$ = new AstGenerate($1, $2); }
|
||||
| yGENERATE genTopBlock yENDGENERATE { $$ = new AstGenerate($1, $2); }
|
||||
| ySCHDR { $$ = new AstScHdr(CRELINE(),*$1); }
|
||||
| ySCINT { $$ = new AstScInt(CRELINE(),*$1); }
|
||||
| ySCIMP { $$ = new AstScImp(CRELINE(),*$1); }
|
||||
@@ -437,7 +437,7 @@ genItemBlock: genItem { $$ = new AstBegin(CRELINE(),"genblk",$1); }
|
||||
| genItemBegin { $$ = $1; }
|
||||
;
|
||||
|
||||
genItemsBlock: genItemList { $$ = new AstBegin(CRELINE(),"genblk",$1); }
|
||||
genTopBlock: genItemList { $$ = new AstBegin(CRELINE(),"genblk",$1); }
|
||||
| genItemBegin { $$ = $1; }
|
||||
;
|
||||
|
||||
|
||||
+20
-10
@@ -123,7 +123,8 @@ sub one_test {
|
||||
} else {
|
||||
$test->oprint("FAILED: ","*"x60,"\n");
|
||||
push @fails, "\t#".$test->soprint("%Error: $test->{errors}\n");
|
||||
push @fails, "\t\tmake && ( cd test_regress ; "
|
||||
my $j = ($opt_jobs>1?" -j 2":"");
|
||||
push @fails, "\t\tmake$j && ( cd test_regress ; "
|
||||
.$test->{pl_filename}." ".join(' ',@Orig_ARGV_Sw)." )\n";
|
||||
$failcnt++;
|
||||
if ($opt_stop) { die "%Error: --stop and errors found\n"; }
|
||||
@@ -252,7 +253,7 @@ sub read {
|
||||
sub write_status {
|
||||
my $self = shift;
|
||||
my $filename = $self->{status_filename};
|
||||
my $fh = IO::File->new($filename,"w") or die "%Error: $! $filename,";
|
||||
my $fh = IO::File->new(">$filename") or die "%Error: $! $filename,";
|
||||
print $fh Dumper($self);
|
||||
print $fh "1;";
|
||||
$fh->close();
|
||||
@@ -372,7 +373,7 @@ sub execute {
|
||||
my %param = (%{$self}, @_); # Default arguments are from $self
|
||||
$self->oprint("Run\n");
|
||||
if ($param{vcs}) {
|
||||
#my $fh = IO::File->new("simv.key","w") or die "%Error: $! simv.key,";
|
||||
#my $fh = IO::File->new(">simv.key") or die "%Error: $! simv.key,";
|
||||
#$fh->print("quit\n"); $fh->close;
|
||||
$self->_run(logfile=>"obj_dir/".$self->{name}."_simv.log",
|
||||
cmd=>["./simv",],
|
||||
@@ -461,7 +462,7 @@ sub _run {
|
||||
sleep 1 if ($try!=7);
|
||||
my $moretry = $try!=0;
|
||||
|
||||
my $fh = IO::File->new($param{logfile},"r");
|
||||
my $fh = IO::File->new("<$param{logfile}");
|
||||
next if !$fh && $moretry;
|
||||
local $/; undef $/;
|
||||
my $wholefile = <$fh>;
|
||||
@@ -507,7 +508,7 @@ sub _make_main {
|
||||
$self->_read_inputs();
|
||||
|
||||
my $filename = "obj_dir/$self->{VM_PREFIX}__main.cpp";
|
||||
my $fh = IO::File->new($filename,"w") or die "%Error: $! $filename,";
|
||||
my $fh = IO::File->new(">$filename") or die "%Error: $! $filename,";
|
||||
|
||||
my $VM_PREFIX = $self->{VM_PREFIX};
|
||||
print $fh "#include \"$VM_PREFIX.h\"\n";
|
||||
@@ -586,7 +587,7 @@ sub _make_top {
|
||||
|
||||
$self->_read_inputs();
|
||||
|
||||
my $fh = IO::File->new($self->{top_shell_filename},"w") or die "%Error: $! $self->{top_shell_filename},";
|
||||
my $fh = IO::File->new(">$self->{top_shell_filename}") or die "%Error: $! $self->{top_shell_filename},";
|
||||
print $fh "module top;\n";
|
||||
foreach my $inp (sort (keys %{$self->{inputs}})) {
|
||||
print $fh " reg ${inp};\n";
|
||||
@@ -639,7 +640,7 @@ sub _read_inputs {
|
||||
my $self = shift;
|
||||
my $filename = $self->{top_filename};
|
||||
$filename = "t/$filename" if !-r $filename;
|
||||
my $fh = IO::File->new($filename) or die "%Error: $! $filename,";
|
||||
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename,";
|
||||
while (defined(my $line = $fh->getline)) {
|
||||
if ($line =~ /^\s*input\s*(\S+)\s*(\/[^\/]+\/|)\s*;/) {
|
||||
$self->{inputs}{$1} = $1;
|
||||
@@ -672,8 +673,8 @@ sub verilator_version {
|
||||
sub files_identical {
|
||||
my $fn1 = shift;
|
||||
my $fn2 = shift;
|
||||
my $f1 = IO::File->new ($fn1) or die "%Error: $! $fn1,";
|
||||
my $f2 = IO::File->new ($fn2) or die "%Error: $! $fn2,";
|
||||
my $f1 = IO::File->new ("<$fn1") or die "%Error: $! $fn1,";
|
||||
my $f2 = IO::File->new ("<$fn2") or die "%Error: $! $fn2,";
|
||||
my @l1 = $f1->getlines();
|
||||
my @l2 = $f2->getlines();
|
||||
my $nl = $#l1; $nl = $#l2 if ($#l2 > $nl);
|
||||
@@ -719,7 +720,7 @@ sub file_contents {
|
||||
my $filename = shift;
|
||||
|
||||
if (!$_File_Contents_Cache{$filename}) {
|
||||
my $fh = IO::File->new($filename,"r");
|
||||
my $fh = IO::File->new("<$filename");
|
||||
if (!$fh) {
|
||||
$_File_Contents_Cache{$filename} = "_Already_Errored_";
|
||||
$self->error("File_grep file not found: ".$filename."\n");
|
||||
@@ -734,6 +735,15 @@ sub file_contents {
|
||||
return $_File_Contents_Cache{$filename};
|
||||
}
|
||||
|
||||
sub write_wholefile {
|
||||
my $self = (ref $_[0]? shift : $Last_Self);
|
||||
my $filename = shift;
|
||||
my $contents = shift;
|
||||
my $fh = IO::File->new(">$filename") or die "%Error: $! writing $filename,";
|
||||
print $fh $contents;
|
||||
$fh->close;
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
#######################################################################
|
||||
#######################################################################
|
||||
|
||||
Executable
+22
@@ -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 2004 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,
|
||||
expect=>
|
||||
'[10] hello
|
||||
[20] world
|
||||
',
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,81 @@
|
||||
// $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 j;
|
||||
integer hit_count;
|
||||
reg [63:0] cam_lookup_hit_vector;
|
||||
|
||||
strings strings ();
|
||||
|
||||
task show;
|
||||
input [8*8-1:0] str;
|
||||
reg [7:0] char;
|
||||
integer loc;
|
||||
begin
|
||||
$write("[%0t] ",$time);
|
||||
strings.stringStart(8*8-1);
|
||||
for (char = strings.stringByte(str); !strings.isNull(char); char = strings.stringByte(str)) begin
|
||||
$write("%c",char);
|
||||
end
|
||||
$write("\n");
|
||||
end
|
||||
endtask
|
||||
|
||||
|
||||
integer cyc; initial cyc=1;
|
||||
always @ (posedge clk) begin
|
||||
if (cyc!=0) begin
|
||||
cyc <= cyc + 1;
|
||||
if (cyc==1) begin
|
||||
show("hello\000xx");
|
||||
end
|
||||
if (cyc==2) begin
|
||||
show("world\000xx");
|
||||
end
|
||||
if (cyc==4) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module strings;
|
||||
// **NOT** reentrant, just a test!
|
||||
integer index;
|
||||
task stringStart;
|
||||
input [31:0] bits;
|
||||
begin
|
||||
index = (bits-1)/8;
|
||||
end
|
||||
endtask
|
||||
|
||||
function isNull;
|
||||
input [7:0] chr;
|
||||
isNull = (chr == 8'h0);
|
||||
endfunction
|
||||
|
||||
function [7:0] stringByte;
|
||||
input [8*8-1:0] str;
|
||||
begin
|
||||
if (index<=0) stringByte=8'h0;
|
||||
else stringByte = str[index*8 +: 8];
|
||||
index = index - 1;
|
||||
end
|
||||
endfunction
|
||||
endmodule
|
||||
|
||||
// Local Variables:
|
||||
// compile-command: "./vlint __FILE__"
|
||||
// End:
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
#!/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 (
|
||||
v_flags2 => ['-v', 't/t_func_lib_sub.v'],
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,13 @@
|
||||
// $Id$
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2003-2006 by Wilson Snyder.
|
||||
|
||||
module t;
|
||||
initial begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#!/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 (
|
||||
);
|
||||
# No execute
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,101 @@
|
||||
// $Id$
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2003-2006 by Wilson Snyder.
|
||||
|
||||
`define zednkw 200
|
||||
|
||||
module BreadAddrDP (zfghtn, cjtmau, knquim, kqxkkr);
|
||||
input zfghtn;
|
||||
input [4:0] cjtmau;
|
||||
input vipmpg;
|
||||
input [7:0] knquim;
|
||||
input [7:0] kqxkkr;
|
||||
|
||||
reg covfok;
|
||||
|
||||
reg [15:0] xwieqw;
|
||||
reg [2:0] ofnjjt;
|
||||
|
||||
reg [37:0] hdsejo[0:1];
|
||||
|
||||
reg wxxzgd, tceppr, ratebp, fjizkr, iwwrnq;
|
||||
reg vrqrih, ryyjxy;
|
||||
reg fgzsox;
|
||||
|
||||
wire xdjikl = ~wxxzgd & ~tceppr & ~ratebp & fjizkr;
|
||||
wire iytyol = ~wxxzgd & ~tceppr & ratebp & ~fjizkr & ~xwieqw[10];
|
||||
wire dywooz = ~wxxzgd & ~tceppr & ratebp & ~fjizkr & xwieqw[10];
|
||||
wire qnpfus = ~wxxzgd & ~tceppr & ratebp & fjizkr;
|
||||
wire fqlkrg = ~wxxzgd & tceppr & ~ratebp & ~fjizkr;
|
||||
|
||||
wire ktsveg = hdsejo[0][6] | (hdsejo[0][37:34] == 4'h1);
|
||||
wire smxixw = vrqrih | (ryyjxy & ktsveg);
|
||||
|
||||
wire [7:0] grvsrs, kyxrft, uxhkka;
|
||||
|
||||
wire [7:0] eianuv = 8'h01 << ofnjjt;
|
||||
wire [7:0] jvpnxn = {8{qnpfus}} & eianuv;
|
||||
wire [7:0] zlnzlj = {8{fqlkrg}} & eianuv;
|
||||
wire [7:0] nahzat = {8{iytyol}} & eianuv;
|
||||
|
||||
genvar i;
|
||||
generate
|
||||
for (i=0;i<8;i=i+1)
|
||||
begin : dnlpyw
|
||||
DecCountReg4 bzpytc (zfghtn, fgzsox, zlnzlj[i],
|
||||
knquim[3:0], covfok, grvsrs[i]);
|
||||
DecCountReg4 oghukp (zfghtn, fgzsox, zlnzlj[i],
|
||||
knquim[7:4], covfok, kyxrft[i]);
|
||||
DecCountReg4 ttvjoo (zfghtn, fgzsox, nahzat[i],
|
||||
kqxkkr[3:0], covfok, uxhkka[i]);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
endmodule
|
||||
|
||||
module DecCountReg4 (clk, fgzsox, fckiyr, uezcjy, covfok, juvlsh);
|
||||
input clk, fgzsox, fckiyr, covfok;
|
||||
input [3:0] uezcjy;
|
||||
output juvlsh;
|
||||
|
||||
task Xinit;
|
||||
begin
|
||||
`ifdef TEST_HARNESS
|
||||
khgawe = 1'b0;
|
||||
`endif
|
||||
end
|
||||
endtask
|
||||
function X;
|
||||
input vrdejo;
|
||||
begin
|
||||
`ifdef TEST_HARNESS
|
||||
if ((vrdejo & ~vrdejo) !== 1'h0) khgawe = 1'b1;
|
||||
`endif
|
||||
X = vrdejo;
|
||||
end
|
||||
endfunction
|
||||
task Xcheck;
|
||||
input vzpwwy;
|
||||
begin
|
||||
end
|
||||
endtask
|
||||
|
||||
reg [3:0] udbvtl;
|
||||
|
||||
assign juvlsh = |udbvtl;
|
||||
wire [3:0] mppedc = {4{fgzsox}} & (fckiyr ? uezcjy : (udbvtl - 4'h1));
|
||||
|
||||
wire qqibou = ((juvlsh | fckiyr) & covfok) | ~fgzsox;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
Xinit;
|
||||
if (X(qqibou))
|
||||
udbvtl <= #`zednkw mppedc;
|
||||
|
||||
Xcheck(fgzsox);
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -1,4 +1,4 @@
|
||||
// $Id:$
|
||||
// $Id$
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
@@ -11,6 +11,7 @@ module t (/*AUTOARG*/
|
||||
|
||||
input clk;
|
||||
integer cyc; initial cyc=1;
|
||||
parameter ONE = 1;
|
||||
|
||||
wire [17:10] bitout;
|
||||
reg [7:0] allbits;
|
||||
@@ -18,6 +19,8 @@ module t (/*AUTOARG*/
|
||||
|
||||
sub sub [7:0] (allbits, onebit, bitout);
|
||||
|
||||
integer x;
|
||||
|
||||
always @ (posedge clk) begin
|
||||
//$write("%x\n", bitout);
|
||||
if (cyc!=0) begin
|
||||
@@ -33,6 +36,14 @@ module t (/*AUTOARG*/
|
||||
end
|
||||
if (cyc==3) begin
|
||||
if (bitout !== 8'h41) $stop;
|
||||
`ifdef verilator // Hacky array subscripting
|
||||
if (sub__0.bitout !== 1'b1) $stop;
|
||||
if (sub__1.bitout !== 1'b0) $stop;
|
||||
`else
|
||||
if (sub[0].bitout !== 1'b1) $stop;
|
||||
if (sub[1].bitout !== 1'b0) $stop;
|
||||
if (sub[ONE].bitout !== 1'b0) $stop;
|
||||
`endif
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
@@ -40,7 +51,14 @@ module t (/*AUTOARG*/
|
||||
end
|
||||
endmodule
|
||||
|
||||
`ifdef USE_INLINE
|
||||
`define INLINE_MODULE /*verilator inline_module*/
|
||||
`else
|
||||
`define INLINE_MODULE /*verilator public_module*/
|
||||
`endif
|
||||
|
||||
module sub (input [7:0] allbits, input [1:0] onebit, output bitout);
|
||||
`INLINE_MODULE
|
||||
wire bitout = (^ onebit) ^ (^ allbits);
|
||||
endmodule
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/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.
|
||||
|
||||
top_filename("t/t_inst_array.v");
|
||||
|
||||
compile (
|
||||
v_flags2 => ['+define+NOUSE_INLINE',],
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -1,13 +1,16 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
|
||||
# $Id:$
|
||||
# $Id$
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003-2005 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.
|
||||
|
||||
top_filename("t/t_inst_array.v");
|
||||
|
||||
compile (
|
||||
v_flags2 => ['+define+USE_INLINE',],
|
||||
);
|
||||
|
||||
execute (
|
||||
@@ -75,6 +75,7 @@ module t (/*AUTOARG*/
|
||||
endfunction
|
||||
|
||||
integer cyc; initial cyc=0;
|
||||
wire [31:0] ucyc = cyc;
|
||||
always @ (posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
$write("%x %x %x %x %x %x %x\n", cyc, sr,srs,sl,sls, b_s,b_us);
|
||||
@@ -88,9 +89,24 @@ module t (/*AUTOARG*/
|
||||
end
|
||||
2: begin
|
||||
a <= 16'sh8b1b; b <= 5'sh1e; // shift AMOUNT is really unsigned
|
||||
if (ucyc / 1 != 32'd2) $stop;
|
||||
if (ucyc / 2 != 32'd1) $stop;
|
||||
if (ucyc * 1 != 32'd2) $stop;
|
||||
if (ucyc * 2 != 32'd4) $stop;
|
||||
if (ucyc * 3 != 32'd6) $stop;
|
||||
if (cyc * 32'sd1 != 32'sd2) $stop;
|
||||
if (cyc * 32'sd2 != 32'sd4) $stop;
|
||||
if (cyc * 32'sd3 != 32'sd6) $stop;
|
||||
end
|
||||
3: begin
|
||||
a <= 16'sh0048; b <= 5'sh1f;
|
||||
if (ucyc * 1 != 32'd3) $stop;
|
||||
if (ucyc * 2 != 32'd6) $stop;
|
||||
if (ucyc * 3 != 32'd9) $stop;
|
||||
if (ucyc * 4 != 32'd12) $stop;
|
||||
if (cyc * 32'sd1 != 32'sd3) $stop;
|
||||
if (cyc * 32'sd2 != 32'sd6) $stop;
|
||||
if (cyc * 32'sd3 != 32'sd9) $stop;
|
||||
end
|
||||
4: begin
|
||||
a <= 16'sh4154; b <= 5'sh02;
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
// $Id:$
|
||||
// $Id$
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// Use this file as a template for submitting bugs, etc.
|
||||
// This module takes a single clock input, and should either
|
||||
// $write("*-* All Finished *-*\n");
|
||||
// $finish
|
||||
// on success, or $stop.
|
||||
//
|
||||
// **If you do not wish for your code to be released to the public
|
||||
// please note it here**
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2005 by Wilson Snyder.
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
|
||||
# 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";
|
||||
my $stdout_filename = "obj_dir/$Last_Self->{name}__test.vpp";
|
||||
|
||||
if (!$Last_Self->{v3}) {
|
||||
@@ -17,8 +18,8 @@ if (!$Last_Self->{v3}) {
|
||||
verilator_make_gcc=>0,
|
||||
stdout_filename => $stdout_filename,
|
||||
);
|
||||
ok(preproc_check("t/$Last_Self->{name}.v", $stdout_filename)
|
||||
&& files_identical($stdout_filename, "t/$Last_Self->{name}.out"));
|
||||
ok(preproc_check($Last_Self->{top_filename}, $stdout_filename)
|
||||
&& files_identical($stdout_filename, $golden_out));
|
||||
}
|
||||
|
||||
sub preproc_check {
|
||||
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
|
||||
# $Id$
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2006-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.
|
||||
|
||||
top_filename("obj_dir/$Last_Self->{name}.v");
|
||||
|
||||
# Rather then having to maintain a new .v and .out, simply add returns
|
||||
# to all lines of the existing t_preproc test.
|
||||
|
||||
$golden_out ||= "obj_dir/$Last_Self->{name}.out";
|
||||
|
||||
{
|
||||
my $wholefile = file_contents("t/t_preproc.v");
|
||||
$wholefile =~ s/\n/\r\n/og;
|
||||
write_wholefile("obj_dir/$Last_Self->{name}.v", $wholefile);
|
||||
}
|
||||
{
|
||||
my $wholefile = file_contents("t/t_preproc.out");
|
||||
$wholefile =~ s!t/t_preproc.v!obj_dir/t_preproc_dos.v!og; # Fix `line's
|
||||
write_wholefile($golden_out, $wholefile);
|
||||
}
|
||||
|
||||
require 't/t_preproc.pl';
|
||||
|
||||
1;
|
||||
Reference in New Issue
Block a user