mirror of
https://github.com/verilator/verilator.git
synced 2026-10-05 17:43:31 +02:00
Add --clk and related optimizations, msg1533.
This commit is contained in:
@@ -176,6 +176,10 @@ string AstNode::prettyName(const string& namein) {
|
||||
pretty += ".";
|
||||
pos += 7;
|
||||
}
|
||||
else if (0==strncmp(pos,"->",2)) {
|
||||
pretty += ".";
|
||||
pos += 2;
|
||||
}
|
||||
else if (0==strncmp(pos,"__PVT__",7)) {
|
||||
pretty += "";
|
||||
pos += 7;
|
||||
|
||||
+36
-2
@@ -257,7 +257,9 @@ public:
|
||||
VAR_PUBLIC_FLAT_RW, // V3LinkParse moves to AstVar::sigPublic
|
||||
VAR_ISOLATE_ASSIGNMENTS, // V3LinkParse moves to AstVar::attrIsolateAssign
|
||||
VAR_SC_BV, // V3LinkParse moves to AstVar::attrScBv
|
||||
VAR_SFORMAT // V3LinkParse moves to AstVar::attrSFormat
|
||||
VAR_SFORMAT, // V3LinkParse moves to AstVar::attrSFormat
|
||||
VAR_CLOCKER, // V3LinkParse moves to AstVar::attrClocker
|
||||
VAR_NO_CLOCKER // V3LinkParse moves to AstVar::attrClocker
|
||||
};
|
||||
enum en m_e;
|
||||
const char* ascii() const {
|
||||
@@ -270,7 +272,8 @@ public:
|
||||
"MEMBER_BASE",
|
||||
"VAR_BASE", "VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC",
|
||||
"VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD","VAR_PUBLIC_FLAT_RW",
|
||||
"VAR_ISOLATE_ASSIGNMENTS", "VAR_SC_BV", "VAR_SFORMAT"
|
||||
"VAR_ISOLATE_ASSIGNMENTS", "VAR_SC_BV", "VAR_SFORMAT", "VAR_CLOCKER",
|
||||
"VAR_NO_CLOCKER"
|
||||
};
|
||||
return names[m_e];
|
||||
};
|
||||
@@ -485,6 +488,37 @@ public:
|
||||
|
||||
//######################################################################
|
||||
|
||||
class AstVarAttrClocker {
|
||||
public:
|
||||
enum en {
|
||||
CLOCKER_UNKNOWN=0,
|
||||
CLOCKER_YES,
|
||||
CLOCKER_NO,
|
||||
_ENUM_END
|
||||
};
|
||||
enum en m_e;
|
||||
// CONSTRUCTOR - note defaults to *UNKNOWN*
|
||||
inline AstVarAttrClocker () : m_e(CLOCKER_UNKNOWN) {}
|
||||
inline AstVarAttrClocker (en _e) : m_e(_e) {}
|
||||
explicit inline AstVarAttrClocker (int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en () const { return m_e; }
|
||||
AstVarAttrClocker invert() const {
|
||||
if (m_e==CLOCKER_YES) return CLOCKER_NO;
|
||||
else if (m_e==CLOCKER_NO) return CLOCKER_YES;
|
||||
else return m_e;
|
||||
}
|
||||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
"","clker","non_clker"};
|
||||
return names[m_e]; }
|
||||
};
|
||||
inline bool operator== (AstVarAttrClocker lhs, AstVarAttrClocker rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator== (AstVarAttrClocker lhs, AstVarAttrClocker::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator== (AstVarAttrClocker::en lhs, AstVarAttrClocker rhs) { return (lhs == rhs.m_e); }
|
||||
inline ostream& operator<<(ostream& os, AstVarAttrClocker rhs) { return os<<rhs.ascii(); }
|
||||
|
||||
//######################################################################
|
||||
|
||||
class VAlwaysKwd {
|
||||
public:
|
||||
enum en {
|
||||
|
||||
+4
-2
@@ -942,6 +942,7 @@ private:
|
||||
bool m_isIfaceParent:1; // dtype is reference to interface present in this module
|
||||
bool m_noSubst:1; // Do not substitute out references
|
||||
bool m_trace:1; // Trace this variable
|
||||
AstVarAttrClocker m_attrClocker;
|
||||
|
||||
void init() {
|
||||
m_input=false; m_output=false; m_tristate=false; m_declOutput=false;
|
||||
@@ -952,8 +953,7 @@ private:
|
||||
m_funcLocal=false; m_funcReturn=false;
|
||||
m_attrClockEn=false; m_attrScBv=false; m_attrIsolateAssign=false; m_attrSFormat=false;
|
||||
m_fileDescr=false; m_isConst=false; m_isStatic=false; m_isPulldown=false; m_isPullup=false;
|
||||
m_isIfaceParent=false;
|
||||
m_noSubst=false;
|
||||
m_isIfaceParent=false; m_attrClocker=AstVarAttrClocker::CLOCKER_UNKNOWN; m_noSubst=false;
|
||||
m_trace=false;
|
||||
}
|
||||
public:
|
||||
@@ -1026,6 +1026,7 @@ public:
|
||||
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
|
||||
AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
|
||||
void attrClockEn(bool flag) { m_attrClockEn = flag; }
|
||||
void attrClocker(AstVarAttrClocker flag) { m_attrClocker = flag; }
|
||||
void attrFileDescr(bool flag) { m_fileDescr = flag; }
|
||||
void attrScClocked(bool flag) { m_scClocked = flag; }
|
||||
void attrScBv(bool flag) { m_attrScBv = flag; }
|
||||
@@ -1105,6 +1106,7 @@ public:
|
||||
bool attrScClocked() const { return m_scClocked; }
|
||||
bool attrSFormat() const { return m_attrSFormat; }
|
||||
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
|
||||
AstVarAttrClocker attrClocker() const { return m_attrClocker; }
|
||||
virtual string verilogKwd() const;
|
||||
void propagateAttrFrom(AstVar* fromp) {
|
||||
// This is getting connected to fromp; keep attributes
|
||||
|
||||
+3
-2
@@ -65,6 +65,7 @@ public:
|
||||
CASEWITHX, // Case with X values
|
||||
CASEX, // Casex
|
||||
CDCRSTLOGIC, // Logic in async reset path
|
||||
CLKDATA, // Clock used as data
|
||||
CMPCONST, // Comparison is constant due to limited range
|
||||
COMBDLY, // Combinatorial delayed assignment
|
||||
DEFPARAM, // Style: Defparam
|
||||
@@ -119,8 +120,8 @@ public:
|
||||
" EC_FIRST_WARN",
|
||||
"ALWCOMBORDER", "ASSIGNDLY", "ASSIGNIN",
|
||||
"BLKANDNBLK", "BLKSEQ",
|
||||
"CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CDCRSTLOGIC", "CMPCONST",
|
||||
"COMBDLY", "DEFPARAM", "DECLFILENAME",
|
||||
"CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CDCRSTLOGIC", "CLKDATA",
|
||||
"CMPCONST", "COMBDLY", "DEFPARAM", "DECLFILENAME",
|
||||
"ENDLABEL", "GENCLK",
|
||||
"IFDEPTH", "IMPERFECTSCH", "IMPLICIT", "IMPURE",
|
||||
"INCABSPATH", "INITIALDLY",
|
||||
|
||||
@@ -237,6 +237,16 @@ private:
|
||||
m_varp->attrScBv(true);
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_CLOCKER) {
|
||||
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
|
||||
m_varp->attrClocker(AstVarAttrClocker::CLOCKER_YES);
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_NO_CLOCKER) {
|
||||
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
|
||||
m_varp->attrClocker(AstVarAttrClocker::CLOCKER_NO);
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstAlwaysPublic* nodep, AstNUser*) {
|
||||
|
||||
+24
-1
@@ -157,12 +157,27 @@ bool V3Options::isFuture(const string& flag) const {
|
||||
bool V3Options::isLibraryFile(const string& filename) const {
|
||||
return m_libraryFiles.find(filename) != m_libraryFiles.end();
|
||||
}
|
||||
|
||||
void V3Options::addLibraryFile(const string& filename) {
|
||||
if (m_libraryFiles.find(filename) == m_libraryFiles.end()) {
|
||||
m_libraryFiles.insert(filename);
|
||||
}
|
||||
}
|
||||
bool V3Options::isClocker(const string& signame) const {
|
||||
return m_clockers.find(signame) != m_clockers.end();
|
||||
}
|
||||
void V3Options::addClocker(const string& signame) {
|
||||
if (m_clockers.find(signame) == m_clockers.end()) {
|
||||
m_clockers.insert(signame);
|
||||
}
|
||||
}
|
||||
bool V3Options::isNoClocker(const string& signame) const {
|
||||
return m_noClockers.find(signame) != m_noClockers.end();
|
||||
}
|
||||
void V3Options::addNoClocker(const string& signame) {
|
||||
if (m_noClockers.find(signame) == m_noClockers.end()) {
|
||||
m_noClockers.insert(signame);
|
||||
}
|
||||
}
|
||||
void V3Options::addVFile(const string& filename) {
|
||||
// We use a list for v files, because it's legal to have includes
|
||||
// in a specific order and multiple of them.
|
||||
@@ -798,6 +813,14 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
|
||||
shift;
|
||||
V3Options::addLibraryFile(parseFileArg(optdir,argv[i]));
|
||||
}
|
||||
else if ( !strcmp (sw, "-clk") && (i+1)<argc ) {
|
||||
shift;
|
||||
V3Options::addClocker(argv[i]);
|
||||
}
|
||||
else if ( !strcmp (sw, "-no-clk") && (i+1)<argc ) {
|
||||
shift;
|
||||
V3Options::addNoClocker(argv[i]);
|
||||
}
|
||||
else if ( !strcmp (sw, "-V") ) {
|
||||
showVersion(true);
|
||||
exit(0);
|
||||
|
||||
@@ -53,6 +53,8 @@ class V3Options {
|
||||
V3StringSet m_ldLibs; // argument: user LDFLAGS
|
||||
V3StringSet m_futures; // argument: -Wfuture- list
|
||||
V3StringSet m_libraryFiles; // argument: Verilog -v files
|
||||
V3StringSet m_clockers; // argument: Verilog -clk signals
|
||||
V3StringSet m_noClockers; // argument: Verilog -noclk signals
|
||||
V3StringList m_vFiles; // argument: Verilog files to read
|
||||
DebugSrcMap m_debugSrcs; // argument: --debugi-<srcfile>=<level>
|
||||
|
||||
@@ -184,6 +186,8 @@ class V3Options {
|
||||
void addCFlags(const string& filename);
|
||||
void addLdLibs(const string& filename);
|
||||
void addLibraryFile(const string& filename);
|
||||
void addClocker(const string& signame);
|
||||
void addNoClocker(const string& signame);
|
||||
void addVFile(const string& filename);
|
||||
|
||||
// ACCESSORS (options)
|
||||
@@ -270,6 +274,8 @@ class V3Options {
|
||||
|
||||
bool isFuture(const string& flag) const;
|
||||
bool isLibraryFile(const string& filename) const;
|
||||
bool isClocker(const string& signame) const;
|
||||
bool isNoClocker(const string& signame) const;
|
||||
|
||||
// ACCESSORS (optimization options)
|
||||
bool oAcycSimp() const { return m_oAcycSimp; }
|
||||
|
||||
+210
-1
@@ -241,6 +241,185 @@ struct OrderVarFanoutCmp {
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// The class is used for propagating the clocker attribute for further
|
||||
// avoiding marking clock signals as circular.
|
||||
// Transformation:
|
||||
// while (newClockerMarked)
|
||||
// check all assignments
|
||||
// if RHS is marked as clocker:
|
||||
// mark LHS as clocker as well.
|
||||
// newClockerMarked = true;
|
||||
//
|
||||
// In addition it also check whether clock and data signals are mixed, and
|
||||
// produce a CLKDATA warning if so.
|
||||
//
|
||||
class OrderClkMarkVisitor : public AstNVisitor {
|
||||
private:
|
||||
bool m_hasClk; // flag indicating whether there is clock signal on rhs
|
||||
bool m_inClocked; // Currently inside a sequential block
|
||||
bool m_newClkMarked; // Flag for deciding whether a new run is needed
|
||||
bool m_inAss; // Currently inside of a assignment
|
||||
int m_childClkWidth; // If in hasClk, width of clock signal in child
|
||||
int m_rightClkWidth; // Clk width on the RHS
|
||||
|
||||
// METHODS
|
||||
static int debug() {
|
||||
static int level = -1;
|
||||
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
|
||||
return level;
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
||||
m_hasClk = false;
|
||||
if (AstVarRef* varrefp = nodep->rhsp()->castVarRef()) {
|
||||
this->visit(varrefp, NULL);
|
||||
m_rightClkWidth = varrefp->width();
|
||||
if (varrefp->varp()->attrClocker() == AstVarAttrClocker::CLOCKER_YES) {
|
||||
if (m_inClocked) {
|
||||
varrefp->v3warn(CLKDATA, "Clock used as data (on rhs of assignment) in sequential block "<<varrefp<<endl);
|
||||
} else {
|
||||
m_hasClk = true;
|
||||
UINFO(5, "node is already marked as clocker "<<varrefp<<endl);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
m_inAss = true;
|
||||
m_childClkWidth = 0;
|
||||
nodep->rhsp()->iterateAndNext(*this);
|
||||
m_rightClkWidth = m_childClkWidth;
|
||||
m_inAss = false;
|
||||
}
|
||||
|
||||
// do the marking
|
||||
if (m_hasClk) {
|
||||
if (nodep->lhsp()->width() > m_rightClkWidth) {
|
||||
nodep->v3warn(CLKDATA, "Clock is assigned to part of data signal "<< nodep->lhsp()<<endl);
|
||||
UINFO(4, "CLKDATA: lhs with width " << nodep->lhsp()->width() <<endl);
|
||||
UINFO(4, " but rhs clock with width " << m_rightClkWidth <<endl);
|
||||
return; // skip the marking
|
||||
}
|
||||
|
||||
AstVarRef* lhsp = nodep->lhsp()->castVarRef();
|
||||
if (lhsp && (lhsp->varp()->attrClocker() == AstVarAttrClocker::CLOCKER_UNKNOWN)) {
|
||||
lhsp->varp()->attrClocker(AstVarAttrClocker::CLOCKER_YES); // mark as clocker
|
||||
m_newClkMarked = true; // enable a further run since new clocker is marked
|
||||
UINFO(5, "node is newly marked as clocker by assignment "<<lhsp<<endl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
if (m_inAss && nodep->varp()->attrClocker() == AstVarAttrClocker::CLOCKER_YES) {
|
||||
if (m_inClocked) {
|
||||
nodep->v3warn(CLKDATA, "Clock used as data (on rhs of assignment) in sequential block "<<nodep->prettyName());
|
||||
} else {
|
||||
m_hasClk = true;
|
||||
m_childClkWidth = nodep->width(); // Pass up
|
||||
UINFO(5, "node is already marked as clocker "<<nodep<<endl);
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstConcat* nodep, AstNUser* wp) {
|
||||
if (m_inAss) {
|
||||
nodep->lhsp()->iterateAndNext(*this);
|
||||
int lw = m_childClkWidth;
|
||||
nodep->rhsp()->iterateAndNext(*this);
|
||||
int rw = m_childClkWidth;
|
||||
m_childClkWidth = lw + rw; // Pass up
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeSel* nodep, AstNUser* wp) {
|
||||
if (m_inAss) {
|
||||
nodep->iterateChildren(*this);
|
||||
// Pass up result width
|
||||
if (m_childClkWidth > nodep->width()) m_childClkWidth = nodep->width();
|
||||
}
|
||||
}
|
||||
virtual void visit(AstSel* nodep, AstNUser*) {
|
||||
if (m_inAss) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (m_childClkWidth > nodep->width()) m_childClkWidth = nodep->width();
|
||||
}
|
||||
}
|
||||
virtual void visit(AstReplicate* nodep, AstNUser*) {
|
||||
if (m_inAss) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->rhsp()->castConst()) {
|
||||
m_childClkWidth = m_childClkWidth * nodep->rhsp()->castConst()->toUInt();
|
||||
} else {
|
||||
m_childClkWidth = nodep->width(); // can not check in this case.
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstActive* nodep, AstNUser*) {
|
||||
m_inClocked = nodep->hasClocked();
|
||||
nodep->iterateChildren(*this);
|
||||
m_inClocked = false;
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
OrderClkMarkVisitor(AstNode* nodep) {
|
||||
m_hasClk = false;
|
||||
m_inClocked = false;
|
||||
m_inAss = false;
|
||||
m_childClkWidth = 0;
|
||||
m_rightClkWidth = 0;
|
||||
do {
|
||||
m_newClkMarked = false;
|
||||
nodep->accept(*this);
|
||||
} while (m_newClkMarked);
|
||||
}
|
||||
virtual ~OrderClkMarkVisitor() {}
|
||||
};
|
||||
|
||||
|
||||
//######################################################################
|
||||
// The class used to check if the assignment has clocker inside.
|
||||
class OrderClkAssVisitor : public AstNVisitor {
|
||||
private:
|
||||
bool m_clkAss; // There is signals marked as clocker in the assignment
|
||||
|
||||
// METHODS
|
||||
static int debug() {
|
||||
static int level = -1;
|
||||
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
|
||||
return level;
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
||||
if (AstVarRef* varrefp = nodep->lhsp()->castVarRef() )
|
||||
if (varrefp->varp()->attrClocker() == AstVarAttrClocker::CLOCKER_YES) {
|
||||
m_clkAss = true;
|
||||
UINFO(6, "node was marked as clocker "<<varrefp<<endl);
|
||||
}
|
||||
nodep->rhsp()->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
if (nodep->varp()->attrClocker() == AstVarAttrClocker::CLOCKER_YES) {
|
||||
m_clkAss = true;
|
||||
UINFO(6, "node was marked as clocker "<<nodep<<endl);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
OrderClkAssVisitor(AstNode* nodep) {
|
||||
m_clkAss = false;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~OrderClkAssVisitor() {}
|
||||
|
||||
// METHODS
|
||||
bool isClkAss() {return m_clkAss;}
|
||||
};
|
||||
|
||||
|
||||
//######################################################################
|
||||
// Order class functions
|
||||
@@ -280,6 +459,7 @@ private:
|
||||
AstActive* m_activep; // Current activation block
|
||||
bool m_inSenTree; // Underneath AstSenItem; any varrefs are clocks
|
||||
bool m_inClocked; // Underneath clocked block
|
||||
bool m_inClkAss; // Underneath AstAssign
|
||||
bool m_inPre; // Underneath AstAssignPre
|
||||
bool m_inPost; // Underneath AstAssignPost
|
||||
OrderLogicVertex* m_activeSenVxp; // Sensitivity vertex
|
||||
@@ -356,6 +536,15 @@ private:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool isClkAssign(AstNodeAssign* nodep) {
|
||||
if (AstVarRef* varrefp = nodep->lhsp()->castVarRef()) {
|
||||
if (varrefp->varp()->attrClocker() == AstVarAttrClocker::CLOCKER_YES) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void process();
|
||||
void processCircular();
|
||||
typedef deque<OrderEitherVertex*> VertexVec;
|
||||
@@ -650,6 +839,10 @@ private:
|
||||
// clock_enable attribute: user's worring about it for us
|
||||
con = false;
|
||||
}
|
||||
if (m_inClkAss && (varscp->varp()->attrClocker()) != AstVarAttrClocker::CLOCKER_YES) {
|
||||
con = false;
|
||||
UINFO(4, "nodep used as clock_enable "<<varscp<<" in "<<m_logicVxp->nodep()<<endl);
|
||||
}
|
||||
}
|
||||
if (gen) varscp->user4(varscp->user4() | VU_GEN);
|
||||
if (con) varscp->user4(varscp->user4() | VU_CON);
|
||||
@@ -672,7 +865,12 @@ private:
|
||||
<< varVxp << endl);
|
||||
varVxp->isDelayed(true);
|
||||
} else {
|
||||
new OrderComboCutEdge(&m_graph, m_logicVxp, varVxp);
|
||||
// If the lhs is a clocker, avoid marking that as circular by
|
||||
// putting a hard edge instead of normal cuttable
|
||||
if (varscp->varp()->attrClocker() == AstVarAttrClocker::CLOCKER_YES)
|
||||
new OrderEdge(&m_graph, m_logicVxp, varVxp, WEIGHT_NORMAL);
|
||||
else
|
||||
new OrderComboCutEdge(&m_graph, m_logicVxp, varVxp);
|
||||
}
|
||||
// For m_inPost:
|
||||
// Add edge consumed_var_POST->logic_vertex
|
||||
@@ -758,17 +956,26 @@ private:
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep, AstNUser*) {
|
||||
OrderClkAssVisitor visitor(nodep);
|
||||
m_inClkAss = visitor.isClkAss();
|
||||
iterateNewStmt(nodep);
|
||||
m_inClkAss = false;
|
||||
}
|
||||
virtual void visit(AstAssignPre* nodep, AstNUser*) {
|
||||
OrderClkAssVisitor visitor(nodep);
|
||||
m_inClkAss = visitor.isClkAss();
|
||||
m_inPre = true;
|
||||
iterateNewStmt(nodep);
|
||||
m_inPre = false;
|
||||
m_inClkAss = false;
|
||||
}
|
||||
virtual void visit(AstAssignPost* nodep, AstNUser*) {
|
||||
OrderClkAssVisitor visitor(nodep);
|
||||
m_inClkAss = visitor.isClkAss();
|
||||
m_inPost = true;
|
||||
iterateNewStmt(nodep);
|
||||
m_inPost = false;
|
||||
m_inClkAss = false;
|
||||
}
|
||||
virtual void visit(AstCoverToggle* nodep, AstNUser*) {
|
||||
iterateNewStmt(nodep);
|
||||
@@ -799,6 +1006,7 @@ public:
|
||||
m_activep = NULL;
|
||||
m_inSenTree = false;
|
||||
m_inClocked = false;
|
||||
m_inClkAss = false;
|
||||
m_inPre = m_inPost = false;
|
||||
m_comboDomainp = NULL;
|
||||
m_deleteDomainp = NULL;
|
||||
@@ -1449,6 +1657,7 @@ void OrderVisitor::process() {
|
||||
|
||||
void V3Order::orderAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
OrderClkMarkVisitor markVisitor(nodep);
|
||||
OrderVisitor visitor;
|
||||
visitor.main(nodep);
|
||||
}
|
||||
|
||||
@@ -243,6 +243,12 @@ private:
|
||||
UINFO(6," New scope "<<varscp<<endl);
|
||||
if (m_aboveCellp && !m_aboveCellp->isTrace()) varscp->trace(false);
|
||||
nodep->user1p(varscp);
|
||||
if (v3Global.opt.isClocker(varscp->prettyName())) {
|
||||
nodep->attrClocker(AstVarAttrClocker::CLOCKER_YES);
|
||||
}
|
||||
if (v3Global.opt.isNoClocker(varscp->prettyName())) {
|
||||
nodep->attrClocker(AstVarAttrClocker::CLOCKER_NO);
|
||||
}
|
||||
if (!m_scopep) nodep->v3fatalSrc("No scope for var");
|
||||
m_varScopes.insert(make_pair(make_pair(nodep, m_scopep), varscp));
|
||||
m_scopep->addVarp(varscp);
|
||||
|
||||
@@ -674,6 +674,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
"/*verilator public_flat_rw*/" { FL; return yVL_PUBLIC_FLAT_RW; } // The @(edge) is converted by the preproc
|
||||
"/*verilator public_module*/" { FL; return yVL_PUBLIC_MODULE; }
|
||||
"/*verilator sc_clock*/" { FL; return yVL_CLOCK; }
|
||||
"/*verilator clocker*/" { FL; return yVL_CLOCKER; }
|
||||
"/*verilator no_clocker*/" { FL; return yVL_NO_CLOCKER; }
|
||||
"/*verilator sc_bv*/" { FL; return yVL_SC_BV; }
|
||||
"/*verilator sformat*/" { FL; return yVL_SFORMAT; }
|
||||
"/*verilator systemc_clock*/" { FL; return yVL_CLOCK; }
|
||||
|
||||
@@ -489,6 +489,8 @@ class AstSenTree;
|
||||
%token<fl> yD_WRITE "$write"
|
||||
|
||||
%token<fl> yVL_CLOCK "/*verilator sc_clock*/"
|
||||
%token<fl> yVL_CLOCKER "/*verilator clocker*/"
|
||||
%token<fl> yVL_NO_CLOCKER "/*verilator no_clocker*/"
|
||||
%token<fl> yVL_CLOCK_ENABLE "/*verilator clock_enable*/"
|
||||
%token<fl> yVL_COVERAGE_BLOCK_OFF "/*verilator coverage_block_off*/"
|
||||
%token<fl> yVL_FULL_CASE "/*verilator full_case*/"
|
||||
@@ -1927,6 +1929,8 @@ sigAttrList<nodep>:
|
||||
|
||||
sigAttr<nodep>:
|
||||
yVL_CLOCK { $$ = new AstAttrOf($1,AstAttrType::VAR_CLOCK); }
|
||||
| yVL_CLOCKER { $$ = new AstAttrOf($1,AstAttrType::VAR_CLOCKER); }
|
||||
| yVL_NO_CLOCKER { $$ = new AstAttrOf($1,AstAttrType::VAR_NO_CLOCKER); }
|
||||
| yVL_CLOCK_ENABLE { $$ = new AstAttrOf($1,AstAttrType::VAR_CLOCK_ENABLE); }
|
||||
| yVL_PUBLIC { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC); v3Global.dpi(true); }
|
||||
| yVL_PUBLIC_FLAT { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT); v3Global.dpi(true); }
|
||||
|
||||
Reference in New Issue
Block a user