Compare commits

...
9 Commits
Author SHA1 Message Date
Wilson Snyder 53155b3a36 Version bump
git-svn-id: file://localhost/svn/verilator/trunk/verilator@783 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-11 20:44:54 +00:00
Wilson Snyder 12ae70ba95 Prep for removing begin under first generate, but doesn't work. Commentary instead
git-svn-id: file://localhost/svn/verilator/trunk/verilator@782 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-11 20:42:47 +00:00
Wilson Snyder 88809587f9 Fix function references under top inlined module.
git-svn-id: file://localhost/svn/verilator/trunk/verilator@781 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-08 16:16:30 +00:00
Wilson Snyder 1b20481100 Version bump
git-svn-id: file://localhost/svn/verilator/trunk/verilator@778 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-06 17:50:47 +00:00
Wilson Snyder 21eb939f37 Allow dotted references of arrayed cells
git-svn-id: file://localhost/svn/verilator/trunk/verilator@777 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-06 17:48:41 +00:00
Wilson Snyder 0a765fbb54 Fix function calls inside loop bounds
git-svn-id: file://localhost/svn/verilator/trunk/verilator@776 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-05 20:06:23 +00:00
Wilson Snyder 749fdaae31 Optimize n*powers of 2. (For parameterized DDR model)
git-svn-id: file://localhost/svn/verilator/trunk/verilator@775 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-01 16:53:14 +00:00
Wilson Snyder 6f48185a1f Fix arrayed instances
git-svn-id: file://localhost/svn/verilator/trunk/verilator@774 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-01 15:31:07 +00:00
Wilson Snyder 7f1b16837e Fix dead modules under generate cells not getting removed
git-svn-id: file://localhost/svn/verilator/trunk/verilator@773 77ca24e4-aefa-0310-84f0-b9a241c72d87
2006-09-01 14:05:20 +00:00
33 changed files with 758 additions and 225 deletions
+15 -4
View File
@@ -3,9 +3,11 @@ 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.602 09/11/2006
*** Changed how internal functions are invoked to avoid aliasing in GCC 3.3+.
**** 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 +15,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.
+22 -1
View File
@@ -1116,7 +1116,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
@@ -1351,6 +1369,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
+1 -1
View File
@@ -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");
+4 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
}
}
+1 -1
View File
@@ -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);
+4
View File
@@ -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
View File
@@ -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
View File
@@ -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
+6
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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
+92 -33
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -24,7 +24,7 @@
//**********************************************************************
//**** Version and host name
#define DTVERSION "Verilator 3.600 08/28/2006"
#define DTVERSION "Verilator 3.602 09/11/2006"
//**********************************************************************
//**** Functions
+3 -3
View File
@@ -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; }
;
+2 -1
View File
@@ -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"; }
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
# $Id$
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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;
+81
View File
@@ -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:
+19
View File
@@ -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;
+13
View File
@@ -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
+14
View File
@@ -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;
+101
View File
@@ -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
+19 -1
View File
@@ -1,4 +1,4 @@
// $Id:$
// $Id$
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
@@ -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
+21
View File
@@ -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 (
+16
View File
@@ -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;
+3 -9
View File
@@ -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*/);