Rework parser and add V3LinkParse so we can handle foo[#].foo[#].foo[#:#] etc
git-svn-id: file://localhost/svn/verilator/trunk/verilator@862 77ca24e4-aefa-0310-84f0-b9a241c72d87
This commit is contained in:
parent
94d0aa2058
commit
58b1ad1439
|
|
@ -155,15 +155,15 @@ test_vcs: all_nomsg
|
|||
test_c: all_nomsg
|
||||
@(cd test_c && $(MAKE))
|
||||
test_c_debug: all_nomsg
|
||||
@(cd test_c && $(MAKE) debug)
|
||||
@(cd test_c && $(MAKE) test_debug)
|
||||
test_sc: all_nomsg
|
||||
@(cd test_sc && $(MAKE))
|
||||
test_sc_debug: all_nomsg
|
||||
@(cd test_sc && $(MAKE) debug)
|
||||
@(cd test_sc && $(MAKE) test_debug)
|
||||
test_sp: all_nomsg
|
||||
@(cd test_sp && $(MAKE))
|
||||
test_sp_debug: all_nomsg
|
||||
@(cd test_sp && $(MAKE) debug)
|
||||
@(cd test_sp && $(MAKE) test_debug)
|
||||
test_verilated: all_nomsg
|
||||
@(cd test_verilated && $(MAKE))
|
||||
test_regress: all_nomsg
|
||||
|
|
|
|||
|
|
@ -143,6 +143,7 @@ RAW_OBJS = \
|
|||
V3LinkDot.o \
|
||||
V3LinkLevel.o \
|
||||
V3LinkLValue.o \
|
||||
V3LinkParse.o \
|
||||
V3LinkResolve.o \
|
||||
V3Localize.o \
|
||||
V3Name.o \
|
||||
|
|
|
|||
43
src/V3Ast.h
43
src/V3Ast.h
|
|
@ -248,6 +248,33 @@ public:
|
|||
inline bool operator== (AstBranchPred::en lhs, AstBranchPred rhs) { return (lhs == rhs.m_e); }
|
||||
inline ostream& operator<<(ostream& os, AstBranchPred rhs) { return os<<rhs.ascii(); }
|
||||
|
||||
//######################################################################
|
||||
|
||||
class AstParseRefExp {
|
||||
public:
|
||||
enum en {
|
||||
NONE, // Used in V3LinkParse only
|
||||
VAR_MEM,
|
||||
VAR_ANY,
|
||||
TASK,
|
||||
FUNC,
|
||||
_ENUM_END
|
||||
};
|
||||
enum en m_e;
|
||||
inline AstParseRefExp() : m_e(NONE) {};
|
||||
inline AstParseRefExp (en _e) : m_e(_e) {};
|
||||
explicit inline AstParseRefExp (int _e) : m_e(static_cast<en>(_e)) {};
|
||||
operator en () const { return m_e; };
|
||||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
"","VAR_MEM","VAR_ANY","TASK","FUNC"};
|
||||
return names[m_e];};
|
||||
};
|
||||
inline bool operator== (AstParseRefExp lhs, AstParseRefExp rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator== (AstParseRefExp lhs, AstParseRefExp::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator== (AstParseRefExp::en lhs, AstParseRefExp rhs) { return (lhs == rhs.m_e); }
|
||||
inline ostream& operator<<(ostream& os, AstParseRefExp rhs) { return os<<rhs.ascii(); }
|
||||
|
||||
//######################################################################
|
||||
// AstNUser - Generic pointer base class for AST User nodes.
|
||||
// - Also used to allow parameter passing up/down iterate calls
|
||||
|
|
@ -943,10 +970,10 @@ private:
|
|||
string m_dotted; // Dotted part of scope to task or ""
|
||||
string m_inlinedDots; // Dotted hiearchy flattened out
|
||||
public:
|
||||
AstNodeFTaskRef(FileLine* fl, const string& name, const string& dotted, AstNode* pinsp)
|
||||
AstNodeFTaskRef(FileLine* fl, AstNode* namep, AstNode* pinsp)
|
||||
:AstNode(fl)
|
||||
, m_taskp(NULL), m_name(name), m_dotted(dotted) {
|
||||
addNOp1p(pinsp);
|
||||
, m_taskp(NULL) {
|
||||
setOp1p(namep); addNOp2p(pinsp);
|
||||
}
|
||||
virtual ~AstNodeFTaskRef() {}
|
||||
virtual bool broken() const { return m_taskp && !m_taskp->brokeExists(); }
|
||||
|
|
@ -961,9 +988,13 @@ public:
|
|||
void inlinedDots(const string& flag) { m_inlinedDots = flag; }
|
||||
AstNodeFTask* taskp() const { return m_taskp; } // [After Link] Pointer to variable
|
||||
void taskp(AstNodeFTask* taskp) { m_taskp=taskp; }
|
||||
// op1 = Pin interconnection list
|
||||
AstNode* pinsp() const { return op1p()->castNode(); }
|
||||
void addPinsp(AstNode* nodep) { addOp1p(nodep); }
|
||||
void name(const string& name) { m_name = name; }
|
||||
void dotted(const string& name) { m_dotted = name; }
|
||||
// op1 = namep
|
||||
AstNode* namep() const { return op1p(); }
|
||||
// op2 = Pin interconnection list
|
||||
AstNode* pinsp() const { return op2p()->castNode(); }
|
||||
void addPinsp(AstNode* nodep) { addOp2p(nodep); }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
|
|
|||
|
|
@ -361,7 +361,11 @@ void AstSenTree::dump(ostream& str) {
|
|||
}
|
||||
void AstSenItem::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
str<<" ["<<m_edgeType.ascii()<<"]";
|
||||
str<<" ["<<edgeType().ascii()<<"]";
|
||||
}
|
||||
void AstParseRef::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
str<<" ["<<expect().ascii()<<"]";
|
||||
}
|
||||
void AstActive::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
|
|
|
|||
|
|
@ -756,6 +756,46 @@ struct AstGenerate : public AstNode {
|
|||
void addStmtp(AstNode* nodep) { addOp1p(nodep); }
|
||||
};
|
||||
|
||||
struct AstParseRef : public AstNode {
|
||||
// A reference to a variable, function or task
|
||||
// We don't know which at parse time due to bison constraints
|
||||
// The link stages will replace this with AstVarRef, or AstTaskRef, etc.
|
||||
// Parents: math|stmt
|
||||
// Children: TEXT|DOT|SEL* (or expression under sel)
|
||||
private:
|
||||
AstParseRefExp m_expect; // Type we think it should resolve to
|
||||
public:
|
||||
AstParseRef(FileLine* fl, AstParseRefExp expect, AstNode* lhsp)
|
||||
:AstNode(fl), m_expect(expect) { setOp1p(lhsp); }
|
||||
virtual ~AstParseRef() {}
|
||||
virtual AstType type() const { return AstType::PARSEREF;}
|
||||
virtual AstNode* clone() { return new AstParseRef(*this);}
|
||||
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
|
||||
virtual void dump(ostream& str);
|
||||
virtual V3Hash sameHash() const { return V3Hash(m_expect); }
|
||||
virtual bool same(AstNode* samep) const { return expect() == samep->castParseRef()->expect(); }
|
||||
virtual string emitVerilog() { V3ERROR_NA; return ""; }
|
||||
virtual string emitOperator() { V3ERROR_NA; return ""; }
|
||||
AstParseRefExp expect() const { return m_expect; }
|
||||
// op1 = Components
|
||||
AstNode* lhsp() const { return op1p(); } // op1 = List of statements
|
||||
};
|
||||
|
||||
struct AstDot : public AstNode {
|
||||
// A dot separating paths in a AstXRef, AstFuncRef or AstTaskRef
|
||||
// These are elimiated in the link stage
|
||||
AstDot(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
|
||||
:AstNode(fl) { setOp1p(lhsp); setOp2p(rhsp); }
|
||||
virtual ~AstDot() {}
|
||||
virtual AstType type() const { return AstType::DOT;}
|
||||
virtual AstNode* clone() { return new AstDot(*this);}
|
||||
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
|
||||
virtual string emitVerilog() { V3ERROR_NA; return ""; }
|
||||
virtual string emitOperator() { V3ERROR_NA; return ""; }
|
||||
AstNode* lhsp() const { return op1p(); }
|
||||
AstNode* rhsp() const { return op2p(); }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
struct AstTask : public AstNodeFTask {
|
||||
|
|
@ -785,8 +825,8 @@ struct AstFunc : public AstNodeFTask {
|
|||
|
||||
struct AstTaskRef : public AstNodeFTaskRef {
|
||||
// A reference to a task
|
||||
AstTaskRef(FileLine* fl, const string& name, const string& dotted, AstNode* pinsp)
|
||||
:AstNodeFTaskRef(fl, name, dotted, pinsp) {}
|
||||
AstTaskRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp)
|
||||
:AstNodeFTaskRef(fl, namep, pinsp) {}
|
||||
virtual ~AstTaskRef() {}
|
||||
virtual AstType type() const { return AstType::TASKREF;}
|
||||
virtual AstNode* clone() { return new AstTaskRef(*this);}
|
||||
|
|
@ -795,8 +835,8 @@ struct AstTaskRef : public AstNodeFTaskRef {
|
|||
|
||||
struct AstFuncRef : public AstNodeFTaskRef {
|
||||
// A reference to a function
|
||||
AstFuncRef(FileLine* fl, const string& name, const string& dotted, AstNode* pinsp)
|
||||
:AstNodeFTaskRef(fl, name, dotted, pinsp) {}
|
||||
AstFuncRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp)
|
||||
:AstNodeFTaskRef(fl, namep, pinsp) {}
|
||||
virtual ~AstFuncRef() {}
|
||||
virtual AstType type() const { return AstType::FUNCREF;}
|
||||
virtual AstNode* clone() { return new AstFuncRef(*this);}
|
||||
|
|
@ -816,8 +856,11 @@ public:
|
|||
class Settle {}; // for creator type-overload selection
|
||||
class Never {}; // for creator type-overload selection
|
||||
AstSenItem(FileLine* fl, AstEdgeType edgeType, AstNodeVarRef* varrefp)
|
||||
: AstNode(fl) {
|
||||
m_edgeType = edgeType;
|
||||
: AstNode(fl), m_edgeType(edgeType) {
|
||||
setOp1p(varrefp);
|
||||
}
|
||||
AstSenItem(FileLine* fl, AstEdgeType edgeType, AstParseRef* varrefp)
|
||||
: AstNode(fl), m_edgeType(edgeType) {
|
||||
setOp1p(varrefp);
|
||||
}
|
||||
AstSenItem(FileLine* fl, Combo)
|
||||
|
|
@ -1175,10 +1218,12 @@ public:
|
|||
};
|
||||
|
||||
struct AstDisplay : public AstNodePli {
|
||||
// Parents: stmtlist
|
||||
// Children: file which must be a varref, MATH to print
|
||||
private:
|
||||
char m_newline;
|
||||
public:
|
||||
AstDisplay(FileLine* fileline, char newln, const string& text, AstNodeVarRef* filep, AstNode* exprsp)
|
||||
AstDisplay(FileLine* fileline, char newln, const string& text, AstNode* filep, AstNode* exprsp)
|
||||
: AstNodePli (fileline, text, exprsp) {
|
||||
setNOp2p(filep);
|
||||
m_newline = newln;
|
||||
|
|
@ -1200,7 +1245,7 @@ public:
|
|||
&& text()==samep->castDisplay()->text(); }
|
||||
// op1 used by AstNodePli
|
||||
char newline() const { return m_newline; } // * = Add a newline for $display
|
||||
AstNodeVarRef* filep() const { return op2p()->castVarRef(); }
|
||||
AstNode* filep() const { return op2p(); }
|
||||
void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); }
|
||||
AstNode* scopeAttrp() const { return op3p(); }
|
||||
AstText* scopeTextp() const { return op3p()->castText(); }
|
||||
|
|
@ -1208,7 +1253,9 @@ public:
|
|||
};
|
||||
|
||||
struct AstFClose : public AstNodeStmt {
|
||||
AstFClose(FileLine* fileline, AstNodeVarRef* filep)
|
||||
// Parents: stmtlist
|
||||
// Children: file which must be a varref
|
||||
AstFClose(FileLine* fileline, AstNode* filep)
|
||||
: AstNodeStmt (fileline) {
|
||||
setNOp2p(filep);
|
||||
}
|
||||
|
|
@ -1224,7 +1271,7 @@ struct AstFClose : public AstNodeStmt {
|
|||
virtual bool isUnlikely() const { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
AstNodeVarRef* filep() const { return op2p()->castVarRef(); }
|
||||
AstNode* filep() const { return op2p(); }
|
||||
void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); }
|
||||
};
|
||||
|
||||
|
|
@ -1247,7 +1294,7 @@ struct AstFOpen : public AstNodeStmt {
|
|||
virtual bool isUnlikely() const { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
AstNodeVarRef* filep() const { return op1p()->castVarRef(); }
|
||||
AstNode* filep() const { return op1p(); }
|
||||
AstNode* filenamep() const { return op2p(); }
|
||||
AstNode* modep() const { return op3p(); }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,236 @@
|
|||
// $Id$
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Parse module/signal name references
|
||||
//
|
||||
// Code available from: http://www.veripool.com/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
// LinkParse TRANSFORMATIONS:
|
||||
// Top-down traversal
|
||||
// Replace ParseRef with VarRef, VarXRef, FuncRef or TaskRef
|
||||
// TASKREF(PARSEREF(DOT(TEXTa,TEXTb))) -> TASKREF(a,b)
|
||||
// PARSEREF(TEXTa) -> VARREF(a)
|
||||
// PARSEREF(DOT(TEXTa,TEXTb)) -> VARXREF("a","b")
|
||||
// PARSEREF(DOT(DOT(TEXTa,TEXTb),TEXTc)) -> VARXREF("a.b","c")
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3LinkParse.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
//######################################################################
|
||||
// Link state, as a visitor of each AstNode
|
||||
|
||||
class LinkParseVisitor : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Cleared on netlist
|
||||
// AstNode::user() -> bool. True if processed
|
||||
|
||||
// STATE
|
||||
string m_dotText; // Dotted module text we are building for a dotted node, passed up
|
||||
bool m_inModDot; // We're inside module part of dotted name
|
||||
AstParseRefExp m_exp; // Type of data we're looking for
|
||||
AstText* m_baseTextp; // Lowest TEXT node that needs replacement with varref
|
||||
|
||||
//int debug() { return 9; }
|
||||
|
||||
// METHODS
|
||||
void checkExpected(AstNode* nodep) {
|
||||
if (m_exp != AstParseRefExp::NONE) {
|
||||
nodep->v3fatalSrc("Tree syntax error: Not expecting "<<nodep->type()<<" under a "<<nodep->backp()->type());
|
||||
m_exp = AstParseRefExp::NONE;
|
||||
}
|
||||
}
|
||||
|
||||
// VISITs
|
||||
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
|
||||
if (!nodep->user()) {
|
||||
nodep->user(true); // Process only once.
|
||||
UINFO(5," "<<nodep<<endl);
|
||||
checkExpected(nodep);
|
||||
// Due to a need to get the arguments, the ParseRefs are under here,
|
||||
// rather then the NodeFTaskRef under the ParseRef.
|
||||
if (nodep->namep()) {
|
||||
m_exp = AstParseRefExp::FUNC;
|
||||
nodep->namep()->accept(*this); // No next, we don't want to do the edit
|
||||
m_exp = AstParseRefExp::NONE;
|
||||
if (!m_baseTextp) nodep->v3fatalSrc("No TEXT found to indicate function name");
|
||||
nodep->name(m_baseTextp->text());
|
||||
nodep->dotted(m_dotText);
|
||||
nodep->namep()->unlinkFrBack()->deleteTree(); m_baseTextp=NULL;
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstParseRef* nodep, AstNUser*) {
|
||||
// VarRef: Parse its reference
|
||||
UINFO(5," "<<nodep<<endl);
|
||||
// May be a varref inside a select, etc, so save state and recurse
|
||||
{
|
||||
// Replace the parsed item with its child IE the selection tree down to the varref itself
|
||||
// Do this before iterating, so we don't have to process the edited tree twice
|
||||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
nodep->replaceWith(lhsp);
|
||||
|
||||
// Process lower nodes
|
||||
m_dotText = "";
|
||||
m_baseTextp = NULL;
|
||||
if (m_exp == AstParseRefExp::FUNC) {
|
||||
lhsp->accept(*this);
|
||||
// Return m_dotText to invoker
|
||||
} else if (nodep->expect() == AstParseRefExp::VAR_MEM
|
||||
|| nodep->expect() == AstParseRefExp::VAR_ANY) {
|
||||
m_exp = nodep->expect();
|
||||
lhsp->accept(*this);
|
||||
m_exp = AstParseRefExp::NONE;
|
||||
if (!m_baseTextp) nodep->v3fatalSrc("No TEXT found to indicate function name");
|
||||
if (m_dotText == "") {
|
||||
AstNode* newp = new AstVarRef(nodep->fileline(), m_baseTextp->text(), false); // lvalue'ness computed later
|
||||
m_baseTextp->replaceWith(newp); m_baseTextp->deleteTree(); m_baseTextp=NULL;
|
||||
} else {
|
||||
AstNode* newp = new AstVarXRef(nodep->fileline(), m_baseTextp->text(), m_dotText, false); // lvalue'ness computed later
|
||||
m_baseTextp->replaceWith(newp); m_baseTextp->deleteTree(); m_baseTextp=NULL;
|
||||
}
|
||||
} else {
|
||||
nodep->v3fatalSrc("Unknown ParseRefExp type\n");
|
||||
}
|
||||
}
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
virtual void visit(AstDot* nodep, AstNUser*) {
|
||||
UINFO(5," "<<nodep<<endl);
|
||||
if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
||||
m_dotText = "";
|
||||
nodep->lhsp()->iterateAndNext(*this);
|
||||
string namelhs = m_dotText;
|
||||
|
||||
m_dotText = "";
|
||||
nodep->rhsp()->iterateAndNext(*this);
|
||||
m_dotText = namelhs + "." + m_dotText;
|
||||
} else { // Not in ModDot, so this is {modulepart} DOT {name}
|
||||
m_inModDot = true;
|
||||
m_dotText = "";
|
||||
nodep->lhsp()->iterateAndNext(*this);
|
||||
string namelhs = m_dotText;
|
||||
|
||||
m_inModDot = false;
|
||||
m_dotText = "";
|
||||
nodep->rhsp()->iterateAndNext(*this);
|
||||
m_dotText = namelhs;
|
||||
|
||||
nodep->replaceWith(nodep->rhsp()->unlinkFrBack()); nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstSelBit* nodep, AstNUser*) {
|
||||
if (!nodep->user()) {
|
||||
nodep->user(true); // Process only once.
|
||||
if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
||||
m_dotText = "";
|
||||
nodep->lhsp()->iterateAndNext(*this);
|
||||
if (AstConst* constp = nodep->rhsp()->castConst()) {
|
||||
m_dotText = m_dotText+"__BRA__"+cvtToStr(constp->asInt())+"__KET__";
|
||||
} else {
|
||||
nodep->v3error("Unsupported: Non-constant inside []'s in the cell part of a dotted reference");
|
||||
}
|
||||
// And pass up m_dotText
|
||||
} else if (m_exp==AstParseRefExp::FUNC) {
|
||||
nodep->v3error("Syntax Error: Range selection '[]' is not allowed as part of function names");
|
||||
} else {
|
||||
nodep->lhsp()->iterateAndNext(*this);
|
||||
AstParseRefExp lastExp = m_exp;
|
||||
AstText* lasttextp = m_baseTextp;
|
||||
{
|
||||
m_exp = AstParseRefExp::NONE;
|
||||
nodep->rhsp()->iterateAndNext(*this);
|
||||
}
|
||||
m_baseTextp = lasttextp;
|
||||
m_exp = lastExp;
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodePreSel* nodep, AstNUser*) {
|
||||
// Excludes simple AstSel, see above
|
||||
if (!nodep->user()) {
|
||||
nodep->user(true); // Process only once.
|
||||
if (m_inModDot) { // Already under dot, so this is {modulepart} DOT {modulepart}
|
||||
nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed in the cell part of a dotted reference");
|
||||
} else if (m_exp==AstParseRefExp::FUNC) {
|
||||
nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed as part of function names");
|
||||
} else if (m_exp==AstParseRefExp::VAR_MEM) {
|
||||
nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed when expecting memory reference");
|
||||
} else {
|
||||
nodep->lhsp()->iterateAndNext(*this);
|
||||
AstParseRefExp lastExp = m_exp;
|
||||
AstText* lasttextp = m_baseTextp;
|
||||
{
|
||||
m_exp = AstParseRefExp::NONE;
|
||||
nodep->rhsp()->iterateAndNext(*this);
|
||||
nodep->thsp()->iterateAndNext(*this);
|
||||
}
|
||||
m_baseTextp = lasttextp;
|
||||
m_exp = lastExp;
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstText* nodep, AstNUser*) {
|
||||
if (!nodep->user()) {
|
||||
nodep->user(true); // Process only once.
|
||||
if (m_exp != AstParseRefExp::NONE) {
|
||||
UINFO(7," "<<nodep<<endl);
|
||||
if (m_inModDot) { // Dotted part, just pass up
|
||||
m_dotText = nodep->text();
|
||||
} else {
|
||||
if (m_baseTextp) nodep->v3fatalSrc("Multiple low-level ParseRef text's found; which one is var name?");
|
||||
m_baseTextp = nodep;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
// Default: Just iterate
|
||||
checkExpected(nodep); // So we detect node types we forgot to list here
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
LinkParseVisitor(AstNetlist* rootp) {
|
||||
m_inModDot = false;
|
||||
m_exp = AstParseRefExp::NONE;
|
||||
m_baseTextp = NULL;
|
||||
AstNode::userClearTree(); // userp() used on entire tree
|
||||
rootp->accept(*this);
|
||||
}
|
||||
virtual ~LinkParseVisitor() {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Link class functions
|
||||
|
||||
void V3LinkParse::linkParse(AstNetlist* rootp) {
|
||||
UINFO(4,__FUNCTION__<<": "<<endl);
|
||||
LinkParseVisitor visitor(rootp);
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// $Id$ //-*- C++ -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Link modules/signals together
|
||||
//
|
||||
// Code available from: http://www.veripool.com/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef _V3LINKPARSE_H_
|
||||
#define _V3LINKPARSE_H_ 1
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3Error.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3LinkParse {
|
||||
public:
|
||||
static void linkParse(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
|
@ -97,6 +97,18 @@ private:
|
|||
m_ftaskp = NULL;
|
||||
}
|
||||
|
||||
virtual void visit(AstSenItem* nodep, AstNUser*) {
|
||||
// Remove bit selects, and bark if it's not a simple variable
|
||||
nodep->iterateChildren(*this);
|
||||
if (AstSel* selp = nodep->sensp()->castSel()) {
|
||||
AstNode* fromp = selp->fromp()->unlinkFrBack();
|
||||
selp->replaceWith(fromp); selp->deleteTree(); selp=NULL;
|
||||
}
|
||||
if (!nodep->sensp()->castNodeVarRef()) {
|
||||
nodep->v3error("Unsupported: Complex statement in sensitivity list");
|
||||
}
|
||||
}
|
||||
|
||||
void iterateSelTriop(AstNodePreSel* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
|
@ -284,11 +296,15 @@ private:
|
|||
}
|
||||
virtual void visit(AstFOpen* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
expectDescriptor(nodep, nodep->filep());
|
||||
expectDescriptor(nodep, nodep->filep()->castNodeVarRef());
|
||||
}
|
||||
virtual void visit(AstFClose* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
expectDescriptor(nodep, nodep->filep());
|
||||
expectDescriptor(nodep, nodep->filep()->castNodeVarRef());
|
||||
}
|
||||
virtual void visit(AstDisplay* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->filep()) expectDescriptor(nodep, nodep->filep()->castNodeVarRef());
|
||||
}
|
||||
|
||||
virtual void visit(AstScCtor* nodep, AstNUser*) {
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@
|
|||
#include "V3LinkCells.h"
|
||||
#include "V3LinkDot.h"
|
||||
#include "V3LinkLevel.h"
|
||||
#include "V3LinkParse.h"
|
||||
#include "V3LinkLValue.h"
|
||||
#include "V3LinkResolve.h"
|
||||
#include "V3Localize.h"
|
||||
|
|
@ -107,6 +108,8 @@ void process () {
|
|||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("cells.tree"));
|
||||
V3Error::abortIfErrors();
|
||||
|
||||
// Convert parseref's to varrefs, and other directly post parsing fixups
|
||||
V3LinkParse::linkParse(v3Global.rootp());
|
||||
// Cross-link signal names
|
||||
V3Link::link(v3Global.rootp());
|
||||
// Cross-link dotted hierarchical references
|
||||
|
|
|
|||
102
src/verilog.y
102
src/verilog.y
|
|
@ -18,13 +18,6 @@
|
|||
//*************************************************************************
|
||||
// Original code here by Paul Wasson and Duane Galbi
|
||||
//*************************************************************************
|
||||
//General Hints
|
||||
//-----------------
|
||||
// 1) {A,B} <= HI; -> expands to two DISTINCT assignment nodes in AST tree
|
||||
//
|
||||
// 2) inv a(in1,out1), b(in2,out2); -> expanded into two AST instance_nodes
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
%{
|
||||
/* $Id$ */
|
||||
|
|
@ -121,6 +114,7 @@ class AstSenTree;
|
|||
AstVar* varp;
|
||||
AstVarRef* varrefp;
|
||||
AstNodeVarRef* varnodep;
|
||||
AstParseRef* parserefp;
|
||||
}
|
||||
|
||||
%token<nump> yINTNUM
|
||||
|
|
@ -233,7 +227,6 @@ class AstSenTree;
|
|||
%type<nodep> instnameList instname
|
||||
%type<pinp> cellpinList cellpinlist2 cellpinitemE instparamListE
|
||||
%type<nodep> defpList defpOne
|
||||
%type<nodep> ignoreRangeE
|
||||
%type<sentreep> sensitivityE
|
||||
%type<senitemp> senList senitem senitemEdge
|
||||
%type<nodep> stmtBlock stmtList stmt stateCaseForIf
|
||||
|
|
@ -243,13 +236,13 @@ class AstSenTree;
|
|||
%type<nodep> casecondList assignList assignOne
|
||||
%type<nodep> constExpr exprNoStr expr exprPsl exprStrText
|
||||
%type<nodep> eList cateList cStrList
|
||||
%type<strp> pathDotted
|
||||
%type<varrefp> varRefBase
|
||||
%type<varnodep> idVarXRef
|
||||
%type<parserefp> varRefMem
|
||||
%type<parserefp> varRefDotBit
|
||||
%type<taskrefp> taskRef
|
||||
%type<funcrefp> funcRef
|
||||
%type<nodep> varRefDotBit
|
||||
%type<nodep> idArrayed
|
||||
%type<nodep> idDotted
|
||||
%type<nodep> strAsInt strAsText concIdList
|
||||
%type<nodep> taskDecl
|
||||
%type<nodep> varDeclList funcDecl funcVarList funcVar
|
||||
|
|
@ -628,16 +621,12 @@ senList: senitem { $$ = $1; }
|
|||
;
|
||||
|
||||
senitem: senitemEdge { $$ = $1; }
|
||||
| idVarXRef ignoreRangeE { $$ = new AstSenItem(CRELINE(),AstEdgeType::ANYEDGE,$1); }
|
||||
//FIX need range ignoring to be stripped later, this was simple varXRef
|
||||
| varRefDotBit { $$ = new AstSenItem(CRELINE(),AstEdgeType::ANYEDGE,$1); }
|
||||
;
|
||||
|
||||
senitemEdge: yPOSEDGE idVarXRef ignoreRangeE { $$ = new AstSenItem($1,AstEdgeType::POSEDGE,$2); }
|
||||
| yNEGEDGE idVarXRef ignoreRangeE { $$ = new AstSenItem($1,AstEdgeType::NEGEDGE,$2); }
|
||||
;
|
||||
|
||||
ignoreRangeE: /* empty */ { $$ = NULL; } /* ignored */
|
||||
| '[' expr ']' { $$ = NULL; } /* ignored */
|
||||
| '[' expr ':' expr ']' { $$ = NULL; } /* ignored */
|
||||
senitemEdge: yPOSEDGE varRefDotBit { $$ = new AstSenItem($1,AstEdgeType::POSEDGE,$2); }
|
||||
| yNEGEDGE varRefDotBit { $$ = new AstSenItem($1,AstEdgeType::NEGEDGE,$2); }
|
||||
;
|
||||
|
||||
stmtBlock: stmt { $$ = $1; }
|
||||
|
|
@ -663,7 +652,7 @@ stmt: ';' { $$ = NULL; }
|
|||
| '{' concIdList '}' yLTE delayE expr ';' { $$ = new AstAssignDly($4,$2,$6); }
|
||||
| '{' concIdList '}' '=' delayE expr ';' { $$ = new AstAssign($4,$2,$6); }
|
||||
| yD_C '(' cStrList ')' ';' { $$ = (v3Global.opt.ignc() ? NULL : new AstUCStmt($1,$3)); }
|
||||
| yD_FCLOSE '(' idVarXRef ')' ';' { $$ = new AstFClose($1, $3); }
|
||||
| yD_FCLOSE '(' varRefDotBit ')' ';' { $$ = new AstFClose($1, $3); }
|
||||
| yD_FINISH ';' { $$ = new AstFinish($1); }
|
||||
| yD_STOP ';' { $$ = new AstStop($1); }
|
||||
| yVL_COVER_OFF { $$ = new AstPragma($1,AstPragmaType::COVERAGE_BLOCK_OFF); }
|
||||
|
|
@ -675,16 +664,16 @@ stmt: ';' { $$ = NULL; }
|
|||
| yD_DISPLAY '(' ySTRING ',' eList ')' ';' { $$ = new AstDisplay($1,'\n',*$3,NULL,$5); }
|
||||
| yD_WRITE '(' ySTRING ')' ';' { $$ = new AstDisplay($1,'\0',*$3,NULL,NULL); }
|
||||
| yD_WRITE '(' ySTRING ',' eList ')' ';' { $$ = new AstDisplay($1,'\0',*$3,NULL,$5); }
|
||||
| yD_FDISPLAY '(' idVarXRef ',' ySTRING ')' ';' { $$ = new AstDisplay($1,'\n',*$5,$3,NULL); }
|
||||
| yD_FDISPLAY '(' idVarXRef ',' ySTRING ',' eList ')' ';' { $$ = new AstDisplay($1,'\n',*$5,$3,$7); }
|
||||
| yD_FWRITE '(' idVarXRef ',' ySTRING ')' ';' { $$ = new AstDisplay($1,'\0',*$5,$3,NULL); }
|
||||
| yD_FWRITE '(' idVarXRef ',' ySTRING ',' eList ')' ';' { $$ = new AstDisplay($1,'\0',*$5,$3,$7); }
|
||||
| yD_READMEMB '(' expr ',' idArrayed ')' ';' { $$ = new AstReadMem($1,false,$3,$5,NULL,NULL); }
|
||||
| yD_READMEMB '(' expr ',' idArrayed ',' expr ')' ';' { $$ = new AstReadMem($1,false,$3,$5,$7,NULL); }
|
||||
| yD_READMEMB '(' expr ',' idArrayed ',' expr ',' expr ')' ';' { $$ = new AstReadMem($1,false,$3,$5,$7,$9); }
|
||||
| yD_READMEMH '(' expr ',' idArrayed ')' ';' { $$ = new AstReadMem($1,true, $3,$5,NULL,NULL); }
|
||||
| yD_READMEMH '(' expr ',' idArrayed ',' expr ')' ';' { $$ = new AstReadMem($1,true, $3,$5,$7,NULL); }
|
||||
| yD_READMEMH '(' expr ',' idArrayed ',' expr ',' expr ')' ';' { $$ = new AstReadMem($1,true, $3,$5,$7,$9); }
|
||||
| yD_FDISPLAY '(' varRefDotBit ',' ySTRING ')' ';' { $$ = new AstDisplay($1,'\n',*$5,$3,NULL); }
|
||||
| yD_FDISPLAY '(' varRefDotBit ',' ySTRING ',' eList ')' ';' { $$ = new AstDisplay($1,'\n',*$5,$3,$7); }
|
||||
| yD_FWRITE '(' varRefDotBit ',' ySTRING ')' ';' { $$ = new AstDisplay($1,'\0',*$5,$3,NULL); }
|
||||
| yD_FWRITE '(' varRefDotBit ',' ySTRING ',' eList ')' ';' { $$ = new AstDisplay($1,'\0',*$5,$3,$7); }
|
||||
| yD_READMEMB '(' expr ',' varRefMem ')' ';' { $$ = new AstReadMem($1,false,$3,$5,NULL,NULL); }
|
||||
| yD_READMEMB '(' expr ',' varRefMem ',' expr ')' ';' { $$ = new AstReadMem($1,false,$3,$5,$7,NULL); }
|
||||
| yD_READMEMB '(' expr ',' varRefMem ',' expr ',' expr ')' ';' { $$ = new AstReadMem($1,false,$3,$5,$7,$9); }
|
||||
| yD_READMEMH '(' expr ',' varRefMem ')' ';' { $$ = new AstReadMem($1,true, $3,$5,NULL,NULL); }
|
||||
| yD_READMEMH '(' expr ',' varRefMem ',' expr ')' ';' { $$ = new AstReadMem($1,true, $3,$5,$7,NULL); }
|
||||
| yD_READMEMH '(' expr ',' varRefMem ',' expr ',' expr ')' ';' { $$ = new AstReadMem($1,true, $3,$5,$7,$9); }
|
||||
;
|
||||
|
||||
stateCaseForIf: caseStmt caseAttrE caseList yENDCASE { $$ = $1; $1->addItemsp($3); }
|
||||
|
|
@ -956,37 +945,40 @@ specifyJunk: dterm {} /* ignored */
|
|||
|
||||
//************************************************
|
||||
// IDs
|
||||
pathDotted: yID { $$ = $1; }
|
||||
| pathDotted '.' yID { $$ = V3Read::newString(*$1+string(".")+*$3); }
|
||||
;
|
||||
|
||||
varRefBase: yID { $$ = new AstVarRef(CRELINE(),*$1,false);}
|
||||
;
|
||||
|
||||
idVarXRef: varRefBase { $$ = $1; }
|
||||
| pathDotted '.' yID { $$ = new AstVarXRef(CRELINE(),*$3,*$1,false);}
|
||||
;
|
||||
|
||||
taskRef: yID { $$ = new AstTaskRef(CRELINE(),*$1,"",NULL);}
|
||||
| yID '(' eList ')' { $$ = new AstTaskRef(CRELINE(),*$1,"",$3);}
|
||||
| pathDotted '.' yID { $$ = new AstTaskRef(CRELINE(),*$3,*$1,NULL);}
|
||||
| pathDotted '.' yID '(' eList ')' { $$ = new AstTaskRef(CRELINE(),*$3,*$1,$5);}
|
||||
;
|
||||
|
||||
funcRef: yID '(' eList ')' { $$ = new AstFuncRef($2,*$1,"",$3); }
|
||||
| pathDotted '.' yID '(' eList ')' { $$ = new AstFuncRef($4,*$3,*$1,$5); }
|
||||
;
|
||||
|
||||
idArrayed: idVarXRef { $$ = $1; }
|
||||
| idArrayed '[' expr ']' { $$ = new AstSelBit($2,$1,$3); } // Or AstArraySel, don't know yet.
|
||||
;
|
||||
|
||||
varRefDotBit: idArrayed { $$ = $1; }
|
||||
// Single component of dotted path, maybe [#].
|
||||
// Due to lookahead constraints, we can't know if [:] or [+:] are valid (last dotted part),
|
||||
// we'll assume so and cleanup later.
|
||||
idArrayed: yID { $$ = new AstText(CRELINE(),*$1); }
|
||||
| idArrayed '[' expr ']' { $$ = new AstSelBit($2,$1,$3); } // Or AstArraySel, don't know yet.
|
||||
| idArrayed '[' constExpr ':' constExpr ']' { $$ = new AstSelExtract($2,$1,$3,$5); }
|
||||
| idArrayed '[' expr yPLUSCOLON constExpr ']' { $$ = new AstSelPlus($2,$1,$3,$5); }
|
||||
| idArrayed '[' expr yMINUSCOLON constExpr ']' { $$ = new AstSelMinus($2,$1,$3,$5); }
|
||||
;
|
||||
|
||||
idDotted: idArrayed { $$ = $1; }
|
||||
| idDotted '.' idArrayed { $$ = new AstDot($2,$1,$3); }
|
||||
;
|
||||
|
||||
// VarRef without any dots or vectorizaion
|
||||
varRefBase: yID { $$ = new AstVarRef(CRELINE(),*$1,false);}
|
||||
;
|
||||
|
||||
// VarRef to a Memory
|
||||
varRefMem: idDotted { $$ = new AstParseRef($1->fileline(), AstParseRefExp::VAR_MEM, $1); }
|
||||
;
|
||||
|
||||
// VarRef to dotted, and/or arrayed, and/or bit-ranged variable
|
||||
varRefDotBit: idDotted { $$ = new AstParseRef($1->fileline(), AstParseRefExp::VAR_ANY, $1); }
|
||||
;
|
||||
|
||||
taskRef: idDotted { $$ = new AstTaskRef(CRELINE(),new AstParseRef($1->fileline(), AstParseRefExp::TASK, $1),NULL);}
|
||||
| idDotted '(' eList ')' { $$ = new AstTaskRef(CRELINE(),new AstParseRef($1->fileline(), AstParseRefExp::TASK, $1),$3);}
|
||||
;
|
||||
|
||||
funcRef: idDotted '(' eList ')' { $$ = new AstFuncRef($2,new AstParseRef($1->fileline(), AstParseRefExp::FUNC, $1), $3); }
|
||||
;
|
||||
|
||||
strAsInt: ySTRING { $$ = new AstConst(CRELINE(),V3Number(V3Number::VerilogString(),CRELINE(),V3Parse::deQuote(CRELINE(),*$1)));}
|
||||
;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// $Id:$
|
||||
// $Id$
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
|
|
@ -33,7 +33,7 @@ module muxtop (
|
|||
output reg [ 31:0 ] o
|
||||
);
|
||||
|
||||
always @ ( i )
|
||||
always @ ( i[43:0] ) // Verify we ignore ranges on always statement sense lists
|
||||
o = MUX( i[39:0] );
|
||||
|
||||
function [31:0] MUX;
|
||||
|
|
|
|||
Loading…
Reference in New Issue