Add --clk and related optimizations, msg1533.

This commit is contained in:
Wilson Snyder 2015-03-12 19:20:46 -04:00
parent 005b4b7609
commit 486d69da5f
26 changed files with 456 additions and 23 deletions

View File

@ -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]

View File

@ -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.

View File

@ -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;

View File

@ -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 {

View File

@ -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

View File

@ -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",

View File

@ -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*) {

View File

@ -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);

View File

@ -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; }

View File

@ -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);
}

View File

@ -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);

View File

@ -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; }

View File

@ -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); }

View File

@ -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},

View File

@ -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 (

View File

@ -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

19
test_regress/t/t_clocker.pl Executable file
View File

@ -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;

View File

@ -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

View File

@ -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 (

View File

@ -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 (

View File

@ -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 (

View File

@ -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 (

View File

@ -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 (

View File

@ -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);

View File

@ -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);

View File

@ -11,6 +11,7 @@ top_filename("t/t_unoptflat_simple_2.v");
# Compile only
compile (
verilator_flags3 => [],
verilator_flags2 => ["--report-unoptflat"],
fails => 1,
expect=>