diff --git a/.gitignore b/.gitignore index e9235a3a7..d426d7134 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ \#* .#* +.nfs* *~ *.tidy *.old diff --git a/Changes b/Changes index 2d2cf87fe..91b9a8eb0 100644 --- a/Changes +++ b/Changes @@ -2,6 +2,35 @@ Revision history for Verilator The contributors that suggested a given feature are shown in []. Thanks! +* Verilator 4.040 2020-08-15 + +** Version 4.040 is planned to be the final version that will + support pre-C++11 compilers. Please move to C++11 or newer compilers. + +*** Fix arrayed interfaces, broke in 4.038 (#2468). [Josh Redford] + +**** Support $stable, $rose and $fell. (#2148) (#2501) [Peter Monsson] + +**** Support simple function localparams (#2461). [James Hanlon] + +**** Miscellaneous parsing error changes towards UVM support. + +**** Fix arrayed interfaces (#2469). [Josh Redford] + +**** Fix protect lib VCS warning. (#2479) [Julien Margetts] + +**** Fix combining different-width parameters (#2484). [abirkmanis] + +**** Fix protect-lib without sequential logic (#2492). [Yutetsu TAKATSUKASA] + +**** Fix V3Unknown from running with flat XML output (#2494). [James Hanlon] + +**** Fix non-32 bit conversion to float (#2495). [dsvf] + +**** Fix casting non-self-determined subexpressions (#2493). [phantom-killua] + +**** Fix SystemC net names (#2500). [Edgar E. Iglesias] + * Verilator 4.038 2020-07-11 diff --git a/ci/travis-install.bash b/ci/travis-install.bash index f4c89c9bd..27adf42ec 100755 --- a/ci/travis-install.bash +++ b/ci/travis-install.bash @@ -80,23 +80,23 @@ elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then if [ "$M32" = 1 ]; then sudo apt-get install lib32z1-dev gcc-multilib g++-multilib fi - yes yes | sudo cpan -fi Unix::Processors Parallel::Forker - # Not listing Bit::Vector as slow to install, and only skips one test - install-vcddiff elif [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update # brew cask install gtkwave # fst2vcd hangs at launch, so don't bother brew install ccache perl - yes yes | sudo cpan -fi Unix::Processors Parallel::Forker - install-vcddiff elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then # fst2vcd fails with "Could not open '', exiting." sudo pkg install -y ccache gmake perl5 python3 - yes yes | sudo cpan -fi Unix::Processors Parallel::Forker - install-vcddiff else fatal "Unknown os: '$TRAVIS_OS_NAME'" fi + # Common installs + if [ "$TRAVIS_DIST" != "trusty" ]; then + TRAVIS_CPAN_REPO=https://cpan.org + fi + # Not listing Bit::Vector as slow to install, and only skips one test + yes yes | sudo cpan -M $TRAVIS_CPAN_REPO -fi Unix::Processors Parallel::Forker + install-vcddiff else ############################################################################## # Unknown build stage diff --git a/configure.ac b/configure.ac index 6a866b524..e672a3198 100644 --- a/configure.ac +++ b/configure.ac @@ -7,11 +7,12 @@ #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[4.038 2020-07-11], +AC_INIT([Verilator],[4.040 2020-08-15], [https://verilator.org], [verilator],[https://verilator.org]) # When releasing, also update header of Changes file # and commit using "devel release" or "Version bump" message +# Then 'make maintainer-dist' AC_CONFIG_HEADER(src/config_build.h) AC_CONFIG_FILES(Makefile docs/Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h verilator.pc verilator-config.cmake verilator-config-version.cmake) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index cc00fe3a1..5eeec896c 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -11,6 +11,7 @@ Dan Petrisko David Horton David Stanford Driss Hafdi +Edgar E. Iglesias Eric Rippey Fan Shupei Garrett Smith @@ -28,6 +29,7 @@ Jan Van Winkel Jeremy Bennett John Coiner John Demme +Josh Redford Julien Margetts Kanad Kanhere Kevin Kiningham @@ -37,6 +39,7 @@ Lukasz Dalek Maarten De Braekeleer Maciej Sobkowski Marco Widmer +Marshal Qiao Matthew Ballance Michael Killough Mike Popoloski @@ -47,6 +50,7 @@ Peter Horvath Peter Monsson Philipp Wagner Pieter Kapsenberg +Piotr Binkowski Qingyao Sun Richard Myers Sean Cross diff --git a/include/verilated.cpp b/include/verilated.cpp index 72f3e97c9..f21bed470 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -584,6 +584,30 @@ QData VL_POWSS_QQW(int obits, int, int rbits, QData lhs, WDataInP rwp, bool lsig return VL_POW_QQW(obits, rbits, rbits, lhs, rwp); } +double VL_ITOR_D_W(int lbits, WDataInP lwp) VL_PURE { + int ms_word = VL_WORDS_I(lbits) - 1; + for (; !lwp[ms_word] && ms_word > 0;) --ms_word; + if (ms_word == 0) return static_cast(lwp[0]); + if (ms_word == 1) return static_cast(VL_SET_QW(lwp)); + // We need 53 bits of mantissa, which might mean looking at 3 words + // namely ms_word, ms_word-1 and ms_word-2 + EData ihi = lwp[ms_word]; + EData imid = lwp[ms_word - 1]; + EData ilo = lwp[ms_word - 2]; + double hi = static_cast(ihi) * exp2(2 * VL_EDATASIZE); + double mid = static_cast(imid) * exp2(VL_EDATASIZE); + double lo = static_cast(ilo); + double d = (hi + mid + lo) * exp2(VL_EDATASIZE * (ms_word - 2)); + return d; +} +double VL_ISTOR_D_W(int lbits, WDataInP lwp) VL_PURE { + if (!VL_SIGN_W(lbits, lwp)) return VL_ITOR_D_W(lbits, lwp); + vluint32_t pos[VL_MULS_MAX_WORDS + 1]; // Fixed size, as MSVC++ doesn't allow [words] here + VL_NEGATE_W(VL_WORDS_I(lbits), pos, lwp); + _VL_CLEAN_INPLACE_W(lbits, pos); + return -VL_ITOR_D_W(lbits, pos); +} + //=========================================================================== // Formatting diff --git a/include/verilated.h b/include/verilated.h index f9cb28fbe..099066ab7 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -764,9 +764,27 @@ static inline QData VL_CVT_Q_D(double lhs) VL_PURE { } // clang-format on -/// Return double from QData (numeric) -static inline double VL_ITOR_D_I(IData lhs) VL_PURE { - return static_cast(static_cast(lhs)); +/// Return double from lhs (numeric) unsigned +double VL_ITOR_D_W(int lbits, WDataInP lwp) VL_PURE; +static inline double VL_ITOR_D_I(int, IData lhs) VL_PURE { + return static_cast(static_cast(lhs)); +} +static inline double VL_ITOR_D_Q(int, QData lhs) VL_PURE { + return static_cast(static_cast(lhs)); +} +/// Return double from lhs (numeric) signed +double VL_ISTOR_D_W(int lbits, WDataInP lwp) VL_PURE; +static inline double VL_ISTOR_D_I(int lbits, IData lhs) VL_PURE { + if (lbits == 32) return static_cast(static_cast(lhs)); + WData lwp[VL_WQ_WORDS_E]; + VL_SET_WI(lwp, lhs); + return VL_ISTOR_D_W(lbits, lwp); +} +static inline double VL_ISTOR_D_Q(int lbits, QData lhs) VL_PURE { + if (lbits == 64) return static_cast(static_cast(lhs)); + WData lwp[VL_WQ_WORDS_E]; + VL_SET_WQ(lwp, lhs); + return VL_ISTOR_D_W(lbits, lwp); } /// Return QData from double (numeric) static inline IData VL_RTOI_I_D(double lhs) VL_PURE { @@ -1453,6 +1471,7 @@ static inline int _VL_CMPS_W(int lbits, WDataInP lwp, WDataInP rwp) VL_MT_SAFE { //========================================================================= // Math +// Output NOT clean static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp, WDataInP lwp) VL_MT_SAFE { EData carry = 1; for (int i = 0; i < words; ++i) { @@ -2538,25 +2557,25 @@ static inline WDataOutP VL_CONSTHI_W_1X(int obits, int lsb, WDataOutP obase, EData d0) VL_MT_SAFE { WDataOutP o = obase + VL_WORDS_I(lsb); o[0] = d0; - _END(obits,1); + _END(obits, VL_WORDS_I(lsb) + 1); } static inline WDataOutP VL_CONSTHI_W_2X(int obits, int lsb, WDataOutP obase, EData d1, EData d0) VL_MT_SAFE { WDataOutP o = obase + VL_WORDS_I(lsb); o[0] = d0; o[1] = d1; - _END(obits,2); + _END(obits, VL_WORDS_I(lsb) + 2); } static inline WDataOutP VL_CONSTHI_W_3X(int obits, int lsb, WDataOutP obase, EData d2, EData d1, EData d0) VL_MT_SAFE { WDataOutP o = obase + VL_WORDS_I(lsb); o[0] = d0; o[1] = d1; o[2] = d2; - _END(obits,3); + _END(obits, VL_WORDS_I(lsb) + 3); } static inline WDataOutP VL_CONSTHI_W_4X(int obits, int lsb, WDataOutP obase, EData d3, EData d2, EData d1, EData d0) VL_MT_SAFE { WDataOutP o = obase + VL_WORDS_I(lsb); o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3; - _END(obits,4); + _END(obits, VL_WORDS_I(lsb) + 4); } static inline WDataOutP VL_CONSTHI_W_5X(int obits, int lsb, WDataOutP obase, EData d4, @@ -2564,7 +2583,7 @@ static inline WDataOutP VL_CONSTHI_W_5X(int obits, int lsb, WDataOutP obase, WDataOutP o = obase + VL_WORDS_I(lsb); o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3; o[4] = d4; - _END(obits,5); + _END(obits, VL_WORDS_I(lsb) + 5); } static inline WDataOutP VL_CONSTHI_W_6X(int obits, int lsb, WDataOutP obase, EData d5, EData d4, @@ -2572,7 +2591,7 @@ static inline WDataOutP VL_CONSTHI_W_6X(int obits, int lsb, WDataOutP obase, WDataOutP o = obase + VL_WORDS_I(lsb); o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3; o[4] = d4; o[5] = d5; - _END(obits,6); + _END(obits, VL_WORDS_I(lsb) + 6); } static inline WDataOutP VL_CONSTHI_W_7X(int obits, int lsb, WDataOutP obase, EData d6, EData d5, EData d4, @@ -2580,7 +2599,7 @@ static inline WDataOutP VL_CONSTHI_W_7X(int obits, int lsb, WDataOutP obase, WDataOutP o = obase + VL_WORDS_I(lsb); o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3; o[4] = d4; o[5] = d5; o[6] = d6; - _END(obits,7); + _END(obits, VL_WORDS_I(lsb) + 7); } static inline WDataOutP VL_CONSTHI_W_8X(int obits, int lsb, WDataOutP obase, EData d7, EData d6, EData d5, EData d4, @@ -2588,7 +2607,7 @@ static inline WDataOutP VL_CONSTHI_W_8X(int obits, int lsb, WDataOutP obase, WDataOutP o = obase + VL_WORDS_I(lsb); o[0] = d0; o[1] = d1; o[2] = d2; o[3] = d3; o[4] = d4; o[5] = d5; o[6] = d6; o[7] = d7; - _END(obits,8); + _END(obits, VL_WORDS_I(lsb) + 8); } #undef _END diff --git a/include/verilated_save.h b/include/verilated_save.h index 74ea32d83..cf6c3a5a5 100644 --- a/include/verilated_save.h +++ b/include/verilated_save.h @@ -55,7 +55,7 @@ public: } virtual ~VerilatedSerialize() { close(); - if (m_bufp) VL_DO_CLEAR(delete m_bufp, m_bufp = NULL); + if (m_bufp) VL_DO_CLEAR(delete[] m_bufp, m_bufp = NULL); } // METHODS bool isOpen() const { return m_isOpen; } @@ -118,7 +118,7 @@ public: } virtual ~VerilatedDeserialize() { close(); - if (m_bufp) VL_DO_CLEAR(delete m_bufp, m_bufp = NULL); + if (m_bufp) VL_DO_CLEAR(delete[] m_bufp, m_bufp = NULL); } // METHODS bool isOpen() const { return m_isOpen; } diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp index 6448d0eab..ec1775503 100644 --- a/src/V3AssertPre.cpp +++ b/src/V3AssertPre.cpp @@ -89,11 +89,54 @@ private: if (!nodep->immediate()) nodep->sentreep(newSenTree(nodep)); clearAssertInfo(); } + virtual void visit(AstFell* nodep) VL_OVERRIDE { + if (nodep->sentreep()) return; // Already processed + iterateChildren(nodep); + FileLine* fl = nodep->fileline(); + AstNode* exprp = nodep->exprp()->unlinkFrBack(); + if (exprp->width() > 1) exprp = new AstSel(fl, exprp, 0, 1); + AstNode* past = new AstPast(fl, exprp, NULL); + past->dtypeFrom(exprp); + exprp = new AstAnd(fl, past, new AstNot(fl, exprp->cloneTree(false))); + exprp->dtypeSetLogicBool(); + nodep->replaceWith(exprp); + nodep->sentreep(newSenTree(nodep)); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } virtual void visit(AstPast* nodep) VL_OVERRIDE { if (nodep->sentreep()) return; // Already processed iterateChildren(nodep); nodep->sentreep(newSenTree(nodep)); } + virtual void visit(AstRose* nodep) VL_OVERRIDE { + if (nodep->sentreep()) return; // Already processed + iterateChildren(nodep); + FileLine* fl = nodep->fileline(); + AstNode* exprp = nodep->exprp()->unlinkFrBack(); + if (exprp->width() > 1) exprp = new AstSel(fl, exprp, 0, 1); + AstNode* past = new AstPast(fl, exprp, NULL); + past->dtypeFrom(exprp); + exprp = new AstAnd(fl, new AstNot(fl, past), exprp->cloneTree(false)); + exprp->dtypeSetLogicBool(); + nodep->replaceWith(exprp); + nodep->sentreep(newSenTree(nodep)); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } + virtual void visit(AstStable* nodep) VL_OVERRIDE { + if (nodep->sentreep()) return; // Already processed + iterateChildren(nodep); + FileLine* fl = nodep->fileline(); + AstNode* exprp = nodep->exprp()->unlinkFrBack(); + AstNode* past = new AstPast(fl, exprp, NULL); + past->dtypeFrom(exprp); + exprp = new AstEq(fl, past, + exprp->cloneTree(false)); // new AstVarRef(fl, exprp, true) + exprp->dtypeSetLogicBool(); + nodep->replaceWith(exprp); + nodep->sentreep(newSenTree(nodep)); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } + virtual void visit(AstPropClocked* nodep) VL_OVERRIDE { // No need to iterate the body, once replace will get iterated iterateAndNextNull(nodep->sensesp()); diff --git a/src/V3Ast.h b/src/V3Ast.h index 674c393f9..f990b491c 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1891,6 +1891,7 @@ public: // For documentation on emitC format see EmitCStmts::emitOpName virtual string emitC() = 0; virtual string emitSimpleOperator() { return ""; } + virtual bool emitCheckMaxWords() { return false; } // Check VL_MULS_MAX_WORDS virtual bool cleanOut() const = 0; // True if output has extra upper bits zero // Someday we will generically support data types on every math node // Until then isOpaque indicates we shouldn't constant optimize this node type diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index d5ee54c8d..d9ec68bb3 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1493,19 +1493,19 @@ void AstParseRef::dump(std::ostream& str) const { this->AstNode::dump(str); str << " [" << expect().ascii() << "]"; } -void AstPackageRef::dump(std::ostream& str) const { +void AstClassOrPackageRef::dump(std::ostream& str) const { this->AstNode::dump(str); - if (packagep()) { str << " pkg=" << nodeAddr(packagep()); } + if (classOrPackagep()) { str << " cpkg=" << nodeAddr(classOrPackagep()); } str << " -> "; - if (packagep()) { - packagep()->dump(str); + if (classOrPackagep()) { + classOrPackagep()->dump(str); } else { str << "UNLINKED"; } } void AstDot::dump(std::ostream& str) const { this->AstNode::dump(str); - if (colon()) str << "[::]"; + if (colon()) str << " [::]"; } void AstActive::dump(std::ostream& str) const { this->AstNode::dump(str); diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index bb055fb6c..f24e6b37c 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -448,6 +448,7 @@ public: ASTNODE_NODE_FUNCS(TypedefFwd) // METHODS virtual string name() const { return m_name; } + virtual bool maybePointedTo() const { return true; } }; class AstDefImplicitDType : public AstNodeDType { @@ -1139,6 +1140,15 @@ public: , m_refDTypep(NULL) , m_name(name) , m_packagep(NULL) {} + AstRefDType(FileLine* fl, const string& name, AstNode* classOrPackagep, AstNode* paramsp) + : ASTGEN_SUPER(fl) + , m_typedefp(NULL) + , m_refDTypep(NULL) + , m_name(name) + , m_packagep(NULL) { + setNOp3p(classOrPackagep); + addNOp4p(paramsp); + } class FlagTypeOfExpr {}; // type(expr) for parser only AstRefDType(FileLine* fl, FlagTypeOfExpr, AstNode* typeofp) : ASTGEN_SUPER(fl) @@ -1216,6 +1226,8 @@ public: AstNodeModule* packagep() const { return m_packagep; } void packagep(AstNodeModule* nodep) { m_packagep = nodep; } AstNode* typeofp() const { return op2p(); } + AstNode* classOrPackagep() const { return op3p(); } + AstPin* paramsp() const { return VN_CAST(op4p(), Pin); } }; class AstStructDType : public AstNodeUOrStructDType { @@ -2429,11 +2441,14 @@ public: class AstModule : public AstNodeModule { // A module declaration +private: + bool m_isProgram; // Module represents a program public: - AstModule(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl, name) {} + AstModule(FileLine* fl, const string& name, bool program = false) + : ASTGEN_SUPER(fl, name) + , m_isProgram(program) {} ASTNODE_NODE_FUNCS(Module) - virtual string verilogKwd() const { return "module"; } + virtual string verilogKwd() const { return m_isProgram ? "program" : "module"; } }; class AstNotFoundModule : public AstNodeModule { @@ -2891,29 +2906,40 @@ public: void ftaskrefp(AstNodeFTaskRef* nodep) { setNOp2p(nodep); } // op2 = Function/task reference }; -class AstPackageRef : public AstNode { +class AstClassOrPackageRef : public AstNode { private: - AstPackage* m_packagep; // Package hierarchy + string m_name; + AstNode* m_classOrPackagep; // Package hierarchy public: - AstPackageRef(FileLine* fl, AstPackage* packagep) + AstClassOrPackageRef(FileLine* fl, const string& name, AstNode* classOrPackagep, + AstNode* paramsp) : ASTGEN_SUPER(fl) - , m_packagep(packagep) {} - ASTNODE_NODE_FUNCS(PackageRef) + , m_name(name) + , m_classOrPackagep(classOrPackagep) { + addNOp4p(paramsp); + } + ASTNODE_NODE_FUNCS(ClassOrPackageRef) // METHODS virtual const char* broken() const { - BROKEN_RTN(!m_packagep || !m_packagep->brokeExists()); + BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); return NULL; } virtual void cloneRelink() { - if (m_packagep && m_packagep->clonep()) { m_packagep = m_packagep->clonep(); } + if (m_classOrPackagep && m_classOrPackagep->clonep()) { + m_classOrPackagep = m_classOrPackagep->clonep(); + } } virtual bool same(const AstNode* samep) const { - return (m_packagep == static_cast(samep)->m_packagep); + return (m_classOrPackagep + == static_cast(samep)->m_classOrPackagep); } - virtual V3Hash sameHash() const { return V3Hash(m_packagep); } + virtual V3Hash sameHash() const { return V3Hash(m_classOrPackagep); } virtual void dump(std::ostream& str = std::cout) const; - AstPackage* packagep() const { return m_packagep; } - void packagep(AstPackage* nodep) { m_packagep = nodep; } + virtual string name() const { return m_name; } // * = Var name + AstNode* classOrPackagep() const { return m_classOrPackagep; } + AstPackage* packagep() const { return VN_CAST(classOrPackagep(), Package); } + void classOrPackagep(AstNode* nodep) { m_classOrPackagep = nodep; } + AstPin* paramsp() const { return VN_CAST(op4p(), Pin); } }; class AstDot : public AstNode { @@ -2929,9 +2955,9 @@ public: } ASTNODE_NODE_FUNCS(Dot) // For parser, make only if non-null package - static AstNode* newIfPkg(FileLine* fl, AstPackage* packagep, AstNode* rhsp) { - if (!packagep) return rhsp; - return new AstDot(fl, true, new AstPackageRef(fl, packagep), rhsp); + static AstNode* newIfPkg(FileLine* fl, AstNode* packageOrClassp, AstNode* rhsp) { + if (!packageOrClassp) return rhsp; + return new AstDot(fl, true, packageOrClassp, rhsp); } virtual void dump(std::ostream& str) const; virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } @@ -5497,6 +5523,7 @@ public: virtual int instrCount() const { return instrCountDouble(); } }; class AstIToRD : public AstNodeUniop { + // $itor where lhs is unsigned public: AstIToRD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) { @@ -5505,10 +5532,27 @@ public: ASTNODE_NODE_FUNCS(IToRD) virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opIToRD(lhs); } virtual string emitVerilog() { return "%f$itor(%l)"; } - virtual string emitC() { return "VL_ITOR_D_I(%li)"; } + virtual string emitC() { return "VL_ITOR_D_%lq(%lw, %li)"; } virtual bool cleanOut() const { return false; } - virtual bool cleanLhs() const { return false; } // Eliminated before matters - virtual bool sizeMattersLhs() const { return false; } // Eliminated before matters + virtual bool cleanLhs() const { return true; } + virtual bool sizeMattersLhs() const { return false; } + virtual int instrCount() const { return instrCountDouble(); } +}; +class AstISToRD : public AstNodeUniop { + // $itor where lhs is signed +public: + AstISToRD(FileLine* fl, AstNode* lhsp) + : ASTGEN_SUPER(fl, lhsp) { + dtypeSetDouble(); + } + ASTNODE_NODE_FUNCS(ISToRD) + virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opISToRD(lhs); } + virtual string emitVerilog() { return "%f$itor($signed(%l))"; } + virtual string emitC() { return "VL_ISTOR_D_%lq(%lw, %li)"; } + virtual bool emitCheckMaxWords() { return true; } + virtual bool cleanOut() const { return false; } + virtual bool cleanLhs() const { return true; } + virtual bool sizeMattersLhs() const { return false; } virtual int instrCount() const { return instrCountDouble(); } }; class AstRealToBits : public AstNodeUniop { @@ -7125,6 +7169,7 @@ public: virtual string emitVerilog() { return "%k(%l %f* %r)"; } virtual string emitC() { return "VL_MULS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } virtual string emitSimpleOperator() { return ""; } + virtual bool emitCheckMaxWords() { return true; } virtual bool cleanOut() const { return false; } virtual bool cleanLhs() const { return true; } virtual bool cleanRhs() const { return true; } @@ -7262,6 +7307,7 @@ public: } virtual string emitVerilog() { return "%k(%l %f** %r)"; } virtual string emitC() { return "VL_POW_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; } + virtual bool emitCheckMaxWords() { return true; } virtual bool cleanOut() const { return false; } virtual bool cleanLhs() const { return true; } virtual bool cleanRhs() const { return true; } @@ -7307,6 +7353,7 @@ public: } virtual string emitVerilog() { return "%k(%l %f** %r)"; } virtual string emitC() { return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 1,0)"; } + virtual bool emitCheckMaxWords() { return true; } virtual bool cleanOut() const { return false; } virtual bool cleanLhs() const { return true; } virtual bool cleanRhs() const { return true; } @@ -7330,6 +7377,7 @@ public: } virtual string emitVerilog() { return "%k(%l %f** %r)"; } virtual string emitC() { return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 1,1)"; } + virtual bool emitCheckMaxWords() { return true; } virtual bool cleanOut() const { return false; } virtual bool cleanLhs() const { return true; } virtual bool cleanRhs() const { return true; } @@ -7353,6 +7401,7 @@ public: } virtual string emitVerilog() { return "%k(%l %f** %r)"; } virtual string emitC() { return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 0,1)"; } + virtual bool emitCheckMaxWords() { return true; } virtual bool cleanOut() const { return false; } virtual bool cleanLhs() const { return true; } virtual bool cleanRhs() const { return true; } @@ -7942,6 +7991,31 @@ public: virtual bool isHeavy() const { return true; } }; +class AstFell : public AstNodeMath { + // Verilog $fell + // Parents: math + // Children: expression +public: + AstFell(FileLine* fl, AstNode* exprp) + : ASTGEN_SUPER(fl) { + addOp1p(exprp); + } + ASTNODE_NODE_FUNCS(Fell) + virtual string emitVerilog() { return "$fell(%l)"; } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + V3ERROR_NA; + } + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const { V3ERROR_NA_RETURN(""); } + virtual int instrCount() const { return widthInstrs(); } + AstNode* exprp() const { return op1p(); } // op1 = expression + AstSenTree* sentreep() const { return VN_CAST(op2p(), SenTree); } // op2 = clock domain + void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain + virtual V3Hash sameHash() const { return V3Hash(); } + virtual bool same(const AstNode* samep) const { return true; } +}; + class AstPast : public AstNodeMath { // Verilog $past // Parents: math @@ -7969,6 +8043,31 @@ public: virtual bool same(const AstNode* samep) const { return true; } }; +class AstRose : public AstNodeMath { + // Verilog $rose + // Parents: math + // Children: expression +public: + AstRose(FileLine* fl, AstNode* exprp) + : ASTGEN_SUPER(fl) { + addOp1p(exprp); + } + ASTNODE_NODE_FUNCS(Rose) + virtual string emitVerilog() { return "$rose(%l)"; } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + V3ERROR_NA; + } + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const { V3ERROR_NA_RETURN(""); } + virtual int instrCount() const { return widthInstrs(); } + AstNode* exprp() const { return op1p(); } // op1 = expression + AstSenTree* sentreep() const { return VN_CAST(op2p(), SenTree); } // op2 = clock domain + void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain + virtual V3Hash sameHash() const { return V3Hash(); } + virtual bool same(const AstNode* samep) const { return true; } +}; + class AstSampled : public AstNodeMath { // Verilog $sampled // Parents: math @@ -7989,6 +8088,31 @@ public: virtual bool same(const AstNode* samep) const { return true; } }; +class AstStable : public AstNodeMath { + // Verilog $stable + // Parents: math + // Children: expression +public: + AstStable(FileLine* fl, AstNode* exprp) + : ASTGEN_SUPER(fl) { + addOp1p(exprp); + } + ASTNODE_NODE_FUNCS(Stable) + virtual string emitVerilog() { return "$stable(%l)"; } + virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { + V3ERROR_NA; + } + virtual string emitC() { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const { V3ERROR_NA_RETURN(""); } + virtual int instrCount() const { return widthInstrs(); } + AstNode* exprp() const { return op1p(); } // op1 = expression + AstSenTree* sentreep() const { return VN_CAST(op2p(), SenTree); } // op2 = clock domain + void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain + virtual V3Hash sameHash() const { return V3Hash(); } + virtual bool same(const AstNode* samep) const { return true; } +}; + class AstPattern : public AstNodeMath { // Verilog '{a,b,c,d...} // Parents: AstNodeAssign, AstPattern, ... diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index 9739e89da..7a0add24c 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -25,7 +25,7 @@ // The following nodes have package pointers and are cleaned up here: // AstRefDType, AstEnumItemRef, AstNodeVarRef, AstNodeFTask // These have packagep but will not exist at this stage -// AstPackageImport, AstDot, AstPackageRef +// AstPackageImport, AstDot, AstClassOrPackageRef // // Note on packagep: After the V3Scope/V3LinkDotScoped stage, package links // are no longer used, but their presence prevents us from removing empty diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index e8e9a1e8f..441ca96be 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -877,6 +877,15 @@ public: emitOpName(nodep, nodep->emitC(), NULL, NULL, NULL); } virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE { + if (nodep->emitCheckMaxWords() + && (nodep->widthWords() > VL_MULS_MAX_WORDS + || nodep->lhsp()->widthWords() > VL_MULS_MAX_WORDS)) { + nodep->v3warn( + E_UNSUPPORTED, + "Unsupported: " + << nodep->prettyOperatorName() << " operator of " << nodep->width() + << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); + } if (emitSimpleOk(nodep)) { putbs("("); puts(nodep->emitSimpleOperator()); @@ -888,6 +897,13 @@ public: } } virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE { + if (nodep->emitCheckMaxWords() && nodep->widthWords() > VL_MULS_MAX_WORDS) { + nodep->v3warn( + E_UNSUPPORTED, + "Unsupported: " + << nodep->prettyOperatorName() << " operator of " << nodep->width() + << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); + } if (emitSimpleOk(nodep)) { putbs("("); iterateAndNextNull(nodep->lhsp()); @@ -915,56 +931,6 @@ public: puts(")"); } } - virtual void visit(AstMulS* nodep) VL_OVERRIDE { - if (nodep->widthWords() > VL_MULS_MAX_WORDS) { - nodep->v3warn( - E_UNSUPPORTED, - "Unsupported: Signed multiply of " - << nodep->width() - << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); - } - visit(VN_CAST(nodep, NodeBiop)); - } - virtual void visit(AstPow* nodep) VL_OVERRIDE { - if (nodep->widthWords() > VL_MULS_MAX_WORDS) { - nodep->v3warn( - E_UNSUPPORTED, - "Unsupported: Power of " - << nodep->width() - << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); - } - visit(VN_CAST(nodep, NodeBiop)); - } - virtual void visit(AstPowSS* nodep) VL_OVERRIDE { - if (nodep->widthWords() > VL_MULS_MAX_WORDS) { - nodep->v3warn( - E_UNSUPPORTED, - "Unsupported: Power of " - << nodep->width() - << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); - } - visit(VN_CAST(nodep, NodeBiop)); - } - virtual void visit(AstPowSU* nodep) VL_OVERRIDE { - if (nodep->widthWords() > VL_MULS_MAX_WORDS) { - nodep->v3warn( - E_UNSUPPORTED, - "Unsupported: Power of " - << nodep->width() - << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); - } - visit(VN_CAST(nodep, NodeBiop)); - } - virtual void visit(AstPowUS* nodep) VL_OVERRIDE { - if (nodep->widthWords() > VL_MULS_MAX_WORDS) { - nodep->v3warn( - E_UNSUPPORTED, - "Unsupported: Power of " - << nodep->width() - << " bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h"); - } - visit(VN_CAST(nodep, NodeBiop)); - } virtual void visit(AstCCast* nodep) VL_OVERRIDE { // Extending a value of the same word width is just a NOP. if (nodep->size() <= VL_IDATASIZE) { @@ -3825,8 +3791,8 @@ void V3EmitC::emitc() { nodep = VN_CAST(nodep->nextp(), NodeModule)) { if (VN_IS(nodep, Class)) continue; // Imped with ClassPackage // clang-format off - { EmitCImp cint; cint.mainInt(nodep); } - { EmitCImp slow; slow.mainImp(nodep, true); } + EmitCImp cint; cint.mainInt(nodep); + cint.mainImp(nodep, true); { EmitCImp fast; fast.mainImp(nodep, false); } // clang-format on } diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 99bd1fcb2..18af595a0 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -429,7 +429,9 @@ public: static AstIfaceRefDType* ifaceRefFromArray(AstNodeDType* nodep) { AstIfaceRefDType* ifacerefp = VN_CAST(nodep, IfaceRefDType); if (!ifacerefp) { - if (AstUnpackArrayDType* arrp = VN_CAST(nodep, UnpackArrayDType)) { + if (AstBracketArrayDType* arrp = VN_CAST(nodep, BracketArrayDType)) { + ifacerefp = VN_CAST(arrp->subDTypep(), IfaceRefDType); + } else if (AstUnpackArrayDType* arrp = VN_CAST(nodep, UnpackArrayDType)) { ifacerefp = VN_CAST(arrp->subDTypep(), IfaceRefDType); } } @@ -1006,12 +1008,6 @@ class LinkDotFindVisitor : public AstNVisitor { // Var: Remember its name for later resolution UASSERT_OBJ(m_curSymp && m_modSymp, nodep, "Var not under module?"); iterateChildren(nodep); - if (m_ftaskp && nodep->isParam()) { - nodep->v3warn(E_UNSUPPORTED, - "Unsupported: Parameters in functions"); // Big3 unsupported too - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - return; - } if (nodep->isFuncLocal() && nodep->lifetime().isStatic()) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'static' function/task variables"); } else if (nodep->isClassMember() && nodep->lifetime().isStatic()) { @@ -1951,7 +1947,7 @@ private: m_ds.m_dotPos = DP_SCOPE; // m_ds.m_dotText communicates the cell prefix between stages - if (VN_IS(nodep->lhsp(), PackageRef)) { + if (VN_IS(nodep->lhsp(), ClassOrPackageRef)) { // if (!start) { nodep->lhsp()->v3error("Package reference may not be embedded in // dotted reference"); m_ds.m_dotErr=true; } m_ds.m_dotPos = DP_PACKAGE; @@ -2047,9 +2043,16 @@ private: expectWhat = "scope/variable"; allowScope = true; allowVar = true; - UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), PackageRef), m_ds.m_dotp->lhsp(), + UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(), "Bad package link"); - packagep = VN_CAST(m_ds.m_dotp->lhsp(), PackageRef)->packagep(); + AstClassOrPackageRef* cpackagerefp + = VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef); + packagep = cpackagerefp->packagep(); + if (!packagep && cpackagerefp->classOrPackagep()) { + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: Class '::' references: " + << AstNode::prettyNameQ(cpackagerefp->name())); + } UASSERT_OBJ(packagep, m_ds.m_dotp->lhsp(), "Bad package link"); m_ds.m_dotSymp = m_statep->getNodeSym(packagep); m_ds.m_dotPos = DP_SCOPE; @@ -2399,11 +2402,19 @@ private: if (nodep->user3SetOnce()) return; UINFO(8, " " << nodep << endl); if (m_ds.m_dotp && m_ds.m_dotPos == DP_PACKAGE) { - UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), PackageRef), m_ds.m_dotp->lhsp(), + UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(), "Bad package link"); - UASSERT_OBJ(VN_CAST(m_ds.m_dotp->lhsp(), PackageRef)->packagep(), m_ds.m_dotp->lhsp(), - "Bad package link"); - nodep->packagep(VN_CAST(m_ds.m_dotp->lhsp(), PackageRef)->packagep()); + AstClassOrPackageRef* cpackagerefp = VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef); + if (cpackagerefp->name() == "process" || cpackagerefp->name() == "local") { + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: " << AstNode::prettyNameQ(cpackagerefp->name())); + } + if (cpackagerefp->paramsp()) { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: parameterized packages"); + } + UASSERT_OBJ(VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef)->packagep(), + m_ds.m_dotp->lhsp(), "Bad package link"); + nodep->packagep(VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef)->packagep()); m_ds.m_dotPos = DP_SCOPE; m_ds.m_dotp = NULL; } else if (m_ds.m_dotp && m_ds.m_dotPos == DP_FINAL) { @@ -2667,12 +2678,30 @@ private: virtual void visit(AstRefDType* nodep) VL_OVERRIDE { // Resolve its reference if (nodep->user3SetOnce()) return; + if (AstNode* cpackagep = nodep->classOrPackagep()) { + if (AstClassOrPackageRef* cpackagerefp = VN_CAST(cpackagep, ClassOrPackageRef)) { + if (cpackagerefp->packagep()) { + nodep->packagep(cpackagerefp->packagep()); + } else { + cpackagep->v3warn(E_UNSUPPORTED, "Unsupported: Class '::' reference"); + // if (cpackagerefp->paramsp()) { + // nodep->v3warn(E_UNSUPPORTED, "Unsupported: parameterized packages"); + // } + } + } else { + cpackagep->v3warn(E_UNSUPPORTED, + "Unsupported: Multiple '::' package/class reference"); + } + VL_DO_DANGLING(cpackagep->unlinkFrBack()->deleteTree(), cpackagep); + } else if (nodep->paramsp()) { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: parameterized packages"); + } if (m_ds.m_dotp && m_ds.m_dotPos == DP_PACKAGE) { - UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), PackageRef), m_ds.m_dotp->lhsp(), + UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(), "Bad package link"); - UASSERT_OBJ(VN_CAST(m_ds.m_dotp->lhsp(), PackageRef)->packagep(), m_ds.m_dotp->lhsp(), - "Bad package link"); - nodep->packagep(VN_CAST(m_ds.m_dotp->lhsp(), PackageRef)->packagep()); + UASSERT_OBJ(VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef)->packagep(), + m_ds.m_dotp->lhsp(), "Bad package link"); + nodep->packagep(VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef)->packagep()); m_ds.m_dotPos = DP_SCOPE; m_ds.m_dotp = NULL; } else { diff --git a/src/V3Number.cpp b/src/V3Number.cpp index e7b19e4e5..d684b9ed5 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -2232,13 +2232,24 @@ V3Number& V3Number::opSelInto(const V3Number& lhs, int lsbval, int width) { //====================================================================== // Ops - Floating point -V3Number& V3Number::opIToRD(const V3Number& lhs) { +V3Number& V3Number::opIToRD(const V3Number& lhs, bool isSigned) { NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_LOGIC_ARGS1(lhs); // IEEE says we ignore x/z in real conversions V3Number noxz(lhs); noxz.opAssignNonXZ(lhs); - return setDouble(noxz.toSInt()); + double d = 0; + bool negate = isSigned && noxz.isNegative(); + if (negate) { + V3Number noxz_signed = noxz; + noxz.opNegate(noxz_signed); + } + for (int bit = noxz.width() - 1; bit >= 0; bit--) { + // Some precision might be lost in this add, that's what we want + if (noxz.bitIs1(bit)) d += exp2(bit); + } + if (negate) d = -d; + return setDouble(d); } V3Number& V3Number::opRToIS(const V3Number& lhs) { NUM_ASSERT_OP_ARGS1(lhs); diff --git a/src/V3Number.h b/src/V3Number.h index 9245b2dfd..1426cfd6e 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -385,7 +385,8 @@ public: V3Number& opLteS(const V3Number& lhs, const V3Number& rhs); // Signed // "D" - double (aka real) math - V3Number& opIToRD(const V3Number& lhs); + V3Number& opIToRD(const V3Number& lhs, bool isSigned = false); + V3Number& opISToRD(const V3Number& lhs) { return opIToRD(lhs, true); } V3Number& opRToIS(const V3Number& lhs); V3Number& opRToIRoundS(const V3Number& lhs); V3Number& opRealToBits(const V3Number& lhs); diff --git a/src/V3Param.cpp b/src/V3Param.cpp index ad43808c2..550abe513 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -106,6 +106,8 @@ private: typedef std::deque CellList; CellList m_cellps; // Cells left to process (in this module) + AstNodeFTask* m_ftaskp; // Function/task reference + AstNodeModule* m_modp; // Current module being processed string m_unlinkedTxt; // Text for AstUnlinkedRef @@ -302,6 +304,11 @@ private: nodep->user5p(genHierNamep); m_cellps.push_back(nodep); } + virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { + m_ftaskp = nodep; + iterateChildren(nodep); + m_ftaskp = NULL; + } // Make sure all parameters are constantified virtual void visit(AstVar* nodep) VL_OVERRIDE { @@ -323,6 +330,16 @@ private: new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, true), nodep->valuep()->cloneTree(true)))); + if (m_ftaskp) { + // We put the initial in wrong place under a function. We + // should move the parameter out of the function and to the + // module, with appropriate dotting, but this confuses LinkDot + // (as then name isn't found later), so punt - probably can + // treat as static function variable when that is supported. + nodep->v3warn( + E_UNSUPPORTED, + "Unsupported: Parameters in functions with complex assign"); + } } } } @@ -556,6 +573,7 @@ public: // CONSTRUCTORS explicit ParamVisitor(AstNetlist* nodep) { m_longId = 0; + m_ftaskp = NULL; m_modp = NULL; m_nextValue = 1; // @@ -617,7 +635,7 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) { // This prevents making additional modules, and makes coverage more // obvious as it won't show up under a unique module page name. } else if (exprp->num().isDouble() || exprp->num().isString() - || exprp->num().isFourState()) { + || exprp->num().isFourState() || exprp->num().width() != 32) { longname += ("_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp)); any_overrides = true; diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index 4c904b2cb..d9d5ae2f1 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -139,7 +139,6 @@ struct V3ParseBisonYYSType { AstSenItem* senitemp; AstNodeVarRef* varnodep; AstPackage* packagep; - AstPackageRef* packagerefp; AstParseRef* parserefp; AstPatMember* patmemberp; AstPattern* patternp; diff --git a/src/V3ProtectLib.cpp b/src/V3ProtectLib.cpp index 06fd9d726..5d6c2fe28 100644 --- a/src/V3ProtectLib.cpp +++ b/src/V3ProtectLib.cpp @@ -60,6 +60,7 @@ private: string m_libName; string m_topName; bool m_foundTop; // Have seen the top module + bool m_hasClk; // True if the top module has sequential logic // VISITORS virtual void visit(AstNetlist* nodep) VL_OVERRIDE { @@ -79,6 +80,8 @@ private: UASSERT_OBJ(!m_foundTop, nodep, "Multiple root modules"); } FileLine* fl = nodep->fileline(); + // Need to know the existence of clk before createSvFile() + m_hasClk = checkIfClockExists(nodep); createSvFile(fl); createCppFile(fl); @@ -162,14 +165,16 @@ private: txtp->addNodep(m_comboPortsp); txtp->addText(fl, ");\n\n"); seqComment(txtp, fl); - m_seqPortsp = new AstTextBlock(fl, - "import \"DPI-C\" function longint " + m_libName - + "_protectlib_seq_update" - "(\n", - false, true); - m_seqPortsp->addText(fl, "chandle handle__V\n"); - txtp->addNodep(m_seqPortsp); - txtp->addText(fl, ");\n\n"); + if (m_hasClk) { + m_seqPortsp = new AstTextBlock(fl, + "import \"DPI-C\" function longint " + m_libName + + "_protectlib_seq_update" + "(\n", + false, true); + m_seqPortsp->addText(fl, "chandle handle__V\n"); + txtp->addNodep(m_seqPortsp); + txtp->addText(fl, ");\n\n"); + } comboIgnoreComment(txtp, fl); m_comboIgnorePortsp = new AstTextBlock(fl, "import \"DPI-C\" function void " + m_libName @@ -192,12 +197,12 @@ private: m_tmpDeclsp = new AstTextBlock(fl); txtp->addNodep(m_tmpDeclsp); txtp->addText(fl, "\ntime last_combo_seqnum__V;\n"); - txtp->addText(fl, "time last_seq_seqnum__V;\n\n"); + if (m_hasClk) { txtp->addText(fl, "time last_seq_seqnum__V;\n\n"); } // CPP hash value addComment(txtp, fl, "Hash value to make sure this file and the corresponding"); addComment(txtp, fl, "library agree"); - m_hashValuep = new AstTextBlock(fl, "localparam int protectlib_hash__V = "); + m_hashValuep = new AstTextBlock(fl, "localparam int protectlib_hash__V = 32'd"); txtp->addNodep(m_hashValuep); txtp->addText(fl, "\n"); @@ -222,33 +227,41 @@ private: txtp->addText(fl, "end\n\n"); // Sequential process - addComment(txtp, fl, "Evaluate clock edges"); - m_clkSensp = new AstTextBlock(fl, "always @(", false, true); - txtp->addNodep(m_clkSensp); - txtp->addText(fl, ") begin\n"); - m_comboIgnoreParamsp - = new AstTextBlock(fl, m_libName + "_protectlib_combo_ignore(\n", false, true); - m_comboIgnoreParamsp->addText(fl, "handle__V\n"); - txtp->addNodep(m_comboIgnoreParamsp); - txtp->addText(fl, ");\n"); - m_seqParamsp = new AstTextBlock( - fl, "last_seq_seqnum__V <= " + m_libName + "_protectlib_seq_update(\n", false, true); - m_seqParamsp->addText(fl, "handle__V\n"); - txtp->addNodep(m_seqParamsp); - txtp->addText(fl, ");\n"); - m_nbAssignsp = new AstTextBlock(fl); - txtp->addNodep(m_nbAssignsp); - txtp->addText(fl, "end\n\n"); + if (m_hasClk) { + addComment(txtp, fl, "Evaluate clock edges"); + m_clkSensp = new AstTextBlock(fl, "always @(", false, true); + txtp->addNodep(m_clkSensp); + txtp->addText(fl, ") begin\n"); + m_comboIgnoreParamsp + = new AstTextBlock(fl, m_libName + "_protectlib_combo_ignore(\n", false, true); + m_comboIgnoreParamsp->addText(fl, "handle__V\n"); + txtp->addNodep(m_comboIgnoreParamsp); + txtp->addText(fl, ");\n"); + m_seqParamsp = new AstTextBlock( + fl, "last_seq_seqnum__V <= " + m_libName + "_protectlib_seq_update(\n", false, + true); + m_seqParamsp->addText(fl, "handle__V\n"); + txtp->addNodep(m_seqParamsp); + txtp->addText(fl, ");\n"); + m_nbAssignsp = new AstTextBlock(fl); + txtp->addNodep(m_nbAssignsp); + txtp->addText(fl, "end\n\n"); + } // Select between combinatorial and sequential results addComment(txtp, fl, "Select between combinatorial and sequential results"); txtp->addText(fl, "always @(*) begin\n"); - m_seqAssignsp = new AstTextBlock(fl, "if (last_seq_seqnum__V > " - "last_combo_seqnum__V) begin\n"); - txtp->addNodep(m_seqAssignsp); - m_comboAssignsp = new AstTextBlock(fl, "end else begin\n"); - txtp->addNodep(m_comboAssignsp); - txtp->addText(fl, "end\n"); + if (m_hasClk) { + m_seqAssignsp = new AstTextBlock(fl, "if (last_seq_seqnum__V > " + "last_combo_seqnum__V) begin\n"); + txtp->addNodep(m_seqAssignsp); + m_comboAssignsp = new AstTextBlock(fl, "end else begin\n"); + txtp->addNodep(m_comboAssignsp); + txtp->addText(fl, "end\n"); + } else { + m_comboAssignsp = new AstTextBlock(fl, ""); + txtp->addNodep(m_comboAssignsp); + } txtp->addText(fl, "end\n\n"); // Final @@ -327,19 +340,21 @@ private: txtp->addText(fl, "return handlep__V->m_seqnum++;\n"); txtp->addText(fl, "}\n\n"); - seqComment(txtp, fl); - m_cSeqParamsp = new AstTextBlock( - fl, "long long " + m_libName + "_protectlib_seq_update(\n", false, true); - m_cSeqParamsp->addText(fl, "void* vhandlep__V\n"); - txtp->addNodep(m_cSeqParamsp); - txtp->addText(fl, ")\n"); - m_cSeqClksp = new AstTextBlock(fl, "{\n"); - castPtr(fl, m_cSeqClksp); - txtp->addNodep(m_cSeqClksp); - m_cSeqOutsp = new AstTextBlock(fl, "handlep__V->eval();\n"); - txtp->addNodep(m_cSeqOutsp); - txtp->addText(fl, "return handlep__V->m_seqnum++;\n"); - txtp->addText(fl, "}\n\n"); + if (m_hasClk) { + seqComment(txtp, fl); + m_cSeqParamsp = new AstTextBlock( + fl, "long long " + m_libName + "_protectlib_seq_update(\n", false, true); + m_cSeqParamsp->addText(fl, "void* vhandlep__V\n"); + txtp->addNodep(m_cSeqParamsp); + txtp->addText(fl, ")\n"); + m_cSeqClksp = new AstTextBlock(fl, "{\n"); + castPtr(fl, m_cSeqClksp); + txtp->addNodep(m_cSeqClksp); + m_cSeqOutsp = new AstTextBlock(fl, "handlep__V->eval();\n"); + txtp->addNodep(m_cSeqOutsp); + txtp->addText(fl, "return handlep__V->m_seqnum++;\n"); + txtp->addText(fl, "}\n\n"); + } comboIgnoreComment(txtp, fl); m_cIgnoreParamsp = new AstTextBlock( @@ -369,6 +384,7 @@ private: } if (nodep->direction() == VDirection::INPUT) { if (nodep->isUsedClock() || nodep->attrClocker() == VVarAttrClocker::CLOCKER_YES) { + UASSERT_OBJ(m_hasClk, nodep, "checkIfClockExists() didn't find this clock"); handleClock(nodep); } else { handleDataInput(nodep); @@ -396,8 +412,10 @@ private: FileLine* fl = varp->fileline(); handleInput(varp); m_seqPortsp->addNodep(varp->cloneTree(false)); - m_seqParamsp->addText(fl, varp->name() + "\n"); - m_clkSensp->addText(fl, "edge(" + varp->name() + ")"); + if (m_hasClk) { + m_seqParamsp->addText(fl, varp->name() + "\n"); + m_clkSensp->addText(fl, "posedge " + varp->name() + " or negedge " + varp->name()); + } m_cSeqParamsp->addText(fl, varp->dpiArgType(true, false) + "\n"); m_cSeqClksp->addText(fl, cInputConnection(varp)); } @@ -408,7 +426,7 @@ private: m_comboPortsp->addNodep(varp->cloneTree(false)); m_comboParamsp->addText(fl, varp->name() + "\n"); m_comboIgnorePortsp->addNodep(varp->cloneTree(false)); - m_comboIgnoreParamsp->addText(fl, varp->name() + "\n"); + if (m_hasClk) { m_comboIgnoreParamsp->addText(fl, varp->name() + "\n"); } m_cComboParamsp->addText(fl, varp->dpiArgType(true, false) + "\n"); m_cComboInsp->addText(fl, cInputConnection(varp)); m_cIgnoreParamsp->addText(fl, varp->dpiArgType(true, false) + "\n"); @@ -421,29 +439,49 @@ private: m_modPortsp->addNodep(varp->cloneTree(false)); m_comboPortsp->addNodep(varp->cloneTree(false)); m_comboParamsp->addText(fl, varp->name() + "_combo__V\n"); - m_seqPortsp->addNodep(varp->cloneTree(false)); - m_seqParamsp->addText(fl, varp->name() + "_tmp__V\n"); + if (m_hasClk) { + m_seqPortsp->addNodep(varp->cloneTree(false)); + m_seqParamsp->addText(fl, varp->name() + "_tmp__V\n"); + } AstNodeDType* comboDtypep = varp->dtypep()->cloneTree(false); m_comboDeclsp->addNodep(comboDtypep); m_comboDeclsp->addText(fl, " " + varp->name() + "_combo__V;\n"); - AstNodeDType* seqDtypep = varp->dtypep()->cloneTree(false); - m_seqDeclsp->addNodep(seqDtypep); - m_seqDeclsp->addText(fl, " " + varp->name() + "_seq__V;\n"); + if (m_hasClk) { + AstNodeDType* seqDtypep = varp->dtypep()->cloneTree(false); + m_seqDeclsp->addNodep(seqDtypep); + m_seqDeclsp->addText(fl, " " + varp->name() + "_seq__V;\n"); - AstNodeDType* tmpDtypep = varp->dtypep()->cloneTree(false); - m_tmpDeclsp->addNodep(tmpDtypep); - m_tmpDeclsp->addText(fl, " " + varp->name() + "_tmp__V;\n"); + AstNodeDType* tmpDtypep = varp->dtypep()->cloneTree(false); + m_tmpDeclsp->addNodep(tmpDtypep); + m_tmpDeclsp->addText(fl, " " + varp->name() + "_tmp__V;\n"); - m_nbAssignsp->addText(fl, varp->name() + "_seq__V <= " + varp->name() + "_tmp__V;\n"); - m_seqAssignsp->addText(fl, varp->name() + " = " + varp->name() + "_seq__V;\n"); + m_nbAssignsp->addText(fl, varp->name() + "_seq__V <= " + varp->name() + "_tmp__V;\n"); + m_seqAssignsp->addText(fl, varp->name() + " = " + varp->name() + "_seq__V;\n"); + } m_comboAssignsp->addText(fl, varp->name() + " = " + varp->name() + "_combo__V;\n"); m_cComboParamsp->addText(fl, varp->dpiArgType(true, false) + "\n"); m_cComboOutsp->addText(fl, V3Task::assignInternalToDpi(varp, true, "", "", "handlep__V->")); - m_cSeqParamsp->addText(fl, varp->dpiArgType(true, false) + "\n"); - m_cSeqOutsp->addText(fl, V3Task::assignInternalToDpi(varp, true, "", "", "handlep__V->")); + if (m_hasClk) { + m_cSeqParamsp->addText(fl, varp->dpiArgType(true, false) + "\n"); + m_cSeqOutsp->addText(fl, + V3Task::assignInternalToDpi(varp, true, "", "", "handlep__V->")); + } + } + + static bool checkIfClockExists(AstNodeModule* modp) { + for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) { + if (AstVar* varp = VN_CAST(stmtp, Var)) { + if (varp->direction() == VDirection::INPUT + && (varp->isUsedClock() + || varp->attrClocker() == VVarAttrClocker::CLOCKER_YES)) { + return true; + } + } + } + return false; } public: @@ -475,7 +513,8 @@ public: , m_cIgnoreParamsp(NULL) , m_libName(v3Global.opt.protectLib()) , m_topName(v3Global.opt.prefix()) - , m_foundTop(false) { + , m_foundTop(false) + , m_hasClk(false) { iterate(nodep); } }; diff --git a/src/V3Width.cpp b/src/V3Width.cpp index de04c0a82..194e46c18 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -332,7 +332,6 @@ private: //======== // Widths: Output real, input integer signed virtual void visit(AstBitsToRealD* nodep) VL_OVERRIDE { visit_Or_Lu64(nodep); } - virtual void visit(AstIToRD* nodep) VL_OVERRIDE { visit_Or_Ls32(nodep); } // Widths: Output integer signed, input real virtual void visit(AstRToIS* nodep) VL_OVERRIDE { visit_Os32_Lr(nodep); } @@ -1032,6 +1031,12 @@ private: // We don't size the constant until we commit the widths, as need parameters // to remain unsized, and numbers to remain unsized to avoid backp() warnings } + virtual void visit(AstFell* nodep) VL_OVERRIDE { + if (m_vup->prelim()) { + iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH); + nodep->dtypeSetLogicBool(); + } + } virtual void visit(AstPast* nodep) VL_OVERRIDE { if (m_vup->prelim()) { iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH); @@ -1056,12 +1061,27 @@ private: } } } + virtual void visit(AstRose* nodep) VL_OVERRIDE { + if (m_vup->prelim()) { + iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH); + nodep->dtypeSetLogicBool(); + } + } + virtual void visit(AstSampled* nodep) VL_OVERRIDE { if (m_vup->prelim()) { iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH); nodep->dtypeFrom(nodep->exprp()); } } + + virtual void visit(AstStable* nodep) VL_OVERRIDE { + if (m_vup->prelim()) { + iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH); + nodep->dtypeSetLogicBool(); + } + } + virtual void visit(AstRand* nodep) VL_OVERRIDE { if (m_vup->prelim()) { nodep->dtypeSetSigned32(); // Says the spec @@ -1524,7 +1544,8 @@ private: virtual void visit(AstCast* nodep) VL_OVERRIDE { nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); // if (debug()) nodep->dumpTree(cout, " CastPre: "); - userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p()); + userIterateAndNext(nodep->lhsp(), WidthVP(SELF, PRELIM).p()); + // When more general casts are supported, the cast elimination will be done later. // For now, replace it ASAP, so widthing can propagate easily // The cast may change signing, but we don't know the sign yet. Make it so. @@ -1537,11 +1558,19 @@ private: // Note widthCheckSized might modify nodep->lhsp() AstNodeDType* subDTypep = nodep->findLogicDType(nodep->width(), nodep->width(), nodep->lhsp()->dtypep()->numeric()); - widthCheckSized(nodep, "Cast", nodep->lhsp(), subDTypep, EXTEND_EXP, false); + iterateCheck(nodep, "value", nodep->lhsp(), CONTEXT, FINAL, subDTypep, EXTEND_EXP, + false); + } else { + iterateCheck(nodep, "value", nodep->lhsp(), SELF, FINAL, nodep->lhsp()->dtypep(), + EXTEND_EXP, false); } AstNode* newp = nodep->lhsp()->unlinkFrBack(); if (basicp->isDouble() && !newp->isDouble()) { - newp = new AstIToRD(nodep->fileline(), newp); + if (newp->isSigned()) { + newp = new AstISToRD(nodep->fileline(), newp); + } else { + newp = new AstIToRD(nodep->fileline(), newp); + } } else if (!basicp->isDouble() && newp->isDouble()) { if (basicp->isSigned()) { newp = new AstRToIRoundS(nodep->fileline(), newp); @@ -3923,16 +3952,27 @@ private: iterateCheck(nodep, "LHS", nodep->lhsp(), SELF, FINAL, subDTypep, EXTEND_EXP); } } - void visit_Or_Ls32(AstNodeUniop* nodep) { - // CALLER: AstIToRD + virtual void visit(AstIToRD* nodep) VL_OVERRIDE { // Real: Output real // LHS presumed self-determined, then coerced to real if (m_vup->prelim()) { // First stage evaluation nodep->dtypeSetDouble(); - AstNodeDType* subDTypep = nodep->findLogicDType(32, 32, VSigning::SIGNED); - // Self-determined operand + // Self-determined operand (TODO check if numeric type) + userIterateAndNext(nodep->lhsp(), WidthVP(SELF, PRELIM).p()); + if (nodep->lhsp()->isSigned()) { + nodep->replaceWith( + new AstISToRD(nodep->fileline(), nodep->lhsp()->unlinkFrBack())); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } + } + } + virtual void visit(AstISToRD* nodep) VL_OVERRIDE { + // Real: Output real + // LHS presumed self-determined, then coerced to real + if (m_vup->prelim()) { // First stage evaluation + nodep->dtypeSetDouble(); + // Self-determined operand (TODO check if numeric type) userIterateAndNext(nodep->lhsp(), WidthVP(SELF, PRELIM).p()); - iterateCheck(nodep, "LHS", nodep->lhsp(), SELF, FINAL, subDTypep, EXTEND_EXP); } } void visit_Os32_Lr(AstNodeUniop* nodep) { @@ -4792,7 +4832,12 @@ private: UINFO(6, " spliceCvtD: " << nodep << endl); AstNRelinker linker; nodep->unlinkFrBack(&linker); - AstNode* newp = new AstIToRD(nodep->fileline(), nodep); + AstNode* newp; + if (nodep->dtypep()->skipRefp()->isSigned()) { + newp = new AstISToRD(nodep->fileline(), nodep); + } else { + newp = new AstIToRD(nodep->fileline(), nodep); + } linker.relink(newp); return newp; } else { diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 66800410b..dc040cc50 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -193,12 +193,16 @@ static void process() { // Expand inouts, stage 2 // Also simplify pin connections to always be AssignWs in prep for V3Unknown V3Tristate::tristateAll(v3Global.rootp()); + } + if (!v3Global.opt.xmlOnly()) { // Move assignments from X into MODULE temps. // (Before flattening, so each new X variable is shared between all scopes of that module.) V3Unknown::unknownAll(v3Global.rootp()); v3Global.constRemoveXs(true); + } + if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { // Module inlining // Cannot remove dead variables after this, as alias information for final // V3Scope's V3LinkDot is in the AstVar. diff --git a/src/verilog.l b/src/verilog.l index c309be3fd..f21a64f1c 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -422,6 +422,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$dimensions" { FL; return yD_DIMENSIONS; } "$error" { FL; return yD_ERROR; } "$fatal" { FL; return yD_FATAL; } + "$fell" { FL; return yD_FELL; } "$high" { FL; return yD_HIGH; } "$increment" { FL; return yD_INCREMENT; } "$info" { FL; return yD_INFO; } @@ -434,7 +435,9 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$past" { FL; return yD_PAST; } "$right" { FL; return yD_RIGHT; } "$root" { FL; return yD_ROOT; } + "$rose" { FL; return yD_ROSE; } "$size" { FL; return yD_SIZE; } + "$stable" { FL; return yD_STABLE; } "$unpacked_dimensions" { FL; return yD_UNPACKED_DIMENSIONS; } "$warning" { FL; return yD_WARNING; } /* SV2005 Keywords */ diff --git a/src/verilog.y b/src/verilog.y index fa324cdfa..9ae8db91a 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -264,17 +264,6 @@ int V3ParseGrammar::s_modTypeImpNum = 0; GRAMMARP->m_instParamp = paramsp; \ } -static AstPackage* CAST_PACKAGE_CLASS(AstNode* nodep) { - if (!nodep) { - return NULL; - } else if (AstPackage* pkgp = VN_CAST(nodep, Package)) { - return pkgp; - } else { - BBUNSUP(nodep->fileline(), "Unsupported class :: reference"); - return NULL; - } -} - #define DEL(nodep) \ { \ if (nodep) nodep->deleteTree(); \ @@ -730,6 +719,7 @@ BISONPRE_VERSION(3.0,%define parse.error verbose) %token yD_FDISPLAYB "$fdisplayb" %token yD_FDISPLAYH "$fdisplayh" %token yD_FDISPLAYO "$fdisplayo" +%token yD_FELL "$fell" %token yD_FEOF "$feof" %token yD_FERROR "$ferror" %token yD_FFLUSH "$fflush" @@ -771,6 +761,7 @@ BISONPRE_VERSION(3.0,%define parse.error verbose) %token yD_REWIND "$rewind" %token yD_RIGHT "$right" %token yD_ROOT "$root" +%token yD_ROSE "$rose" %token yD_RTOI "$rtoi" %token yD_SAMPLED "$sampled" %token yD_SFORMAT "$sformat" @@ -782,6 +773,7 @@ BISONPRE_VERSION(3.0,%define parse.error verbose) %token yD_SIZE "$size" %token yD_SQRT "$sqrt" %token yD_SSCANF "$sscanf" +%token yD_STABLE "$stable" %token yD_STIME "$stime" %token yD_STOP "$stop" %token yD_SWRITE "$swrite" @@ -1476,7 +1468,7 @@ program_declaration: // IEEE: program_declaration + program_nonansi_header + pr pgmFront: yPROGRAM lifetimeE idAny/*new_program*/ - { $$ = new AstModule($3,*$3); + { $$ = new AstModule($3, *$3, true); $$->lifetime($2); $$->inLibrary(PARSEP->inLibrary() || $$->fileline()->celldefineOn()); $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); @@ -1783,8 +1775,8 @@ simple_type: // ==IEEE: simple_type // // Even though we looked up the type and have a AstNode* to it, // // we can't fully resolve it because it may have been just a forward definition. | packageClassScopeE idType - { AstRefDType* refp = new AstRefDType($2, *$2); - refp->packagep($1); $$ = refp; } + { AstRefDType* refp = new AstRefDType($2, *$2, $1, NULL); + $$ = refp; } // // // { generate_block_identifer ... } '.' // // Need to determine if generate_block_identifier can be lex-detected @@ -1801,13 +1793,10 @@ data_type: // ==IEEE: data_type // // IEEE: ps_covergroup_identifier // // Don't distinguish between types and classes so all these combined | packageClassScopeE idType packed_dimensionListE - { AstRefDType* refp = new AstRefDType($2, *$2); - refp->packagep($1); + { AstRefDType* refp = new AstRefDType($2, *$2, $1, NULL); $$ = GRAMMARP->createArray(refp, $3, true); } | packageClassScopeE idType parameter_value_assignmentClass packed_dimensionListE - { AstRefDType* refp = new AstRefDType($2, *$2); - refp->packagep($1); - BBUNSUP($3->fileline(), "Unsupported: Parameter classes"); + { AstRefDType* refp = new AstRefDType($2, *$2, $1, $3); $$ = GRAMMARP->createArray(refp, $4, true); } ; @@ -1851,7 +1840,8 @@ var_data_type: // ==IEEE: var_data_type ; type_reference: // ==IEEE: type_reference - yTYPE '(' exprOrDataType ')' { $$ = new AstRefDType($1, AstRefDType::FlagTypeOfExpr(), $3); } + yTYPE '(' exprOrDataType ')' + { $$ = new AstRefDType($1, AstRefDType::FlagTypeOfExpr(), $3); } ; struct_unionDecl: // IEEE: part of data_type @@ -2021,8 +2011,7 @@ enum_base_typeE: // IEEE: enum_base_type | idAny rangeListE { $$ = GRAMMARP->createArray(new AstRefDType($1, *$1), $2, true); } | packageClassScope idAny rangeListE - { AstRefDType* refp = new AstRefDType($2, *$2); - refp->packagep($1); + { AstRefDType* refp = new AstRefDType($2, *$2, $1, NULL); $$ = GRAMMARP->createArray(refp, $3, true); } ; @@ -2526,7 +2515,7 @@ delay_control: //== IEEE: delay_control delay_value: // ==IEEE:delay_value // // IEEE: ps_identifier - packageClassScopeE varRefBase { $$ = $2; $2->packagep($1); } + packageClassScopeE varRefBase { $$ = AstDot::newIfPkg($2, $1, $2); } | yaINTNUM { $$ = new AstConst($1, *$1); } | yaFLOATNUM { $$ = new AstConst($1, AstConst::RealDouble(), $1); } | timeNumAdjusted { $$ = $1; } @@ -3412,7 +3401,7 @@ taskRef: // IEEE: part of tf_call id { $$ = new AstTaskRef($1,*$1,NULL); } | id '(' list_of_argumentsE ')' { $$ = new AstTaskRef($1,*$1,$3); } | packageClassScope id '(' list_of_argumentsE ')' - { $$ = AstDot::newIfPkg($2, CAST_PACKAGE_CLASS($1), new AstTaskRef($2, *$2, $4)); } + { $$ = AstDot::newIfPkg($2, $1, new AstTaskRef($2, *$2, $4)); } ; funcRef: // IEEE: part of tf_call @@ -3428,7 +3417,7 @@ funcRef: // IEEE: part of tf_call id '(' list_of_argumentsE ')' { $$ = new AstFuncRef($1, *$1, $3); } | packageClassScope id '(' list_of_argumentsE ')' - { $$ = AstDot::newIfPkg($2, CAST_PACKAGE_CLASS($1), new AstFuncRef($2, *$2, $4)); } + { $$ = AstDot::newIfPkg($2, $1, new AstFuncRef($2, *$2, $4)); } //UNSUP list_of_argumentE should be pev_list_of_argumentE //UNSUP: idDotted is really just id to allow dotted method calls ; @@ -3609,6 +3598,8 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task or func) | yD_COUNTONES '(' expr ')' { $$ = new AstCountOnes($1,$3); } | yD_DIMENSIONS '(' exprOrDataType ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_DIMENSIONS,$3); } | yD_EXP '(' expr ')' { $$ = new AstExpD($1,$3); } + | yD_FELL '(' expr ')' { $$ = new AstFell($1,$3); } + | yD_FELL '(' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $fell and clock arguments"); } | yD_FEOF '(' expr ')' { $$ = new AstFEof($1,$3); } | yD_FERROR '(' idClassSel ',' idClassSel ')' { $$ = new AstFError($1, $3, $5); } | yD_FGETC '(' expr ')' { $$ = new AstFGetC($1,$3); } @@ -3650,6 +3641,8 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task or func) | yD_REWIND '(' idClassSel ')' { $$ = new AstFSeek($1, $3, new AstConst($1, 0), new AstConst($1, 0)); } | yD_RIGHT '(' exprOrDataType ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_RIGHT,$3,NULL); } | yD_RIGHT '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_RIGHT,$3,$5); } + | yD_ROSE '(' expr ')' { $$ = new AstRose($1,$3); } + | yD_ROSE '(' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $rose and clock arguments"); } | yD_RTOI '(' expr ')' { $$ = new AstRToIS($1,$3); } | yD_SAMPLED '(' expr ')' { $$ = new AstSampled($1, $3); } | yD_SFORMATF '(' exprDispList ')' { $$ = new AstSFormatF($1, AstSFormatF::NoFormat(), $3, 'd', false); } @@ -3662,6 +3655,8 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task or func) | yD_SQRT '(' expr ')' { $$ = new AstSqrtD($1,$3); } | yD_SSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstSScanF($1,*$5,$3,$6); } | yD_STIME parenE { $$ = new AstSel($1, new AstTime($1, VTimescale(VTimescale::NONE)), 0, 32); } + | yD_STABLE '(' expr ')' { $$ = new AstStable($1,$3); } + | yD_STABLE '(' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $stable and clock arguments"); } | yD_TAN '(' expr ')' { $$ = new AstTanD($1,$3); } | yD_TANH '(' expr ')' { $$ = new AstTanhD($1,$3); } | yD_TESTPLUSARGS '(' str ')' { $$ = new AstTestPlusArgs($1,*$3); } @@ -4263,7 +4258,7 @@ exprScope: // scope and variable for use to inside an expression yTHIS { $$ = new AstParseRef($1, VParseRefExp::PX_ROOT, "this"); } | yD_ROOT { $$ = new AstParseRef($1, VParseRefExp::PX_ROOT, "$root"); } | idArrayed { $$ = $1; } - | packageClassScope idArrayed { $$ = AstDot::newIfPkg($2->fileline(), CAST_PACKAGE_CLASS($1), $2); } + | packageClassScope idArrayed { $$ = AstDot::newIfPkg($2->fileline(), $1, $2); } | ~l~expr '.' idArrayed { $$ = new AstDot($2, false, $1, $3); } // // expr below must be a "yTHIS" | ~l~expr '.' ySUPER { $$ = $1; BBUNSUP($3, "Unsupported: super"); } @@ -4742,7 +4737,7 @@ idClassSel: // Misc Ref to dotted, and/or arrayed, and/or bit-ranged va { $$ = new AstDot($2, false, new AstParseRef($1, VParseRefExp::PX_ROOT, "super"), $3); } | yTHIS '.' ySUPER '.' idDotted { $$ = $5; BBUNSUP($1, "Unsupported: this.super"); } // // Expanded: package_scope idDotted - | packageClassScope idDotted { $$ = $2; BBUNSUP($2, "Unsupported: package scoped id"); } + | packageClassScope idDotted { $$ = new AstDot($2, true, $1, $2); } ; idClassSelForeach: @@ -4754,7 +4749,7 @@ idClassSelForeach: { $$ = new AstDot($2, false, new AstParseRef($1, VParseRefExp::PX_ROOT, "super"), $3); } | yTHIS '.' ySUPER '.' idDottedForeach { $$ = $5; BBUNSUP($1, "Unsupported: this.super"); } // // Expanded: package_scope idForeach - | packageClassScope idDottedForeach { $$ = $2; BBUNSUP($2, "Unsupported: package/class scoped id"); } + | packageClassScope idDottedForeach { $$ = new AstDot($2, true, $1, $2); } ; idDotted: @@ -4785,7 +4780,8 @@ idDottedMoreForeach: // id below includes: // enum_identifier idArrayed: // IEEE: id + select - id { $$ = new AstParseRef($1, VParseRefExp::PX_TEXT, *$1, NULL, NULL); } + id + { $$ = new AstParseRef($1, VParseRefExp::PX_TEXT, *$1, NULL, NULL); } // // IEEE: id + part_select_range/constant_part_select_range | idArrayed '[' expr ']' { $$ = new AstSelBit($2, $1, $3); } // Or AstArraySel, don't know yet. | idArrayed '[' constExpr ':' constExpr ']' { $$ = new AstSelExtract($2, $1, $3, $5); } @@ -4795,7 +4791,8 @@ idArrayed: // IEEE: id + select ; idArrayedForeach: // IEEE: id + select (under foreach expression) - id { $$ = new AstParseRef($1, VParseRefExp::PX_TEXT, *$1, NULL, NULL); } + id + { $$ = new AstParseRef($1, VParseRefExp::PX_TEXT, *$1, NULL, NULL); } // // IEEE: id + part_select_range/constant_part_select_range | idArrayed '[' expr ']' { $$ = new AstSelBit($2, $1, $3); } // Or AstArraySel, don't know yet. | idArrayed '[' constExpr ':' constExpr ']' { $$ = new AstSelExtract($2, $1, $3, $5); } @@ -5888,18 +5885,17 @@ class_typeExtImpOne: // part of IEEE: class_type, where we either get a p idAny /*mid*/ { /* no nextId as not refing it above this*/ } /*cont*/ parameter_value_assignmentE - { $$ = new AstParseRef($1, VParseRefExp::PX_TEXT, *$1, NULL, NULL); - $$ = $1; - if ($3) BBUNSUP($3->fileline(), "Unsupported: Parameterized classes"); } + { $$ = new AstClassOrPackageRef($1, *$1, $1, $3); + $$ = $1; } // // // package_sopeIdFollows expanded | yD_UNIT yP_COLONCOLON - { $$ = new AstParseRef($1, VParseRefExp::PX_TEXT, "$unit", NULL, NULL); + { $$ = new AstClassOrPackageRef($1, "$unit", NULL, NULL); $$ = NULL; // No purpose otherwise, every symtab can see root SYMP->nextId(PARSEP->rootp()); } // | yLOCAL__COLONCOLON yP_COLONCOLON - { $$ = new AstParseRef($1, VParseRefExp::PX_TEXT, "local", NULL, NULL); + { $$ = new AstClassOrPackageRef($1, "local::", NULL, NULL); $$ = NULL; // UNSUP SYMP->nextId(PARSEP->rootp()); BBUNSUP($1, "Unsupported: Randomize 'local::'"); } @@ -5912,11 +5908,11 @@ class_typeExtImpOne: // part of IEEE: class_type, where we either get a p //=== Below rules assume special scoping per above -packageClassScopeNoId: // IEEE: [package_scope] not followed by yaID +packageClassScopeNoId: // IEEE: [package_scope] not followed by yaID packageClassScope { $$ = $1; $$ = $1; SYMP->nextId(NULL); } ; -packageClassScopeE: // IEEE: [package_scope] +packageClassScopeE: // IEEE: [package_scope] // // IMPORTANT: The lexer will parse the following ID to be in the found package // // if not needed must use packageClassScopeNoId // // TODO: To support classes should return generic type, not packagep @@ -5925,7 +5921,7 @@ packageClassScopeE: // IEEE: [package_scope] | packageClassScope { $$ = $1; $$ = $1; } ; -packageClassScope: // IEEE: class_scope + type +packageClassScope: // IEEE: class_scope // // IEEE: "class_type yP_COLONCOLON" // // IMPORTANT: The lexer will parse the following ID to be in the found package // // if not needed must use packageClassScopeNoId @@ -5934,10 +5930,11 @@ packageClassScope: // IEEE: class_scope + type packageClassScopeList { $$ = $1; $$ = $1; } | localNextId yP_COLONCOLON { $$ = $1; $$ = $1; } | dollarUnitNextId yP_COLONCOLON { $$ = $1; $$ = $1; } - | dollarUnitNextId yP_COLONCOLON packageClassScopeList { $$ = $3; $$ = $3; } + | dollarUnitNextId yP_COLONCOLON packageClassScopeList + { $$ = new AstDot($2, true, $1, $3); $$ = $3; } ; -packageClassScopeList: // IEEE: class_type: "id [ parameter_value_assignment ]" but allow yaID__aTYPE +packageClassScopeList: // IEEE: class_type: "id [ parameter_value_assignment ]" but allow yaID__aTYPE // // Or IEEE: [package_scope] // // IMPORTANT: The lexer will parse the following ID to be in the found package // // if not needed must use packageClassScopeNoId @@ -5945,10 +5942,10 @@ packageClassScopeList: // IEEE: class_type: "id [ parameter_value_assi // // If you follow the rules down, class_type is really a list via ps_class_identifier packageClassScopeItem { $$ = $1; $$ = $1; } | packageClassScopeList packageClassScopeItem - { $$ = $2; $$ = $2; BBUNSUP($2, "Unsupported: Nested :: references"); } + { $$ = new AstDot($2, true, $1, $2); $$ = $2; } ; -packageClassScopeItem: // IEEE: package_scope or [package_scope]::[class_scope] +packageClassScopeItem: // IEEE: package_scope or [package_scope]::[class_scope] // // IMPORTANT: The lexer will parse the following ID to be in the found package // // if not needed must use packageClassScopeNoId // // IEEE: class_type: "id [ parameter_value_assignment ]" but allow yaID__aTYPE @@ -5956,29 +5953,30 @@ packageClassScopeItem: // IEEE: package_scope or [package_scope]::[cla idCC /*mid*/ { SYMP->nextId($1); } /*cont*/ yP_COLONCOLON - { $$ = VN_CAST($1, Package); $$ = $1; } // UNSUP classes + { $$ = new AstClassOrPackageRef($1, *$1, $1, NULL); $$ = $1; } // | idCC parameter_value_assignment /*mid*/ { SYMP->nextId($1); } // Change next *after* we handle parameters, not before /*cont*/ yP_COLONCOLON - { $$ = VN_CAST($1, Package); $$ = $1; // UNSUP classes - if ($2) BBUNSUP($2->fileline(), "Unsupported: Parameterized classes"); } + { $$ = new AstClassOrPackageRef($1, *$1, $1, $2); $$ = $1; } ; -dollarUnitNextId: // $unit +dollarUnitNextId: // $unit // // IMPORTANT: The lexer will parse the following ID to be in the found package // // if not needed must use packageClassScopeNoId // // Must call nextId without any additional tokens following yD_UNIT - { $$ = GRAMMARP->unitPackage($1); SYMP->nextId(PARSEP->rootp()); } + { $$ = new AstClassOrPackageRef($1, "$unit", GRAMMARP->unitPackage($1), NULL); + SYMP->nextId(PARSEP->rootp()); } ; -localNextId: // local +localNextId: // local // // IMPORTANT: The lexer will parse the following ID to be in the found package // // if not needed must use packageClassScopeNoId // // Must call nextId without any additional tokens following yLOCAL__COLONCOLON - { $$ = GRAMMARP->unitPackage($1); SYMP->nextId(PARSEP->rootp()); + { $$ = new AstClassOrPackageRef($1, "local::", GRAMMARP->unitPackage($1), NULL); + SYMP->nextId(PARSEP->rootp()); BBUNSUP($1, "Unsupported: Randomize 'local::'"); } ; diff --git a/test_regress/t/t_class2.out b/test_regress/t/t_class2.out index 3444da0d9..25f82f892 100644 --- a/test_regress/t/t_class2.out +++ b/test_regress/t/t_class2.out @@ -1,4 +1,7 @@ -%Error: t/t_class2.v:35:16: Can't find definition of variable: 'ENUM_VAL' +%Error-UNSUPPORTED: t/t_class2.v:35:16: Unsupported: Class '::' references: 'Cls' 35 | if (Cls::ENUM_VAL != 22) $stop; | ^~~~~~~~ -%Error: Exiting due to +%Error: Internal Error: t/t_class2.v:35:11: ../V3LinkDot.cpp:#: Bad package link + 35 | if (Cls::ENUM_VAL != 22) $stop; + | ^~~ + ... See the manual and https://verilator.org for more assistance. diff --git a/test_regress/t/t_class_extends.out b/test_regress/t/t_class_extends.out index c839d805a..8cd0d95fd 100644 --- a/test_regress/t/t_class_extends.out +++ b/test_regress/t/t_class_extends.out @@ -1,28 +1,16 @@ %Error-UNSUPPORTED: t/t_class_extends.v:13:21: Unsupported: class extends 13 | class Base1 extends Base0; | ^~~~~ -%Error: t/t_class_extends.v:13:21: Found definition of 'Base0' as a CLASS but expected a variable - 13 | class Base1 extends Base0; - | ^~~~~ %Error-UNSUPPORTED: t/t_class_extends.v:18:21: Unsupported: class extends 18 | class Base2 extends Base1; | ^~~~~ -%Error: t/t_class_extends.v:18:21: Found definition of 'Base1' as a CLASS but expected a variable - 18 | class Base2 extends Base1; - | ^~~~~ %Error-UNSUPPORTED: t/t_class_extends.v:22:19: Unsupported: class extends 22 | class Cls extends Base2; | ^~~~~ -%Error: t/t_class_extends.v:22:19: Found definition of 'Base2' as a CLASS but expected a variable - 22 | class Cls extends Base2; - | ^~~~~ %Error: t/t_class_extends.v:25:4: Can't find typedef: 'T' 25 | T imemberc; | ^ %Error-UNSUPPORTED: t/t_class_extends.v:33:43: Unsupported: class extends 33 | class uvm__registry #(type T=int) extends uvm_object_wrapper; | ^~~~~~~~~~~~~~~~~~ -%Error: t/t_class_extends.v:33:43: Found definition of 'uvm_object_wrapper' as a CLASS but expected a variable - 33 | class uvm__registry #(type T=int) extends uvm_object_wrapper; - | ^~~~~~~~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_extends_this.out b/test_regress/t/t_class_extends_this.out index 020f115a4..6f0456393 100644 --- a/test_regress/t/t_class_extends_this.out +++ b/test_regress/t/t_class_extends_this.out @@ -7,9 +7,6 @@ %Error-UNSUPPORTED: t/t_class_extends_this.v:17:19: Unsupported: class extends 17 | class Cls extends Base; | ^~~~ -%Error: t/t_class_extends_this.v:17:19: Found definition of 'Base' as a CLASS but expected a variable - 17 | class Cls extends Base; - | ^~~~ %Error-UNSUPPORTED: t/t_class_extends_this.v:21:11: Unsupported: this 21 | if (this.value != 2) $stop; | ^~~~ diff --git a/test_regress/t/t_class_member_bad.out b/test_regress/t/t_class_member_bad.out index eb6537580..1251ff9af 100644 --- a/test_regress/t/t_class_member_bad.out +++ b/test_regress/t/t_class_member_bad.out @@ -1,7 +1,4 @@ %Error-UNSUPPORTED: t/t_class_member_bad.v:11:20: Unsupported: class extends 11 | class Cls2 extends Base1; | ^~~~~ -%Error: t/t_class_member_bad.v:11:20: Found definition of 'Base1' as a CLASS but expected a variable - 11 | class Cls2 extends Base1; - | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_method_bad.out b/test_regress/t/t_class_method_bad.out index 88dcdf4f4..bb2dbc0f6 100644 --- a/test_regress/t/t_class_method_bad.out +++ b/test_regress/t/t_class_method_bad.out @@ -1,7 +1,4 @@ %Error-UNSUPPORTED: t/t_class_method_bad.v:11:20: Unsupported: class extends 11 | class Cls2 extends Base1; | ^~~~~ -%Error: t/t_class_method_bad.v:11:20: Found definition of 'Base1' as a CLASS but expected a variable - 11 | class Cls2 extends Base1; - | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_param.out b/test_regress/t/t_class_param.out index f4aba8765..53cdad86a 100644 --- a/test_regress/t/t_class_param.out +++ b/test_regress/t/t_class_param.out @@ -1,4 +1,7 @@ -%Error-UNSUPPORTED: t/t_class_param.v:20:11: Unsupported: Parameter classes +%Error-UNSUPPORTED: t/t_class_param.v:20:4: Unsupported: parameterized packages 20 | Cls #(.P(4)) c4; - | ^ + | ^~~ +%Error-UNSUPPORTED: t/t_class_param.v:9:23: Unsupported: class parameter + 9 | class Cls #(parameter P = 12); + | ^ %Error: Exiting due to diff --git a/test_regress/t/t_class_typedef.out b/test_regress/t/t_class_typedef.out index bc468849c..4979a037a 100644 --- a/test_regress/t/t_class_typedef.out +++ b/test_regress/t/t_class_typedef.out @@ -1,4 +1,13 @@ -%Error-UNSUPPORTED: t/t_class_typedef.v:14:24: Unsupported: Parameterized classes +%Error-UNSUPPORTED: t/t_class_typedef.v:12:4: Unsupported: Class '::' reference + 12 | uvm_resource_types::rsrc_q_t rtab [string]; + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_class_typedef.v:12:24: Can't find typedef: 'rsrc_q_t' + 12 | uvm_resource_types::rsrc_q_t rtab [string]; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_class_typedef.v:14:4: Unsupported: Class '::' reference 14 | uvm_resource_types#(1,2,3)::rsrc_q_t rtab_paramed [string]; - | ^ + | ^~~~~~~~~~~~~~~~~~ +%Error: t/t_class_typedef.v:14:32: Can't find typedef: 'rsrc_q_t' + 14 | uvm_resource_types#(1,2,3)::rsrc_q_t rtab_paramed [string]; + | ^~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_vparam_unsup.out b/test_regress/t/t_class_vparam_unsup.out index 66f55b199..b0b72a8c4 100644 --- a/test_regress/t/t_class_vparam_unsup.out +++ b/test_regress/t/t_class_vparam_unsup.out @@ -1,4 +1,4 @@ -%Error-UNSUPPORTED: t/t_class_vparam_unsup.v:13:58: Unsupported: Parameter classes +%Error-UNSUPPORTED: t/t_class_vparam_unsup.v:13:40: Unsupported: parameterized packages 13 | pure virtual function void funcname(paramed_class_t #(CTYPE_t) v); - | ^~~~~~~ + | ^~~~~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_const_hi.pl b/test_regress/t/t_const_hi.pl new file mode 100755 index 000000000..a17622844 --- /dev/null +++ b/test_regress/t/t_const_hi.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2004 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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_const_hi.v b/test_regress/t/t_const_hi.v new file mode 100644 index 000000000..edf2afef4 --- /dev/null +++ b/test_regress/t/t_const_hi.v @@ -0,0 +1,53 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc = 0; + reg [1:0] reg_i; + reg [1049:0] pad0; + reg [1049:0] reg_o; + reg [1049:0] spad1; + + /*AUTOWIRE*/ + + always_comb begin + if (reg_i[1] == 1'b1) + reg_o = {986'd0, 64'hffff0000ffff0000}; + else if (reg_i[0] == 1'b1) + reg_o = {64'hffff0000ffff0000, 986'd0}; + else + reg_o = 1050'd0; + end + + // Test loop + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 0) begin + reg_i <= 2'b00; + pad0 <= '1; + spad1 <= '1; + end + else if (cyc == 1) begin + reg_i <= 2'b01; + end + else if (cyc == 2) begin + if (reg_o != {64'hffff0000ffff0000, 986'd0}) $stop; + reg_i <= 2'b10; + end + else if (cyc == 99) begin + if (reg_o != {986'd0, 64'hffff0000ffff0000}) $stop; + if (pad0 != '1) $stop; + if (spad1 != '1) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_fell.pl b/test_regress/t/t_fell.pl new file mode 100644 index 000000000..c1a6773e9 --- /dev/null +++ b/test_regress/t/t_fell.pl @@ -0,0 +1,21 @@ +#!/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. + +scenarios(simulator => 1); + +compile( + verilator_flags2 => ['--assert'], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_fell.v b/test_regress/t/t_fell.v new file mode 100644 index 000000000..eff06f114 --- /dev/null +++ b/test_regress/t/t_fell.v @@ -0,0 +1,81 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2020 by Peter Monsson. + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + integer cyc; initial cyc=2; + wire [31:0] in = cyc; + + Test test (/*AUTOINST*/ + // Inputs + .clk (clk), + .in (in[31:0])); + + Test2 test2 (/*AUTOINST*/ + // Inputs + .clk (clk), + .in (in[31:0])); + + always @ (posedge clk) begin + if (cyc!=0) begin + cyc <= cyc + 1; + if (cyc==10) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + end + +endmodule + +module Test (/*AUTOARG*/ + // Inputs + clk, in + ); + + input clk; + input [31:0] in; + + reg [31:0] dly0 = 1; + + // If called in an assertion, sequence, or property, the appropriate clocking event. + // Otherwise, if called in a disable condition or a clock expression in an assertion, sequence, or prop, explicit. + // Otherwise, if called in an action block of an assertion, the leading clock of the assertion is used. + // Otherwise, if called in a procedure, the inferred clock + // Otherwise, default clocking + + always @(posedge clk) begin + dly0 <= in; + // In clock expression + $write("in=%0d, dly0=%0d, fell=%0d, past=%0d\n", in, dly0, $fell(dly0), $past(dly0)); + if ($fell(dly0[4])) $stop; + end + + assert property (@(posedge clk) $fell(dly0) || dly0%2==1); +endmodule + + +module Test2 (/*AUTOARG*/ + // Inputs + clk, in + ); + + input clk; + input [31:0] in; + + reg [31:0] dly0 = 1; + + always @(posedge clk) begin + dly0 <= in; + if ($fell(dly0[31:4])) $stop; + end + + default clocking @(posedge clk); endclocking + assert property ($fell(dly0[0]) || dly0%2==1); +endmodule diff --git a/test_regress/t/t_interface_arraymux.v b/test_regress/t/t_interface_arraymux.v index 8709cbca4..261f154d9 100644 --- a/test_regress/t/t_interface_arraymux.v +++ b/test_regress/t/t_interface_arraymux.v @@ -39,6 +39,19 @@ module ThingMuxOH the_intf.t things_in [NTHINGS-1:0], the_intf.i thing_out ); + assign thing_out.valid = things_in[0].valid; +endmodule + +module ThingMuxShort + #( + parameter NTHINGS = 1, + parameter M = 5 ) + ( + input logic [NTHINGS-1:0] select_oh, + the_intf.t things_in [NTHINGS], + the_intf.i thing_out + ); + assign thing_out.valid = things_in[0].valid; endmodule module Thinker @@ -55,8 +68,10 @@ module Thinker the_intf #(.M(M)) curr_things [N-1:0] (); the_intf #(.M(M)) prev_things [N-1:0] (); + the_intf #(.M(M)) s_things [N] (); the_intf #(.M(M)) curr_thing (); the_intf #(.M(M)) prev_thing (); + the_intf #(.M(M)) s_thing (); logic [N-1:0] select_oh; @@ -78,6 +93,15 @@ module Thinker .things_in( prev_things ), .thing_out( prev_thing )); + // 3rd mux, using short array nomenclature: + ThingMuxShort #( + .NTHINGS ( N ), + .M ( M )) + s_thing_mux( + .select_oh( select_oh ), + .things_in( s_things ), + .thing_out( s_thing )); + endmodule module t diff --git a/test_regress/t/t_math_real.v b/test_regress/t/t_math_real.v index 167bd9fbf..dc94b5aa3 100644 --- a/test_regress/t/t_math_real.v +++ b/test_regress/t/t_math_real.v @@ -6,6 +6,7 @@ // Version 2.0. // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +`define checkr(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got=%f exp=%f\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); `define is_near_real(a,b) (( ((a)<(b)) ? (b)-(a) : (a)-(b)) < (((a)/(b))*0.0001)) module t (/*AUTOARG*/ @@ -16,6 +17,16 @@ module t (/*AUTOARG*/ integer i; reg [63:0] b; + reg [47:0] i48; + reg signed [47:0] is48; + reg [31:0] ci32; + reg signed [31:0] cis32; + reg [47:0] ci48; + reg signed [47:0] cis48; + reg [63:0] ci64; + reg signed [63:0] cis64; + reg [95:0] ci96; + reg signed [95:0] cis96; real r, r2; integer cyc=0; @@ -88,6 +99,41 @@ module t (/*AUTOARG*/ // bug b = 64'h7fe8000000000000; $display("%6.3f", $bitstoreal(b)); + // bug + i48 = 48'hff00_00000000; + r = real'(i48); + if (r != 280375465082880.0) $stop; + r = $itor(i48); + if (r != 280375465082880.0) $stop; + + is48 = 48'shff00_00000000; + r = real'(is48); + if (r != -1099511627776.0) $stop; + r = $itor(is48); + if (r != -1099511627776.0) $stop; + + r = 0; + r = i48; + if (r != 280375465082880.0) $stop; + r = 0; + + r = $itor(-10); + if (r != -10.0) $stop; + + r = real'(4'sb1111); + if (r != -1) $stop; + r = $itor(4'sb1111); + if (r != -1) $stop; + + r = real'(4'b1111); + if (r != 15) $stop; + r = $itor(4'b1111); + if (r != 15) $stop; + + r = real'(96'hf0000000_00000000_00000000); + if (r != 74276402357122816493947453440.0) $stop; + r = real'(96'shf0000000_00000000_00000000); + if (r != -4951760157141521099596496896.0) $stop; end // Test loop @@ -98,8 +144,18 @@ module t (/*AUTOARG*/ cyc <= cyc + 1; if (cyc==0) begin // Setup + ci48 <= '0; + cis48 <= '0; + ci96 <= '0; + cis96 <= '0; end - else if (cyc<90) begin + else if (cyc == 1) begin + ci48 <= 48'hff00_00000000; + cis48 <= 48'shff00_00000000; + ci96 <= 96'hf0000000_00000000_00000000; + cis96 <= 96'shf0000000_00000000_00000000; + end + else if (cyc<80) begin if ($time != {32'h0, $rtoi($realtime)}) $stop; if ($itor(cyc) != cyc) $stop; //Unsup: if ((real `($time)) != $realtime) $stop; @@ -141,6 +197,76 @@ module t (/*AUTOARG*/ != (((cyc-50)!=0) ? 10 : 20)) $stop; // if ((!(r-50.0)) != (!((cyc-50) != 0))) $stop; + // + r = real'(ci48); + `checkr(r, 280375465082880.0); + r = real'(cis48); + `checkr(r, -1099511627776.0); + // + r = real'(ci96); + `checkr(r, 74276402357122816493947453440.0); + r = real'(cis96); + `checkr(r, -4951760157141521099596496896.0); + end + else if (cyc==90) begin + ci32 <= '0; + cis32 <= '0; + ci48 <= '0; + cis48 <= '0; + ci64 <= '0; + cis64 <= '0; + ci96 <= '0; + cis96 <= '0; + end + else if (cyc==91) begin + `checkr(real'(ci32), 0.0); + `checkr(real'(cis32), 0.0); + `checkr(real'(ci48), 0.0); + `checkr(real'(cis48), 0.0); + `checkr(real'(ci64), 0.0); + `checkr(real'(cis64), 0.0); + `checkr(real'(ci96), 0.0); + `checkr(real'(cis96), 0.0); + end + else if (cyc==92) begin + ci32 <= 32'b1; + cis32 <= 32'b1; + ci48 <= 48'b1; + cis48 <= 48'b1; + ci64 <= 64'b1; + cis64 <= 64'b1; + ci96 <= 96'b1; + cis96 <= 96'b1; + end + else if (cyc==93) begin + `checkr(real'(ci32), 1.0); + `checkr(real'(cis32), 1.0); + `checkr(real'(ci48), 1.0); + `checkr(real'(cis48), 1.0); + `checkr(real'(ci64), 1.0); + `checkr(real'(cis64), 1.0); + `checkr(real'(ci96), 1.0); + `checkr(real'(cis96), 1.0); + end + else if (cyc==94) begin + ci32 <= ~ '0; + cis32 <= ~ '0; + ci48 <= ~ '0; + cis48 <= ~ '0; + ci64 <= ~ '0; + cis64 <= ~ '0; + ci96 <= ~ '0; + cis96 <= ~ '0; + end + else if (cyc==95) begin + `checkr(real'(ci32), 4294967295.0); + `checkr(real'(cis32), -1.0); + `checkr(real'(ci48), 281474976710655.0); + `checkr(real'(cis48), -1.0); + `checkr(real'(ci64), 18446744073709551616.0); + `checkr(real'(cis64), -1.0); + `checkr(real'(ci96), 79228162514264337593543950336.0); + `checkr(real'(cis96), -1.0); end else if (cyc==99) begin $write("*-* All Finished *-*\n"); diff --git a/test_regress/t/t_math_real_random.pl b/test_regress/t/t_math_real_random.pl new file mode 100755 index 000000000..9a15dd2cc --- /dev/null +++ b/test_regress/t/t_math_real_random.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2019 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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_math_real_random.v b/test_regress/t/t_math_real_random.v new file mode 100644 index 000000000..02c86774f --- /dev/null +++ b/test_regress/t/t_math_real_random.v @@ -0,0 +1,100 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define checkr(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got=%f exp=%f\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc=0; + reg [63:0] crc; + reg [63:0] sum; + + reg [127:0] in; + + check #(48) check48 (.*); + check #(31) check31 (.*); + check #(32) check32 (.*); + check #(63) check63 (.*); + check #(64) check64 (.*); + check #(96) check96 (.*); + check #(128) check128 (.*); + + always_comb begin + if (crc[2:0] == 0) in = '0; + else if (crc[2:0] == 1) in = ~'0; + else if (crc[2:0] == 2) in = 128'b1; + else if (crc[2:0] == 3) in = ~ 128'b1; + else begin + in = {crc, crc}; + if (crc[3]) in[31:0] = '0; + if (crc[4]) in[63:32] = '0; + if (crc[5]) in[95:64] = '0; + if (crc[6]) in[127:96] = '0; + if (crc[7]) in[31:0] = ~'0; + if (crc[8]) in[63:32] = ~'0; + if (crc[9]) in[95:64] = ~'0; + if (crc[10]) in[127:96] = ~'0; + end + end + + // Test loop + always @ (posedge clk) begin +`ifdef TEST_VERBOSE + $write("[%0t] cyc==%0d in=%x\n",$time, cyc, in); +`endif + cyc <= cyc + 1; + crc <= {crc[62:0], crc[63]^crc[2]^crc[0]}; + if (cyc == 0) begin + // Setup + crc <= 64'h5aef0c8d_d70a4497; + sum <= '0; + end + else if (cyc == 99) begin + `checkr(check48.sum, 14574057015683440.000000); + `checkr(check31.sum, 114141374814.000000); + `checkr(check32.sum, 236547942750.000000); + `checkr(check63.sum, 513694866079917670400.000000); + `checkr(check64.sum, 1002533584033221181440.000000); + `checkr(check96.sum, 4377373669974269260279175970816.000000); + `checkr(check128.sum, 18358899571808044815012294240949812330496.000000); + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule + +module check(/*AUTOARG*/ + // Inputs + in, clk, cyc + ); + parameter WIDTH = 128; + input [127:0] in; + + wire [WIDTH-1:0] ci = in[WIDTH-1:0]; + wire signed [WIDTH-1:0] cis = in[WIDTH-1:0]; + + real r; + real rs; + always_comb r = ci; + always_comb rs = cis; + + input clk; + input integer cyc; + real sum; + + always_ff @ (negedge clk) begin +`ifdef TEST_VERBOSE + $write("[%0t] w%0d in=%h r=%f rs=%f sum=%f\n", $time, WIDTH, ci, r, rs, sum); +`endif + if (cyc < 10) sum <= 0; + else sum <= sum + r + rs; + end +endmodule diff --git a/test_regress/t/t_math_shift_extend.pl b/test_regress/t/t_math_shift_extend.pl new file mode 100755 index 000000000..763e64f5b --- /dev/null +++ b/test_regress/t/t_math_shift_extend.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env 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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute(); + +ok(1); +1; diff --git a/test_regress/t/t_math_shift_extend.v b/test_regress/t/t_math_shift_extend.v new file mode 100644 index 000000000..b0f4707de --- /dev/null +++ b/test_regress/t/t_math_shift_extend.v @@ -0,0 +1,37 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + + logic in1 = 1; + logic [1:0] in2 = 2'b11; + logic [31:0] out; + + typedef logic [7:0] data_t; + + // verilator lint_off WIDTH + initial begin + in1 = 1; + in2 = 0; + out = data_t'(in1 << in2); + if (out != 8'b1) $stop; + + in2 = 1; + out = data_t'(in1 << in2); + if (out != 8'b10) $stop; + + in2 = 2; + out = data_t'(in1 << in2); + if (out != 8'b100) $stop; + + in2 = 3; + out = data_t'(in1 << in2); + if (out != 8'b1000) $stop; + + $write("*-* All Finished *-*\n"); + $finish(); + end +endmodule diff --git a/test_regress/t/t_math_wide_bad.out b/test_regress/t/t_math_wide_bad.out new file mode 100644 index 000000000..1c4516c1d --- /dev/null +++ b/test_regress/t/t_math_wide_bad.out @@ -0,0 +1,10 @@ +%Error-UNSUPPORTED: t/t_math_wide_bad.v:22:18: Unsupported: operator POWSS operator of 576 bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h + 22 | assign z2 = a ** 3; + | ^~ +%Error-UNSUPPORTED: t/t_math_wide_bad.v:23:15: Unsupported: operator ISTORD operator of 64 bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h + 23 | assign r = real'(a); + | ^~~~ +%Error-UNSUPPORTED: t/t_math_wide_bad.v:21:17: Unsupported: operator MULS operator of 576 bits exceeds hardcoded limit VL_MULS_MAX_WORDS in verilatedos.h + 21 | assign z = a * b; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_math_wide_bad.pl b/test_regress/t/t_math_wide_bad.pl new file mode 100755 index 000000000..9c9fb65a0 --- /dev/null +++ b/test_regress/t/t_math_wide_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2010 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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_math_wide_bad.v b/test_regress/t/t_math_wide_bad.v new file mode 100644 index 000000000..8864a0bfc --- /dev/null +++ b/test_regress/t/t_math_wide_bad.v @@ -0,0 +1,25 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Outputs + z, z2, r, + // Inputs + a, b + ); + + input signed [17*32 : 0] a; + input signed [17*32 : 0] b; + + output signed [17*32 : 0] z; + output signed [17*32 : 0] z2; + output real r; + + assign z = a * b; + assign z2 = a ** 3; + assign r = real'(a); + +endmodule diff --git a/test_regress/t/t_param_func2.pl b/test_regress/t/t_param_func2.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_param_func2.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env 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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_param_func2.v b/test_regress/t/t_param_func2.v new file mode 100644 index 000000000..432d2914d --- /dev/null +++ b/test_regress/t/t_param_func2.v @@ -0,0 +1,52 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + sub #(.WIDTH(4)) sub4(); + sub #(.WIDTH(8)) sub8(); + + logic [3:0] out4; + logic [7:0] out8; + + initial begin + out4 = sub4.orer(4'b1000); + out8 = sub8.orer(8'b10000000); + if (out4 != 4'b1011) $stop; + if (out8 != 8'b10111111) $stop; + out4 = sub4.orer2(4'b1000); + out8 = sub8.orer2(8'b10000000); + if (out4 != 4'b1001) $stop; + if (out8 != 8'b10011111) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule + + +module sub; + parameter WIDTH = 1; + + function [WIDTH-1:0] orer; + input [WIDTH-1:0] in; + // IEEE provices no way to override this parameter, basically it's a localparam + parameter MASK_W = WIDTH - 2; + localparam [MASK_W-1:0] MASK = '1; + // verilator lint_off WIDTH + return in | MASK; + // verilator lint_on WIDTH + endfunction + + function [WIDTH-1:0] orer2; + input [WIDTH-1:0] in; + // Same param names as other function to check we disambiguate + // IEEE provices no way to override this parameter, basically it's a localparam + parameter MASK_W = WIDTH - 3; + localparam [MASK_W-1:0] MASK = '1; + // verilator lint_off WIDTH + return in | MASK; + // verilator lint_on WIDTH + endfunction +endmodule diff --git a/test_regress/t/t_param_in_func_bad.out b/test_regress/t/t_param_in_func_bad.out index f152cd026..683490111 100644 --- a/test_regress/t/t_param_in_func_bad.out +++ b/test_regress/t/t_param_in_func_bad.out @@ -1,7 +1,5 @@ -%Error-UNSUPPORTED: t/t_param_in_func_bad.v:24:26: Unsupported: Parameters in functions +%Error-UNSUPPORTED: t/t_param_in_func_bad.v:24:26: Unsupported: Parameters in functions with complex assign + : ... In instance t 24 | localparam logic[7:0] digits[10] | ^~~~~~ -%Error: t/t_param_in_func_bad.v:28:11: Can't find definition of variable: 'digits' - 28 | return digits[d]; - | ^~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_param_width.pl b/test_regress/t/t_param_width.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_param_width.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env 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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_param_width.v b/test_regress/t/t_param_width.v new file mode 100644 index 000000000..bc41be394 --- /dev/null +++ b/test_regress/t/t_param_width.v @@ -0,0 +1,38 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2016 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// issue 1991 + +module t + (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + socket #(3'b000) s0(); + socket #(3'b010) s1(); + socket #(2'b10) s2(); + socket #(2'b11) s3(); + + always_ff @ (posedge clk) begin + if (s0.ADDR != 0) $stop; + if (s1.ADDR != 2) $stop; + if (s2.ADDR != 2) $stop; + if (s3.ADDR != 3) $stop; + if ($bits(s0.ADDR) != 3) $stop; + if ($bits(s1.ADDR) != 3) $stop; + if ($bits(s2.ADDR) != 2) $stop; + if ($bits(s3.ADDR) != 2) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule + +module socket #(ADDR)(); + initial + $display("bits %0d, addr %b", $bits(ADDR), ADDR); +endmodule diff --git a/test_regress/t/t_process.out b/test_regress/t/t_process.out index c024cca10..7f135af7b 100644 --- a/test_regress/t/t_process.out +++ b/test_regress/t/t_process.out @@ -1,22 +1,9 @@ %Error: t/t_process.v:22:4: Can't find typedef: 'process' 22 | process p; | ^~~~~~~ -%Error: t/t_process.v:26:20: Can't find definition of task/function: 'self' +%Error-UNSUPPORTED: t/t_process.v:26:20: Unsupported: 'process' 26 | p = process::self(); | ^~~~ -%Error: t/t_process.v:27:34: Can't find definition of variable: 'RUNNING' - 27 | if (p.status() != process::RUNNING) $stop; - | ^~~~~~~ -%Error: t/t_process.v:28:34: Can't find definition of variable: 'WAITING' - 28 | if (p.status() == process::WAITING) $stop; - | ^~~~~~~ -%Error: t/t_process.v:29:34: Can't find definition of variable: 'SUSPENDED' - 29 | if (p.status() == process::SUSPENDED) $stop; - | ^~~~~~~~~ -%Error: t/t_process.v:30:34: Can't find definition of variable: 'KILLED' - 30 | if (p.status() == process::KILLED) $stop; - | ^~~~~~ -%Error: t/t_process.v:31:34: Can't find definition of variable: 'FINISHED' - 31 | if (p.status() == process::FINISHED) $stop; - | ^~~~~~~~ -%Error: Exiting due to +%Error: Internal Error: t/t_process.v:26:11: ../V3LinkDot.cpp:#: Bad package link + 26 | p = process::self(); + | ^~~~~~~ diff --git a/test_regress/t/t_prot_lib_comb.pl b/test_regress/t/t_prot_lib_comb.pl new file mode 100755 index 000000000..296873c8f --- /dev/null +++ b/test_regress/t/t_prot_lib_comb.pl @@ -0,0 +1,69 @@ +#!/usr/bin/env perl +# Makes the test run with tracing enabled by default, can be overridden +# with --notrace +unshift(@ARGV, "--trace"); +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2019 by Todd Strader. 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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios( + vlt => 1, + xsim => 1, + ); + +$Self->{sim_time} = $Self->{benchmark} * 100 if $Self->{benchmark}; + +my $secret_prefix = "secret"; +my $secret_dir = "$Self->{obj_dir}/$secret_prefix"; +mkdir $secret_dir; + +while (1) { + # Always compile the secret file with Verilator no matter what simulator + # we are testing with + run(logfile => "$secret_dir/vlt_compile.log", + cmd => ["perl", + "$ENV{VERILATOR_ROOT}/bin/verilator", + "--prefix", + "Vt_prot_lib_secret", + "-cc", + "-Mdir", + $secret_dir, + "--protect-lib", + $secret_prefix, + "t/t_prot_lib_comb.v"], + verilator_run => 1, + ); + last if $Self->{errors}; + + run(logfile => "$secret_dir/secret_gcc.log", + cmd=>[$ENV{MAKE}, + "-C", + $secret_dir, + "-f", + "Vt_prot_lib_secret.mk"]); + last if $Self->{errors}; + + compile( + verilator_flags2 => ["$secret_dir/secret.sv", + "+define+PROCESS_TOP", + "-LDFLAGS", + "$secret_prefix/libsecret.a"], + xsim_flags2 => ["$secret_dir/secret.sv"], + ); + + execute( + check_finished => 1, + xsim_run_flags2 => ["--sv_lib", + "$secret_dir/libsecret", + "--dpi_absolute"], + ); + + ok(1); + last; +} +1; diff --git a/test_regress/t/t_prot_lib_comb.v b/test_regress/t/t_prot_lib_comb.v new file mode 100644 index 000000000..9b8e9e96d --- /dev/null +++ b/test_regress/t/t_prot_lib_comb.v @@ -0,0 +1,56 @@ +// DESCRIPTION: Verilator: Verilog Test module +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2020 by Yutetsu TAKATSUKASA. +// SPDX-License-Identifier: CC0-1.0 + +`ifdef PROCESS_TOP +`define CHECK if (out0 != (in0 ^ in1) || out1 != (in0 | in1) || out2 != (in0 & in1)) begin \ + $display("Mismatch in0:%b in1:%b out0:%b out1:%b out2:%b", in0, in1, out0, out1, out2); \ + $stop; \ + end + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + + logic in0, in1; + logic out0, out1, out2; + logic [31:0] count = 0; + // actually XOR and OR and AND + secret i_secret(.in0(in0), .in1(in1), .out0(out0), .out1(out1), .out2(out2)); + + always @(posedge clk) begin + count <= count + 32'd1; + if (count == 32'd1) begin + in0 <= 1'b0; + in1 <= 1'b0; + end else if (count == 32'd2) begin + `CHECK + in0 <= 1'b1; + in1 <= 1'b0; + end else if (count == 32'd3) begin + `CHECK + in0 <= 1'b0; + in1 <= 1'b1; + end else if (count == 32'd4) begin + `CHECK + in0 <= 1'b1; + in1 <= 1'b1; + end else if (count == 32'd5) begin + `CHECK + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule + +`else +module secret(input in0, input in1, output out0, output out1, output out2); + assign out0 = in0 ^ in1; + assign out1 = in0 | in1; + assign out2 = in0 & in1; +endmodule +`endif diff --git a/test_regress/t/t_rose.pl b/test_regress/t/t_rose.pl new file mode 100644 index 000000000..c1a6773e9 --- /dev/null +++ b/test_regress/t/t_rose.pl @@ -0,0 +1,21 @@ +#!/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. + +scenarios(simulator => 1); + +compile( + verilator_flags2 => ['--assert'], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_rose.v b/test_regress/t/t_rose.v new file mode 100644 index 000000000..1eadaa61d --- /dev/null +++ b/test_regress/t/t_rose.v @@ -0,0 +1,81 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2020 by Peter Monsson. + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + integer cyc; initial cyc=1; + wire [31:0] in = cyc; + + Test test (/*AUTOINST*/ + // Inputs + .clk (clk), + .in (in[31:0])); + + Test2 test2 (/*AUTOINST*/ + // Inputs + .clk (clk), + .in (in[31:0])); + + always @ (posedge clk) begin + if (cyc!=0) begin + cyc <= cyc + 1; + if (cyc==10) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + end + +endmodule + +module Test (/*AUTOARG*/ + // Inputs + clk, in + ); + + input clk; + input [31:0] in; + + reg [31:0] dly0 = 0; + + // If called in an assertion, sequence, or property, the appropriate clocking event. + // Otherwise, if called in a disable condition or a clock expression in an assertion, sequence, or prop, explicit. + // Otherwise, if called in an action block of an assertion, the leading clock of the assertion is used. + // Otherwise, if called in a procedure, the inferred clock + // Otherwise, default clocking + + always @(posedge clk) begin + dly0 <= in; + // In clock expression + $write("in=%0d, dly0=%0d, rose=%0d, past=%0d\n", in, dly0, $rose(dly0), $past(dly0)); + if ($rose(dly0[4])) $stop; + end + + assert property (@(posedge clk) $rose(dly0) || dly0%2==0); +endmodule + + +module Test2 (/*AUTOARG*/ + // Inputs + clk, in + ); + + input clk; + input [31:0] in; + + reg [31:0] dly0; + + always @(posedge clk) begin + dly0 <= in; + if ($rose(dly0[31:4])) $stop; + end + + default clocking @(posedge clk); endclocking + assert property ($rose(dly0[0]) || dly0%2==0); +endmodule diff --git a/test_regress/t/t_sc_names.cpp b/test_regress/t/t_sc_names.cpp new file mode 100644 index 000000000..13316602e --- /dev/null +++ b/test_regress/t/t_sc_names.cpp @@ -0,0 +1,30 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Edgar E. Iglesias. +// SPDX-License-Identifier: CC0-1.0 + +#include VM_PREFIX_INCLUDE +#include "Vt_sc_names.h" + +VM_PREFIX* tb = NULL; + +int sc_main(int argc, char* argv[]) { + tb = new VM_PREFIX("tb"); + std::vector < sc_object* > ch = tb->get_child_objects(); + bool found = false; + + /* We expect to find clk in here. */ + for (int i = 0; i < ch.size(); ++i) { + if (!strcmp(ch[i]->basename(), "clk")) { + found = true; + } + } + + if (found) { + VL_PRINTF("*-* All Finished *-*\n"); + tb->final(); + } else { + vl_fatal(__FILE__, __LINE__, "tb", "Unexpected results\n"); + } + return 0; +} diff --git a/test_regress/t/t_sc_names.pl b/test_regress/t/t_sc_names.pl new file mode 100755 index 000000000..2dc3e81c8 --- /dev/null +++ b/test_regress/t/t_sc_names.pl @@ -0,0 +1,30 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Edgar E. Iglesias. 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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_sc) { + skip("No SystemC installed"); +} +else { + top_filename("t/t_sc_names.v"); + + compile( + make_main => 0, + verilator_flags2 => ["-sc --exe $Self->{t_dir}/t_sc_names.cpp"], + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_sc_names.v b/test_regress/t/t_sc_names.v new file mode 100644 index 000000000..13bcd4371 --- /dev/null +++ b/test_regress/t/t_sc_names.v @@ -0,0 +1,11 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Edgar E. Iglesias. +// SPDX-License-Identifier: CC0-1.0 + +module t ( + clk + ); + input clk; +endmodule diff --git a/test_regress/t/t_stable.pl b/test_regress/t/t_stable.pl new file mode 100644 index 000000000..c1a6773e9 --- /dev/null +++ b/test_regress/t/t_stable.pl @@ -0,0 +1,21 @@ +#!/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. + +scenarios(simulator => 1); + +compile( + verilator_flags2 => ['--assert'], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_stable.v b/test_regress/t/t_stable.v new file mode 100644 index 000000000..9b9a831b7 --- /dev/null +++ b/test_regress/t/t_stable.v @@ -0,0 +1,81 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2020 by Peter Monsson. + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + integer cyc; initial cyc=1; + wire [31:0] in = cyc; + + Test test (/*AUTOINST*/ + // Inputs + .clk (clk), + .in (in[31:0])); + + Test2 test2 (/*AUTOINST*/ + // Inputs + .clk (clk), + .in (in[31:0])); + + + always @ (posedge clk) begin + if (cyc!=0) begin + cyc <= cyc + 1; + if (cyc==10) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + end + +endmodule + +module Test (/*AUTOARG*/ + // Inputs + clk, in + ); + + input clk; + input [31:0] in; + + reg [31:0] dly0 = -1; + + // If called in an assertion, sequence, or property, the appropriate clocking event. + // Otherwise, if called in a disable condition or a clock expression in an assertion, sequence, or prop, explicit. + // Otherwise, if called in an action block of an assertion, the leading clock of the assertion is used. + // Otherwise, if called in a procedure, the inferred clock + // Otherwise, default clocking + + always @(posedge clk) begin + dly0 <= in; + // In clock expression + $write("dly0=%0d, in=%0d, stable=%0d, past=%0d\n", dly0, in, $stable(dly0), $past(dly0)); + if ($stable(dly0)) $stop; + end + + assert property (@(posedge clk) !$stable(dly0)); +endmodule + +module Test2 (/*AUTOARG*/ + // Inputs + clk, in + ); + + input clk; + input [31:0] in; + + reg [31:0] dly0; + + always @(posedge clk) begin + dly0 <= in; + if (!$stable(dly0[31:4])) $stop; + end + + default clocking @(posedge clk); endclocking + assert property ($stable(dly0[31:4])); +endmodule diff --git a/test_regress/t/t_sys_file_basic.v b/test_regress/t/t_sys_file_basic.v index 272574d0d..9497d3a2a 100644 --- a/test_regress/t/t_sys_file_basic.v +++ b/test_regress/t/t_sys_file_basic.v @@ -8,7 +8,7 @@ `define STRINGIFY(x) `"x`" `define ratio_error(a,b) (((a)>(b) ? ((a)-(b)) : ((b)-(a))) /(a)) -`define checkr(gotv,expv) do if (`ratio_error((gotv),(expv))>0.0001) begin $write("%%Error: %s:%0d: got=%g exp=%g\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); +`define checkr(gotv,expv) do if (`ratio_error((gotv),(expv))>0.0001) begin $write("%%Error: %s:%0d: got=%f exp=%f\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); `define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); `define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); diff --git a/test_regress/t/t_wire_types.v b/test_regress/t/t_wire_types.v index 11952324a..fb67e7a7b 100644 --- a/test_regress/t/t_wire_types.v +++ b/test_regress/t/t_wire_types.v @@ -11,7 +11,7 @@ module t (/*AUTOARG*/ input clk; `define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); -`define checkr(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got=%g exp=%g\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); +`define checkr(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got=%f exp=%f\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); // IEEE: integer_atom_type wire byte w_byte; diff --git a/test_regress/t/t_xml_flat_vlvbound.out b/test_regress/t/t_xml_flat_vlvbound.out new file mode 100644 index 000000000..ae5da8f13 --- /dev/null +++ b/test_regress/t/t_xml_flat_vlvbound.out @@ -0,0 +1,200 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test_regress/t/t_xml_flat_vlvbound.pl b/test_regress/t/t_xml_flat_vlvbound.pl new file mode 100755 index 000000000..9c51c5674 --- /dev/null +++ b/test_regress/t/t_xml_flat_vlvbound.pl @@ -0,0 +1,25 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2012 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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +my $out_filename = "$Self->{obj_dir}/V$Self->{name}.xml"; + +compile( + verilator_flags2 => ['--xml-only', '--flatten'], + verilator_make_gmake => 0, + make_top_shell => 0, + make_main => 0, + ); + +files_identical("$out_filename", $Self->{golden_filename}); + +ok(1); +1; diff --git a/test_regress/t/t_xml_flat_vlvbound.v b/test_regress/t/t_xml_flat_vlvbound.v new file mode 100644 index 000000000..9ed0db0cf --- /dev/null +++ b/test_regress/t/t_xml_flat_vlvbound.v @@ -0,0 +1,27 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2012 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module vlvbound_test + ( + input logic [15:0] i_a, + input logic [15:0] i_b, + output logic [6:0] o_a, + output logic [6:0] o_b + ); + + function automatic logic [6:0] foo(input logic [15:0] val); + logic [6:0] ret; + integer i; + for (i=0 ; i < 7; i++) begin + ret[i] = (val[i*2 +: 2] == 2'b00); + end + return ret; + endfunction + + assign o_a = foo(i_a); + assign o_b = foo(i_b); + +endmodule