Add --clk and related optimizations, msg1533.
This commit is contained in:
parent
005b4b7609
commit
486d69da5f
2
Changes
2
Changes
|
@ -7,6 +7,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
|||
|
||||
*** Add VerilatedVcdFile to allow real-time waveforms, bug890. [HyungKi Jeong]
|
||||
|
||||
*** Add --clk and related optimizations, msg1533. [Jie Xu]
|
||||
|
||||
**** Fix comma-instantiations with parameters, bug884. [Franck Jullien]
|
||||
|
||||
**** Fix SystemC arrayed bit vectors, bug886. [David Poole]
|
||||
|
|
|
@ -246,6 +246,7 @@ descriptions in the next sections for more information.
|
|||
-CFLAGS <flags> C++ Compiler flags for makefile
|
||||
--cc Create C++ output
|
||||
--cdc Clock domain crossing analysis
|
||||
--clk <signal-name> Mark specified signal as clock
|
||||
--compiler <compiler-name> Tune for specified C++ compiler
|
||||
--converge-limit <loops> Tune convergence settle time
|
||||
--coverage Enable all coverage
|
||||
|
@ -284,6 +285,7 @@ descriptions in the next sections for more information.
|
|||
--MP Create phony dependency targets
|
||||
--Mdir <directory> Name of output object directory
|
||||
--mod-prefix <topname> Name to prepend to lower classes
|
||||
--no-clk <signal-name> Prevent marking specified signal as clock
|
||||
--no-pins64 Don't use vluint64_t's for 33-64 bit sigs
|
||||
--no-skip-identical Disable skipping identical output
|
||||
+notimingchecks Ignored
|
||||
|
@ -456,6 +458,23 @@ information is also written to the file {prefix}__cdc.txt.
|
|||
Currently only checks some items that other CDC tools missed; if you have
|
||||
interest in adding more traditional CDC checks, please contact the authors.
|
||||
|
||||
=item --clk I<signal-name>
|
||||
|
||||
Sometimes it is quite difficult for Verilator to distinguish clock signals from
|
||||
other data signals. Occasionally the clock signals can end up in the checking
|
||||
list of signals which determines if further evaluation is needed. This will
|
||||
heavily degrade the performance of verilated model.
|
||||
|
||||
With --clk <signal-name>, user can specified root clock into the model, then
|
||||
Verilator will mark the signal as clocker and propagate the clocker attribute
|
||||
automatically to other signals derived from that. In this way, Verilator will
|
||||
try to avoid taking the clocker signal into checking list.
|
||||
|
||||
Note signal-name is specified by the RTL hiearchy path. For example, v.foo.bar.
|
||||
If the signal is the input to top-module, the directly the signal name. If you
|
||||
find it difficult to find the exact name, try to use C</*verilator clocker*/> in
|
||||
RTL file to mark the signal directly.
|
||||
|
||||
=item --compiler I<compiler-name>
|
||||
|
||||
Enables tunings and work-arounds for the specified C++ compiler.
|
||||
|
@ -761,6 +780,10 @@ otherwise manually create the Mdir before calling Verilator.
|
|||
Specifies the name to prepend to all lower level classes. Defaults to
|
||||
the same as --prefix.
|
||||
|
||||
=item --no-clk <signal-name>
|
||||
|
||||
Prevent the specified signal from being marked as clock. See C<--clk>.
|
||||
|
||||
=item --no-pins64
|
||||
|
||||
Backward compatible alias for "--pins-bv 33".
|
||||
|
@ -2126,6 +2149,15 @@ scheduling algorithm, sometimes required for correct clock behavior, and
|
|||
always improving performance. It's also a good idea to enable the
|
||||
IMPERFECTSCH warning, to insure all clock enables are properly recognized.
|
||||
|
||||
=item /*verilator clocker*/
|
||||
|
||||
=item /*verilator no_clocker*/
|
||||
|
||||
Used after a signal declaration to indicate the signal is used as clock or
|
||||
not. This information is used by Verilator to mark the signal as clocker
|
||||
and propagate the clocker attribute automatically to derived signals. See
|
||||
C<--clk> for more information.
|
||||
|
||||
=item /*verilator coverage_block_off*/
|
||||
|
||||
Specifies the entire begin/end block should be ignored for coverage
|
||||
|
@ -2842,6 +2874,16 @@ With --cdc only, warns that asynchronous flop reset terms come from other
|
|||
than primary inputs or flopped outputs, creating the potential for reset
|
||||
glitches.
|
||||
|
||||
=item CLKDATA
|
||||
|
||||
Warns that clock signal is mixed used with/as data signal. The checking for
|
||||
this warning is enabled only if user has explicitly marked some signal as
|
||||
clocker using command line option or in-source meta comment (see C<--clk>).
|
||||
|
||||
The warning can be disabled without affecting the simulation result. But it
|
||||
is recommanded to check the warning as this may degrade the performance of
|
||||
the Verilated model.
|
||||
|
||||
=item CMPCONST
|
||||
|
||||
Warns that you are comparing a value in a way that will always be constant.
|
||||
|
|
|
@ -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;
|
||||
|
|
38
src/V3Ast.h
38
src/V3Ast.h
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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*) {
|
||||
|
|
|
@ -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; }
|
||||
|
|
211
src/V3Order.cpp
211
src/V3Order.cpp
|
@ -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); }
|
||||
|
|
|
@ -393,6 +393,7 @@ sub new {
|
|||
"-OD", # As currently disabled unless -O3
|
||||
"--debug-check"],
|
||||
verilator_flags2 => [],
|
||||
verilator_flags3 => ["--clk clk"],
|
||||
verilator_make_gcc => 1,
|
||||
verilated_debug => $Opt_Verilated_Debug,
|
||||
stdout_filename => undef, # Redirect stdout
|
||||
|
@ -502,7 +503,8 @@ sub compile_vlt_flags {
|
|||
my $checkflags = join(' ',@{$param{v_flags}},
|
||||
@{$param{v_flags2}},
|
||||
@{$param{verilator_flags}},
|
||||
@{$param{verilator_flags2}});
|
||||
@{$param{verilator_flags2}},
|
||||
@{$param{verilator_flags3}});
|
||||
$self->{sc} = 1 if ($checkflags =~ /-sc\b/);
|
||||
$self->{sp} = 1 if ($checkflags =~ /-sp\b/);
|
||||
$self->{trace} = 1 if ($opt_trace || $checkflags =~ /-trace\b/);
|
||||
|
@ -533,6 +535,7 @@ sub compile_vlt_flags {
|
|||
"--prefix ".$param{VM_PREFIX},
|
||||
@verilator_flags,
|
||||
@{$param{verilator_flags2}},
|
||||
@{$param{verilator_flags3}},
|
||||
@{$param{v_flags}},
|
||||
@{$param{v_flags2}},
|
||||
$param{top_filename},
|
||||
|
|
|
@ -8,6 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
|||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
verilator_flags2 => ["-Wno-CLKDATA"],
|
||||
);
|
||||
|
||||
execute (
|
||||
|
|
|
@ -39,30 +39,23 @@ module t (clk);
|
|||
if (cyc==3) begin
|
||||
d1 <= 1'b1; d3<=3'h3; d8<=8'h44;
|
||||
ena <= 1'b1;
|
||||
// PROPER ANSWER is 8'h11, but we are negative-testing
|
||||
//if (q8 != 8'h11) $stop;
|
||||
if (q8 != 8'h33) $stop;
|
||||
if (q8 != 8'h11) $stop;
|
||||
end
|
||||
if (cyc==4) begin
|
||||
d1 <= 1'b1; d3<=3'h4; d8<=8'h77;
|
||||
ena <= 1'b1;
|
||||
// PROPER ANSWER is 8'h11, but we are negative-testing
|
||||
//if (q8 != 8'h11) $stop;
|
||||
if (q8 != 8'h33) $stop;
|
||||
if (q8 != 8'h11) $stop;
|
||||
end
|
||||
if (cyc==5) begin
|
||||
d1 <= 1'b1; d3<=3'h0; d8<=8'h88;
|
||||
ena <= 1'b1;
|
||||
// PROPER ANSWER is 8'h44, but we are negative-testing
|
||||
//if (q8 != 8'h44) $stop;
|
||||
if (q8 != 8'h44) $stop;
|
||||
end
|
||||
if (cyc==6) begin
|
||||
// PROPER ANSWER is 8'h77, but we are negative-testing
|
||||
//if (q8 != 8'h77) $stop;
|
||||
if (q8 != 8'h77) $stop;
|
||||
end
|
||||
if (cyc==7) begin
|
||||
// PROPER ANSWER is 8'h88, but we are negative-testing
|
||||
//if (q8 != 8'h88) $stop;
|
||||
if (q8 != 8'h88) $stop;
|
||||
end
|
||||
//
|
||||
if (cyc==20) begin
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# 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
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
# verilator_flags2 => ["-Wno-UNOPTFLAT"]
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
|
@ -0,0 +1,66 @@
|
|||
// DESCRIPTION: Verilator: Simple test of CLkDATA
|
||||
//
|
||||
// Trigger the CLKDATA detection
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2015 by Jie Xu.
|
||||
|
||||
localparam ID_MSB = 1;
|
||||
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk,
|
||||
res,
|
||||
res8,
|
||||
res16
|
||||
);
|
||||
input clk;
|
||||
output res;
|
||||
output [7:0] res8;
|
||||
output [15:0] res16;
|
||||
|
||||
|
||||
wire [7:0] clkSet;
|
||||
wire clk_1;
|
||||
wire [2:0] clk_3;
|
||||
wire [3:0] clk_4;
|
||||
wire clk_final;
|
||||
reg [7:0] count;
|
||||
|
||||
|
||||
assign clkSet = {8{clk}};
|
||||
assign clk_4 = clkSet[7:4];
|
||||
assign clk_1 = clk_4[0];;
|
||||
|
||||
// arraysel
|
||||
assign clk_3 = {3{clk_1}};
|
||||
assign clk_final = clk_3[0];
|
||||
|
||||
// the following two assignment triggers the CLKDATA warning
|
||||
// because on LHS there are a mix of signals both CLOCK and
|
||||
// DATA
|
||||
/* verilator lint_off CLKDATA */
|
||||
assign res8 = {clk_3, 1'b0, clk_4};
|
||||
assign res16 = {count, clk_3, clk_1, clk_4};
|
||||
/* verilator lint_on CLKDATA */
|
||||
|
||||
|
||||
initial
|
||||
count = 0;
|
||||
|
||||
|
||||
always @(posedge clk_final or negedge clk_final) begin
|
||||
count = count + 1;
|
||||
// the following assignment should trigger the CLKDATA warning
|
||||
// because CLOCK signal is used as DATA in sequential block
|
||||
/* verilator lint_off CLKDATA */
|
||||
res <= clk_final;
|
||||
/* verilator lint_on CLKDATA */
|
||||
if ( count == 8'hf) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
|||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
verilator_flags2 => ["-Wno-UNOPTFLAT"]
|
||||
verilator_flags2 => ["-Wno-CLKDATA"]
|
||||
);
|
||||
|
||||
execute (
|
||||
|
|
|
@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
|||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
verilator_flags2 => ["-Wno-UNOPTFLAT"]
|
||||
verilator_flags2 => ["-Wno-CLKDATA"]
|
||||
);
|
||||
|
||||
execute (
|
||||
|
|
|
@ -8,6 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
|||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
verilator_flags2 => ["-Wno-CLKDATA"]
|
||||
);
|
||||
|
||||
execute (
|
||||
|
|
|
@ -10,6 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
|||
compile (
|
||||
# Disable inlining, this test is trivial without it
|
||||
verilator_flags2 => ["-Oi --trace"],
|
||||
verilator_flags3 => [],
|
||||
);
|
||||
|
||||
execute (
|
||||
|
|
|
@ -15,6 +15,7 @@ compile (
|
|||
make_top_shell => 0,
|
||||
make_main => 0,
|
||||
verilator_flags2 => ["--exe $Self->{t_dir}/t_mem_multi_io2.cpp -Oi"],
|
||||
verilator_flags3 => [],
|
||||
);
|
||||
|
||||
execute (
|
||||
|
|
|
@ -15,6 +15,7 @@ compile (
|
|||
make_top_shell => 0,
|
||||
make_main => 0,
|
||||
verilator_flags2 => ["--exe $Self->{t_dir}/t_mem_multi_io3.cpp -Oi"],
|
||||
verilator_flags3 => [],
|
||||
);
|
||||
|
||||
ok(1);
|
||||
|
|
|
@ -15,6 +15,7 @@ compile (
|
|||
make_top_shell => 0,
|
||||
make_main => 0,
|
||||
verilator_flags2 => ["--exe $Self->{t_dir}/t_mem_multi_io3.cpp --sc -Oi"],
|
||||
verilator_flags3 => [],
|
||||
);
|
||||
|
||||
ok(1);
|
||||
|
|
|
@ -11,6 +11,7 @@ top_filename("t/t_unoptflat_simple_2.v");
|
|||
|
||||
# Compile only
|
||||
compile (
|
||||
verilator_flags3 => [],
|
||||
verilator_flags2 => ["--report-unoptflat"],
|
||||
fails => 1,
|
||||
expect=>
|
||||
|
|
Loading…
Reference in New Issue