diff --git a/Changes b/Changes index 55b980a8e..ce2f1c88d 100644 --- a/Changes +++ b/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] diff --git a/bin/verilator b/bin/verilator index 7d3891e7a..b5a60dba8 100755 --- a/bin/verilator +++ b/bin/verilator @@ -246,6 +246,7 @@ descriptions in the next sections for more information. -CFLAGS C++ Compiler flags for makefile --cc Create C++ output --cdc Clock domain crossing analysis + --clk Mark specified signal as clock --compiler Tune for specified C++ compiler --converge-limit 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 Name of output object directory --mod-prefix Name to prepend to lower classes + --no-clk 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 + +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 , 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 in +RTL file to mark the signal directly. + =item --compiler I 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 + +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. diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 8e10ba1c0..ec3b6476c 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -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; diff --git a/src/V3Ast.h b/src/V3Ast.h index f06f8b2e5..bcfaf9fde 100644 --- a/src/V3Ast.h +++ b/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(_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<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*) { diff --git a/src/V3Options.cpp b/src/V3Options.cpp index fd5f2a993..2bdda7b50 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -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)= @@ -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; } diff --git a/src/V3Order.cpp b/src/V3Order.cpp index 9c3d9be07..f9abedbc2 100644 --- a/src/V3Order.cpp +++ b/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 "<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()<lhsp()->width() <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 "<varp()->attrClocker() == AstVarAttrClocker::CLOCKER_YES) { + if (m_inClocked) { + nodep->v3warn(CLKDATA, "Clock used as data (on rhs of assignment) in sequential block "<prettyName()); + } else { + m_hasClk = true; + m_childClkWidth = nodep->width(); // Pass up + UINFO(5, "node is already marked as clocker "<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 "<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 "<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 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 "<nodep()<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__<<": "<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); diff --git a/src/verilog.l b/src/verilog.l index 9cab9fe6c..32e92bb80 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -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; } diff --git a/src/verilog.y b/src/verilog.y index fb16ac308..6784aa1c5 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -489,6 +489,8 @@ class AstSenTree; %token yD_WRITE "$write" %token yVL_CLOCK "/*verilator sc_clock*/" +%token yVL_CLOCKER "/*verilator clocker*/" +%token yVL_NO_CLOCKER "/*verilator no_clocker*/" %token yVL_CLOCK_ENABLE "/*verilator clock_enable*/" %token yVL_COVERAGE_BLOCK_OFF "/*verilator coverage_block_off*/" %token yVL_FULL_CASE "/*verilator full_case*/" @@ -1927,6 +1929,8 @@ sigAttrList: sigAttr: 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); } diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 92f5dce56..2d33502cd 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -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}, diff --git a/test_regress/t/t_alw_dly.pl b/test_regress/t/t_alw_dly.pl index 7058e622f..2ca3a9b9a 100755 --- a/test_regress/t/t_alw_dly.pl +++ b/test_regress/t/t_alw_dly.pl @@ -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 ( diff --git a/test_regress/t/t_clk_condflop_nord.v b/test_regress/t/t_clk_condflop_nord.v index e6a18e0db..5554ecb07 100644 --- a/test_regress/t/t_clk_condflop_nord.v +++ b/test_regress/t/t_clk_condflop_nord.v @@ -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 diff --git a/test_regress/t/t_clocker.pl b/test_regress/t/t_clocker.pl new file mode 100755 index 000000000..7a1792c6f --- /dev/null +++ b/test_regress/t/t_clocker.pl @@ -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; diff --git a/test_regress/t/t_clocker.v b/test_regress/t/t_clocker.v new file mode 100644 index 000000000..4a8b3f408 --- /dev/null +++ b/test_regress/t/t_clocker.v @@ -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 diff --git a/test_regress/t/t_detectarray_1.pl b/test_regress/t/t_detectarray_1.pl index eadb41ee3..86c7dd2ec 100755 --- a/test_regress/t/t_detectarray_1.pl +++ b/test_regress/t/t_detectarray_1.pl @@ -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 ( diff --git a/test_regress/t/t_detectarray_2.pl b/test_regress/t/t_detectarray_2.pl index eadb41ee3..86c7dd2ec 100755 --- a/test_regress/t/t_detectarray_2.pl +++ b/test_regress/t/t_detectarray_2.pl @@ -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 ( diff --git a/test_regress/t/t_math_shift.pl b/test_regress/t/t_math_shift.pl index 7058e622f..b8f89b85c 100755 --- a/test_regress/t/t_math_shift.pl +++ b/test_regress/t/t_math_shift.pl @@ -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 ( diff --git a/test_regress/t/t_mem_multi_io.pl b/test_regress/t/t_mem_multi_io.pl index 50bf56f60..886fe42af 100755 --- a/test_regress/t/t_mem_multi_io.pl +++ b/test_regress/t/t_mem_multi_io.pl @@ -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 ( diff --git a/test_regress/t/t_mem_multi_io2_cc.pl b/test_regress/t/t_mem_multi_io2_cc.pl index c5708fba8..c52d2027e 100755 --- a/test_regress/t/t_mem_multi_io2_cc.pl +++ b/test_regress/t/t_mem_multi_io2_cc.pl @@ -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 ( diff --git a/test_regress/t/t_mem_multi_io3_cc.pl b/test_regress/t/t_mem_multi_io3_cc.pl index d9a9e9be1..e1509c512 100755 --- a/test_regress/t/t_mem_multi_io3_cc.pl +++ b/test_regress/t/t_mem_multi_io3_cc.pl @@ -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); diff --git a/test_regress/t/t_mem_multi_io3_sc.pl b/test_regress/t/t_mem_multi_io3_sc.pl index 5d54f4f4e..19cfbc9d4 100755 --- a/test_regress/t/t_mem_multi_io3_sc.pl +++ b/test_regress/t/t_mem_multi_io3_sc.pl @@ -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); diff --git a/test_regress/t/t_unoptflat_simple_2_bad.pl b/test_regress/t/t_unoptflat_simple_2_bad.pl index 493894ecb..ecb077c39 100755 --- a/test_regress/t/t_unoptflat_simple_2_bad.pl +++ b/test_regress/t/t_unoptflat_simple_2_bad.pl @@ -11,6 +11,7 @@ top_filename("t/t_unoptflat_simple_2.v"); # Compile only compile ( + verilator_flags3 => [], verilator_flags2 => ["--report-unoptflat"], fails => 1, expect=>