diff --git a/.travis.yml b/.travis.yml index 4eef5d994..a10734230 100644 --- a/.travis.yml +++ b/.travis.yml @@ -85,7 +85,7 @@ jobs: # OS X build - {stage: build, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {create: {name: osx-xcode11.6, paths: .}}} # FreeBSD build - - {stage: build, if: type = cron, os: freebsd, compiler: clang, workspaces: {create: {name: freebsd, paths: .}}} + #- {stage: build, if: type = cron, os: freebsd, compiler: clang, workspaces: {create: {name: freebsd, paths: .}}} ############################################################################ # Jobs in the 'test' stage ############################################################################ @@ -136,10 +136,10 @@ jobs: - {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=vltmt-0} - {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=vltmt-1} # FreeBSD tests - - {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-0} - - {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-1} - - {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-0} - - {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-1} + #- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-0} + #- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-1} + #- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-0} + #- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-1} notifications: email: diff --git a/Changes b/Changes index 5bdbe0afa..8887c8af9 100644 --- a/Changes +++ b/Changes @@ -3,6 +3,37 @@ Revision history for Verilator The contributors that suggested a given feature are shown in []. Thanks! +* Verilator 4.102 2020-10-15 + +**** Support const object new() assignments. + +**** Support # as a comment in -f files (#2497). [phantom-killua] + +**** Support 'this' (#2585). [Rafal Kapuscik] + +**** Support defines for FST tracing (#2592). [Markus Krause] + +**** Support |=> inside properties (#1292). [Peter Monsson] + +**** Fix timescale with --hierarchical (#2554). [Yutetsu TAKATSUKASA] + +**** Fix cmake build with --hierarchical (#2560). [Yutetsu TAKATSUKASA] + +**** Fix -G dropping public indication (#2561). [Andrew Goessling] + +**** Fix $urandom_range passed variable (#2563). [nanduraj1] + +**** Fix method calls to package class functions (#2565). [Peter Monsson] + +**** Fix class wide member display (#2567). [Nandu Raj P] + +**** Fix hierarchical references inside function (#2267) (#2572). [James Pallister] + +**** Fix flushCall for backward compatibility (#2580). [chenguokai] + +**** Fix preprocessor stringify of undefined macro. [Martin Whitaker] + + * Verilator 4.100 2020-09-07 ** C++11 or newer compilers are now required. @@ -27,6 +58,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Add support for assume property. [Peter Monsson] +**** Add support for |=> inside properties (#1292). [Peter Monsson] + * Verilator 4.040 2020-08-15 diff --git a/Makefile.in b/Makefile.in index 8870f6cc0..93d3ef247 100644 --- a/Makefile.in +++ b/Makefile.in @@ -170,6 +170,8 @@ DISTFILES_INC = $(INFOS) .gitignore \ test_regress/t/t*/*.v* \ test_regress/t/t*/*/*.sv* \ test_regress/t/t*/*/*.v* \ + test_regress/t/t*/*.cpp \ + test_regress/t/t*/CMakeLists.txt \ test_regress/t/*.cpp \ test_regress/t/*.h \ test_regress/t/*.dat \ diff --git a/bin/verilator_gantt b/bin/verilator_gantt index ddd7f2434..46f70dfaf 100755 --- a/bin/verilator_gantt +++ b/bin/verilator_gantt @@ -156,7 +156,8 @@ sub report { print "\nAnalysis:\n"; printf " Total threads = %d\n", $nthreads; printf " Total mtasks = %d\n", scalar(keys %Mtasks); - printf " Total cpus used = %d\n", scalar(keys %{$Global{cpus}}); + my $ncpus = scalar(keys %{$Global{cpus}}); + printf " Total cpus used = %d\n", $ncpus; printf " Total yields = %d\n", $Global{stats}{yields}; printf " Total eval time = %d rdtsc ticks\n", $Global{last_end}; printf " Longest mtask time = %d rdtsc ticks\n", $long_mtask_time; @@ -206,6 +207,12 @@ sub report { print " stddev = " . ($stddev) . "\n"; print " e ^ stddev = " . exp($stddev). "\n"; print "\n"; + + if ($nthreads > $ncpus) { + print "%Warning: There were fewer CPUs ($ncpus) then threads ($nthreads).\n"; + print " : See docs on use of numactl.\n"; + print "\n"; + } } sub report_graph { diff --git a/configure.ac b/configure.ac index 1cb0dd8d5..9439f43cc 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[4.100 2020-09-07], +AC_INIT([Verilator],[4.102 2020-10-15], [https://verilator.org], [verilator],[https://verilator.org]) # When releasing, also update header of Changes file diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index fca9bec6d..2442f3b2a 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -25,6 +25,7 @@ Iztok Jeras James Hanlon James Hutchinson Jamey Hicks +James Pallister Jan Van Winkel Jeremy Bennett John Coiner @@ -39,6 +40,7 @@ Lukasz Dalek Maarten De Braekeleer Maciej Sobkowski Marco Widmer +Markus Krause Marshal Qiao Matthew Ballance Michael Killough @@ -52,6 +54,7 @@ Philipp Wagner Pieter Kapsenberg Piotr Binkowski Qingyao Sun +Rafal Kapuscik Richard Myers Rupert Swarbrick Sean Cross @@ -65,6 +68,7 @@ Tobias Wölfel Todd Strader Tomasz Gorochowik Tymoteusz Blazejczyk +Victor Besyakov Vassilis Papaefstathiou Veripool API Bot Wilson Snyder diff --git a/docs/internals.adoc b/docs/internals.adoc index 8b7cbd765..fdf08a899 100644 --- a/docs/internals.adoc +++ b/docs/internals.adoc @@ -586,7 +586,7 @@ dealing with. For example a visitor might not implement separate `visit` methods for `AstIf` and `AstGenIf`, but just a single method for the base class: - void visit (AstNodeIf* nodep) + void visit(AstNodeIf* nodep) However that method might want to specify additional code if it is called for `AstGenIf`. Verilator does this by providing a `VN_IS` method for each @@ -672,7 +672,7 @@ Set to 1 to indicate that the compilation or execution is intended to fail. For example the following would specify that compilation requires two defines and is expected to fail. - compile ( + compile( verilator_flags2 => ["-DSMALL_CLOCK -DGATED_COMMENT"], fails => 1, ); @@ -758,6 +758,15 @@ may be required to setup the system for fuzzing. == Debugging +=== Debug Levels + +The "UINFO" calls in the source indicate a debug level. Messages level 3 +and below are globally enabled with `--debug`. Higher levels may be +controlled with `--debugi `. An individual source file levels may +be controlled with `-debugi- `. For example `--debug +--debugi 5 --debugi-V3Width 9` will use the debug binary at default debug +level 5, with the V3Width.cpp file at level 9. + === --debug When you run with `--debug` there are two primary output file types placed diff --git a/include/verilated.cpp b/include/verilated.cpp index fe450ab25..00600f7ca 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -913,10 +913,11 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA output += "0123456789abcdef"[charval]; } break; - default: + default: { // LCOV_EXCL_START std::string msg = std::string("Unknown _vl_vsformat code: ") + pos[0]; VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str()); break; + } // LCOV_EXCL_STOP } // switch } } // switch @@ -1182,10 +1183,12 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf } break; } - default: + default: { // LCOV_EXCL_START std::string msg = std::string("Unknown _vl_vsscanf code: ") + pos[0]; VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str()); break; + } // LCOV_EXCL_STOP + } // switch if (!inIgnore) ++got; @@ -2596,7 +2599,7 @@ vluint32_t VerilatedVarProps::entSize() const { case VLVT_UINT32: size = sizeof(IData); break; case VLVT_UINT64: size = sizeof(QData); break; case VLVT_WDATA: size = VL_WORDS_I(packed().elements()) * sizeof(IData); break; - default: size = 0; break; + default: size = 0; break; // LCOV_EXCL_LINE } return size; } diff --git a/include/verilated.h b/include/verilated.h index 4f25248bd..9d339d8db 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -499,6 +499,7 @@ public: static void addFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE; static void removeFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE; static void runFlushCallbacks() VL_MT_SAFE; + static void flushCall() VL_MT_SAFE { runFlushCallbacks(); } // Deprecated /// Callbacks to run prior to termination static void addExitCb(VoidPCb cb, void* datap) VL_MT_SAFE; static void removeExitCb(VoidPCb cb, void* datap) VL_MT_SAFE; diff --git a/include/verilated.mk.in b/include/verilated.mk.in index f08066a49..eb6b2b72c 100644 --- a/include/verilated.mk.in +++ b/include/verilated.mk.in @@ -54,6 +54,7 @@ VK_CPPFLAGS_ALWAYS += \ -DVM_COVERAGE=$(VM_COVERAGE) \ -DVM_SC=$(VM_SC) \ -DVM_TRACE=$(VM_TRACE) \ + -DVM_TRACE_FST=$(VM_TRACE_FST) \ $(CFG_CXXFLAGS_NO_UNUSED) \ ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users diff --git a/include/verilated_save.cpp b/include/verilated_save.cpp index e571e9cf8..26d626102 100644 --- a/include/verilated_save.cpp +++ b/include/verilated_save.cpp @@ -42,9 +42,10 @@ // clang-format on // CONSTANTS -static const char* const VLTSAVE_HEADER_STR - = "verilatorsave01\n"; ///< Value of first bytes of each file -static const char* const VLTSAVE_TRAILER_STR = "vltsaved"; ///< Value of last bytes of each file +/// Value of first bytes of each file (must be multiple of 8 bytes) +static const char* const VLTSAVE_HEADER_STR = "verilatorsave01\n"; +/// Value of last bytes of each file (must be multiple of 8 bytes) +static const char* const VLTSAVE_TRAILER_STR = "vltsaved"; //============================================================================= //============================================================================= @@ -64,10 +65,10 @@ VerilatedDeserialize& VerilatedDeserialize::readAssert(const void* __restrict da size_t size) VL_MT_UNSAFE_ONE { if (VL_UNLIKELY(readDiffers(datap, size))) { std::string fn = filename(); - std::string msg - = "Can't deserialize save-restore file as was made from different model:" + filename(); + std::string msg = "Can't deserialize save-restore file as was made from different model: " + + filename(); VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str()); - close(); + // Die before we close() as close would infinite loop } return *this; // For function chaining } @@ -88,9 +89,11 @@ void VerilatedDeserialize::header() VL_MT_UNSAFE_ONE { if (VL_UNLIKELY(os.readDiffers(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR)))) { std::string fn = filename(); std::string msg - = std::string("Can't deserialize; file has wrong header signature: ") + filename(); + = std::string( + "Can't deserialize; file has wrong header signature, or file not found: ") + + filename(); VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str()); - close(); + // Die before we close() as close would infinite loop } os.read(Verilated::serialized1Ptr(), Verilated::serialized1Size()); os.read(Verilated::serialized2Ptr(), Verilated::serialized2Size()); @@ -109,7 +112,7 @@ void VerilatedDeserialize::trailer() VL_MT_UNSAFE_ONE { std::string msg = std::string("Can't deserialize; file has wrong end-of-file signature: ") + filename(); VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str()); - close(); + // Die before we close() as close would infinite loop } } diff --git a/include/verilated_threads.cpp b/include/verilated_threads.cpp index 4edd9db71..1a6d1277e 100644 --- a/include/verilated_threads.cpp +++ b/include/verilated_threads.cpp @@ -139,7 +139,7 @@ void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed) { if (VL_UNLIKELY(!fp)) { VL_FATAL_MT(filenamep, 0, "", "+prof+threads+file file not writable"); // cppcheck-suppress resourceLeak // bug, doesn't realize fp is nullptr - return; + return; // LCOV_EXCL_LINE } // TODO Perhaps merge with verilated_coverage output format, so can diff --git a/include/verilated_threads.h b/include/verilated_threads.h index 56ed7499b..1ff8de64e 100644 --- a/include/verilated_threads.h +++ b/include/verilated_threads.h @@ -22,6 +22,15 @@ #include "verilatedos.h" #include "verilated.h" // for VerilatedMutex and clang annotations +#ifndef VL_THREADED +// Hitting this likely means verilated_threads.cpp is being compiled when +// 'verilator --threads' was not used. 'verilator --threads' sets +// VL_THREADED. +// Alternatively it is always safe but may harm performance to always +// define VL_THREADED for all compiles. +#error "verilated_threads.h/cpp expected VL_THREADED (from verilator --threads)" +#endif + #include #include #include diff --git a/nodist/code_coverage.dat b/nodist/code_coverage.dat index 3e298fd4f..f4aacd760 100644 --- a/nodist/code_coverage.dat +++ b/nodist/code_coverage.dat @@ -46,14 +46,17 @@ remove_gcda_regexp(qr!test_regress/.*/(Vt_|Vtop_).*\.gcda!); exclude_line_regexp(qr/(\bv3fatalSrc\b |\bfatalSrc\b |\bVL_UNCOVERABLE\b + |\bVL_UNREACHABLE\b |\bVL_FATAL |\bUASSERT + |\bNUM_ASSERT |\bERROR_RSVD_WORD |\bV3ERROR_NA |\bUINFO\b)/x); # Exclude for branch coverage only exclude_branch_regexp(qr/(\bdebug\(\) + |\bassert\( |\bSELF_CHECK)/x); 1; diff --git a/src/Makefile.in b/src/Makefile.in index 91c60b76a..29f17f795 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -81,6 +81,10 @@ prefiles:: config_rev.h config_rev.h: ${srcdir}/config_rev.pl $(GIT_CHANGE_DEP) $(PERL) ${srcdir}/config_rev.pl ${srcdir} >$@ +# Human convenience +clang-format: + $(MAKE) -C .. $@ + maintainer-copy:: clean mostlyclean distclean maintainer-clean:: -rm -rf obj_* *.log *.dmp *.vpd core diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index b4205e0a1..981d705ae 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -317,12 +317,12 @@ private: "_Vpast_" + cvtToStr(m_modPastNum++) + "_" + cvtToStr(i), inp->dtypep()); m_modp->addStmtp(outvarp); - AstNode* assp = new AstAssignDly(nodep->fileline(), - new AstVarRef(nodep->fileline(), outvarp, true), inp); + AstNode* assp = new AstAssignDly( + nodep->fileline(), new AstVarRef(nodep->fileline(), outvarp, VAccess::WRITE), inp); alwaysp->addStmtp(assp); // if (debug() >= 9) assp->dumpTree(cout, "-ass: "); invarp = outvarp; - inp = new AstVarRef(nodep->fileline(), invarp, false); + inp = new AstVarRef(nodep->fileline(), invarp, VAccess::READ); } nodep->replaceWith(inp); } diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp index 2bc745a1c..50a405b13 100644 --- a/src/V3AssertPre.cpp +++ b/src/V3AssertPre.cpp @@ -39,6 +39,8 @@ private: AstSenItem* m_senip = nullptr; // Last sensitivity // Reset each always: AstSenItem* m_seniAlwaysp = nullptr; // Last sensitivity in always + // Reset each assertion: + AstNode* m_disablep = nullptr; // Last disable // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -58,7 +60,10 @@ private: } return newp; } - void clearAssertInfo() { m_senip = nullptr; } + void clearAssertInfo() { + m_senip = nullptr; + m_disablep = nullptr; + } // VISITORS //========== Statements @@ -129,8 +134,25 @@ private: AstNode* exprp = nodep->exprp()->unlinkFrBack(); AstNode* past = new AstPast(fl, exprp, nullptr); past->dtypeFrom(exprp); - exprp = new AstEq(fl, past, - exprp->cloneTree(false)); // new AstVarRef(fl, exprp, true) + exprp = new AstEq(fl, past, exprp->cloneTree(false)); + exprp->dtypeSetLogicBool(); + nodep->replaceWith(exprp); + nodep->sentreep(newSenTree(nodep)); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } + + virtual void visit(AstImplication* nodep) override { + if (nodep->sentreep()) return; // Already processed + + FileLine* fl = nodep->fileline(); + AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); + AstNode* lhsp = nodep->lhsp()->unlinkFrBack(); + + if (m_disablep) { lhsp = new AstAnd(fl, new AstNot(fl, m_disablep), lhsp); } + + AstNode* past = new AstPast(fl, lhsp, nullptr); + past->dtypeFrom(lhsp); + AstNode* exprp = new AstOr(fl, new AstNot(fl, past), rhsp); exprp->dtypeSetLogicBool(); nodep->replaceWith(exprp); nodep->sentreep(newSenTree(nodep)); @@ -145,6 +167,7 @@ private: // Block is the new expression to evaluate AstNode* blockp = nodep->propp()->unlinkFrBack(); if (nodep->disablep()) { + m_disablep = nodep->disablep()->cloneTree(false); if (VN_IS(nodep->backp(), Cover)) { blockp = new AstAnd( nodep->disablep()->fileline(), diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index b20a3b184..e8f8682ef 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -58,9 +58,10 @@ std::ostream& operator<<(std::ostream& os, AstType rhs); //###################################################################### // Creators -void AstNode::init() { +AstNode::AstNode(AstType t, FileLine* fl) + : m_type{t} + , m_fileline{fl} { editCountInc(); - m_fileline = nullptr; m_nextp = nullptr; m_backp = nullptr; m_headtailp = this; // When made, we're a list of only a single element diff --git a/src/V3Ast.h b/src/V3Ast.h index 636f45df1..dbcfa1960 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -123,6 +123,33 @@ inline std::ostream& operator<<(std::ostream& os, const VLifetime& rhs) { //###################################################################### +class VAccess { +public: + enum en : uint8_t { READ, WRITE }; + enum en m_e; + const char* ascii() const { + static const char* const names[] = {"RD", "WR"}; + return names[m_e]; + } + inline VAccess() + : m_e{READ} {} + // cppcheck-suppress noExplicitConstructor + inline VAccess(en _e) + : m_e{_e} {} + explicit inline VAccess(int _e) + : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning + operator en() const { return m_e; } + VAccess invert() const { return (m_e == WRITE) ? VAccess(READ) : VAccess(WRITE); } + bool isRead() const { return m_e == READ; } + bool isWrite() const { return m_e == WRITE; } +}; +inline bool operator==(const VAccess& lhs, const VAccess& rhs) { return lhs.m_e == rhs.m_e; } +inline bool operator==(const VAccess& lhs, VAccess::en rhs) { return lhs.m_e == rhs; } +inline bool operator==(VAccess::en lhs, const VAccess& rhs) { return lhs == rhs.m_e; } +inline std::ostream& operator<<(std::ostream& os, const VAccess& rhs) { return os << rhs.ascii(); } + +//###################################################################### + class VSigning { public: enum en : uint8_t { @@ -1422,7 +1449,6 @@ class AstNode { if (nodep) nodep->m_backp = this; } - void init(); // initialize value of AstNode private: AstNode* cloneTreeIter(); AstNode* cloneTreeIterList(); @@ -1442,15 +1468,7 @@ public: protected: // CONSTRUCTORS - AstNode(AstType t) - : m_type{t} { - init(); - } - AstNode(AstType t, FileLine* fl) - : m_type{t} { - init(); - m_fileline = fl; - } + AstNode(AstType t, FileLine* fl); virtual AstNode* clone() = 0; // Generally, cloneTree is what you want instead virtual void cloneRelink() {} void cloneRelinkTree(); @@ -1889,6 +1907,7 @@ public: : AstNode{t, fl} {} ASTNODE_BASE_FUNCS(NodeMath) // METHODS + virtual void dump(std::ostream& str) const override; virtual bool hasDType() const override { return true; } virtual string emitVerilog() = 0; /// Format string for verilog writing; see V3EmitV // For documentation on emitC format see EmitCStmts::emitOpName @@ -1911,6 +1930,7 @@ public: // See checkTreeIter also that asserts no children // cppcheck-suppress functionConst void iterateChildren(AstNVisitor& v) {} + virtual void dump(std::ostream& str) const override; }; class AstNodeUniop : public AstNodeMath { @@ -1925,6 +1945,7 @@ public: AstNode* lhsp() const { return op1p(); } void lhsp(AstNode* nodep) { return setOp1p(nodep); } // METHODS + virtual void dump(std::ostream& str) const override; // Set out to evaluation of a AstConst'ed lhs virtual void numberOperate(V3Number& out, const V3Number& lhs) = 0; virtual bool cleanLhs() const = 0; @@ -1987,6 +2008,7 @@ public: void rhsp(AstNode* nodep) { return setOp2p(nodep); } void thsp(AstNode* nodep) { return setOp3p(nodep); } // METHODS + virtual void dump(std::ostream& str) const override; // Set out to evaluation of a AstConst'ed virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, const V3Number& ths) @@ -2142,6 +2164,7 @@ public: } ASTNODE_BASE_FUNCS(NodeProcedure) // METHODS + virtual void dump(std::ostream& str) const override; AstNode* bodysp() const { return op2p(); } // op2 = Statements to evaluate void addStmtp(AstNode* nodep) { addOp2p(nodep); } bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); } @@ -2158,8 +2181,11 @@ public: // METHODS bool isStatement() const { return m_statement; } // Really a statement void statement(bool flag) { m_statement = flag; } - virtual void addNextStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here - virtual void addBeforeStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here + virtual void addNextStmt(AstNode* newp, + AstNode* belowp) override; // Stop statement searchback here + virtual void addBeforeStmt(AstNode* newp, + AstNode* belowp) override; // Stop statement searchback here + virtual void dump(std::ostream& str = std::cout) const override; }; class AstNodeAssign : public AstNodeStmt { @@ -2255,7 +2281,7 @@ public: class AstNodeVarRef : public AstNodeMath { // An AstVarRef or AstVarXRef private: - bool m_lvalue; // Left hand side assignment + VAccess m_access; // Left hand side assignment AstVar* m_varp; // [AfterLink] Pointer to variable itself AstVarScope* m_varScopep = nullptr; // Varscope for hierarchy AstNodeModule* m_packagep = nullptr; // Package hierarchy @@ -2264,28 +2290,29 @@ private: bool m_hierThis = false; // Hiername points to "this" function public: - AstNodeVarRef(AstType t, FileLine* fl, const string& name, bool lvalue) + AstNodeVarRef(AstType t, FileLine* fl, const string& name, const VAccess& access) : AstNodeMath{t, fl} - , m_lvalue{lvalue} + , m_access{access} , m_name{name} { this->varp(nullptr); } - AstNodeVarRef(AstType t, FileLine* fl, const string& name, AstVar* varp, bool lvalue) + AstNodeVarRef(AstType t, FileLine* fl, const string& name, AstVar* varp, const VAccess& access) : AstNodeMath{t, fl} - , m_lvalue{lvalue} + , m_access{access} , m_name{name} { // May have varp==nullptr this->varp(varp); } ASTNODE_BASE_FUNCS(NodeVarRef) + virtual void dump(std::ostream& str) const override; virtual bool hasDType() const override { return true; } virtual const char* broken() const override; virtual int instrCount() const override { return widthInstrs(); } virtual void cloneRelink() override; virtual string name() const override { return m_name; } // * = Var name virtual void name(const string& name) override { m_name = name; } - bool lvalue() const { return m_lvalue; } - void lvalue(bool lval) { m_lvalue = lval; } // Avoid using this; Set in constructor + VAccess access() const { return m_access; } + void access(const VAccess& flag) { m_access = flag; } // Avoid using this; Set in constructor AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable void varp(AstVar* varp); AstVarScope* varScopep() const { return m_varScopep; } @@ -2862,6 +2889,7 @@ public: AstNodeRange(AstType t, FileLine* fl) : AstNode{t, fl} {} ASTNODE_BASE_FUNCS(NodeRange) + virtual void dump(std::ostream& str) const override; }; //###################################################################### diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 8f140aa9e..1462df395 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -87,8 +87,10 @@ const char* AstNodeUOrStructDType::broken() const { return nullptr; } +void AstNodeStmt::dump(std::ostream& str) const { this->AstNode::dump(str); } + void AstNodeCCall::dump(std::ostream& str) const { - this->AstNode::dump(str); + this->AstNodeStmt::dump(str); if (funcp()) { str << " " << funcp()->name() << " => "; funcp()->dump(str); @@ -331,7 +333,7 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& string ostatic; if (isStatic() && namespc.empty()) ostatic = "static "; - VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep()); + VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep(), false); string oname; if (named) { @@ -1035,8 +1037,10 @@ void AstNode::dump(std::ostream& str) const { } } +void AstNodeProcedure::dump(std::ostream& str) const { this->AstNode::dump(str); } + void AstAlways::dump(std::ostream& str) const { - this->AstNode::dump(str); + this->AstNodeProcedure::dump(str); if (keyword() != VAlwaysKwd::ALWAYS) str << " [" << keyword().ascii() << "]"; } @@ -1057,8 +1061,12 @@ string AstBasicDType::prettyDTypeName() const { } return os.str(); } + +void AstNodeMath::dump(std::ostream& str) const { this->AstNode::dump(str); } +void AstNodeUniop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); } + void AstCCast::dump(std::ostream& str) const { - this->AstNode::dump(str); + this->AstNodeUniop::dump(str); str << " sz" << size(); } void AstCell::dump(std::ostream& str) const { @@ -1119,15 +1127,15 @@ void AstClassRefDType::dumpSmall(std::ostream& str) const { str << "class:" << name(); } void AstNodeCoverOrAssert::dump(std::ostream& str) const { - this->AstNode::dump(str); + this->AstNodeStmt::dump(str); if (immediate()) str << " [IMMEDIATE]"; } void AstDisplay::dump(std::ostream& str) const { - this->AstNode::dump(str); + this->AstNodeStmt::dump(str); // str<<" "<AstNode::dump(str); + this->AstNodeMath::dump(str); str << " -> "; if (itemp()) { itemp()->dump(str); @@ -1167,7 +1175,7 @@ void AstInitArray::dump(std::ostream& str) const { } } void AstJumpGo::dump(std::ostream& str) const { - this->AstNode::dump(str); + this->AstNodeStmt::dump(str); str << " -> "; if (labelp()) { labelp()->dump(str); @@ -1176,7 +1184,7 @@ void AstJumpGo::dump(std::ostream& str) const { } } void AstJumpLabel::dump(std::ostream& str) const { - this->AstNode::dump(str); + this->AstNodeStmt::dump(str); str << " -> "; if (blockp()) { blockp()->dump(str); @@ -1185,7 +1193,7 @@ void AstJumpLabel::dump(std::ostream& str) const { } } void AstMemberSel::dump(std::ostream& str) const { - this->AstNode::dump(str); + this->AstNodeMath::dump(str); str << " -> "; if (varp()) { varp()->dump(str); @@ -1194,7 +1202,7 @@ void AstMemberSel::dump(std::ostream& str) const { } } void AstMethodCall::dump(std::ostream& str) const { - this->AstNode::dump(str); + this->AstNodeStmt::dump(str); if (isStatement()) str << " [STMT]"; str << " -> "; if (taskp()) { @@ -1235,27 +1243,30 @@ void AstPin::dump(std::ostream& str) const { if (svImplicit()) str << " [.SV]"; } void AstPrintTimeScale::dump(std::ostream& str) const { - this->AstNode::dump(str); + this->AstNodeStmt::dump(str); str << " " << timeunit(); } + +void AstNodeTermop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); } void AstTime::dump(std::ostream& str) const { - this->AstNode::dump(str); + this->AstNodeTermop::dump(str); str << " " << timeunit(); } void AstTimeD::dump(std::ostream& str) const { - this->AstNode::dump(str); + this->AstNodeTermop::dump(str); str << " " << timeunit(); } void AstTimeImport::dump(std::ostream& str) const { - this->AstNode::dump(str); + this->AstNodeUniop::dump(str); str << " " << timeunit(); } void AstTypedef::dump(std::ostream& str) const { this->AstNode::dump(str); if (attrPublic()) str << " [PUBLIC]"; } +void AstNodeRange::dump(std::ostream& str) const { this->AstNode::dump(str); } void AstRange::dump(std::ostream& str) const { - this->AstNode::dump(str); + this->AstNodeRange::dump(str); if (littleEndian()) str << " [LITTLE]"; } void AstRefDType::dump(std::ostream& str) const { @@ -1352,15 +1363,16 @@ void AstPackageImport::dump(std::ostream& str) const { this->AstNode::dump(str); str << " -> " << packagep(); } +void AstNodeTriop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); } void AstSel::dump(std::ostream& str) const { - this->AstNode::dump(str); + this->AstNodeTriop::dump(str); if (declRange().ranged()) { str << " decl" << declRange() << "]"; if (declElWidth() != 1) str << "/" << declElWidth(); } } void AstSliceSel::dump(std::ostream& str) const { - this->AstNode::dump(str); + this->AstNodeTriop::dump(str); if (declRange().ranged()) str << " decl" << declRange(); } void AstMTaskBody::dump(std::ostream& str) const { @@ -1428,10 +1440,11 @@ void AstVarScope::dump(std::ostream& str) const { str << " ->UNLINKED"; } } +void AstNodeVarRef::dump(std::ostream& str) const { this->AstNodeMath::dump(str); } void AstVarXRef::dump(std::ostream& str) const { - this->AstNode::dump(str); + this->AstNodeVarRef::dump(str); if (packagep()) { str << " pkg=" << nodeAddr(packagep()); } - if (lvalue()) { + if (access().isWrite()) { str << " [LV] => "; } else { str << " [RV] <- "; @@ -1447,9 +1460,9 @@ void AstVarXRef::dump(std::ostream& str) const { } } void AstVarRef::dump(std::ostream& str) const { - this->AstNode::dump(str); + this->AstNodeVarRef::dump(str); if (packagep()) { str << " pkg=" << nodeAddr(packagep()); } - if (lvalue()) { + if (access().isWrite()) { str << " [LV] => "; } else { str << " [RV] <- "; @@ -1522,7 +1535,7 @@ void AstActive::dump(std::ostream& str) const { } } void AstNodeFTaskRef::dump(std::ostream& str) const { - this->AstNode::dump(str); + this->AstNodeStmt::dump(str); if (packagep()) { str << " pkg=" << nodeAddr(packagep()); } str << " -> "; if (dotted() != "") { str << ".=" << dotted() << " "; } @@ -1554,7 +1567,7 @@ void AstBegin::dump(std::ostream& str) const { if (implied()) str << " [IMPLIED]"; } void AstCoverDecl::dump(std::ostream& str) const { - this->AstNode::dump(str); + this->AstNodeStmt::dump(str); if (!page().empty()) str << " page=" << page(); if (!linescov().empty()) str << " lc=" << linescov(); if (this->dataDeclNullp()) { @@ -1565,7 +1578,7 @@ void AstCoverDecl::dump(std::ostream& str) const { } } void AstCoverInc::dump(std::ostream& str) const { - this->AstNode::dump(str); + this->AstNodeStmt::dump(str); str << " -> "; if (declp()) { declp()->dump(str); @@ -1578,7 +1591,7 @@ void AstFork::dump(std::ostream& str) const { if (!joinType().join()) str << " [" << joinType() << "]"; } void AstTraceInc::dump(std::ostream& str) const { - this->AstNode::dump(str); + this->AstNodeStmt::dump(str); str << " -> "; if (declp()) { declp()->dump(str); @@ -1597,10 +1610,11 @@ void AstNodeText::dump(std::ostream& str) const { str << " \"" << out << "\""; } -void AstVFile::dump(std::ostream& str) const { this->AstNode::dump(str); } +void AstNodeFile::dump(std::ostream& str) const { this->AstNode::dump(str); } +void AstVFile::dump(std::ostream& str) const { this->AstNodeFile::dump(str); } void AstCFile::dump(std::ostream& str) const { - this->AstNode::dump(str); + this->AstNodeFile::dump(str); if (source()) str << " [SRC]"; if (slow()) str << " [SLOW]"; } diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index f4dd547ff..cf681fad5 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -539,10 +539,13 @@ public: } virtual bool same(const AstNode* samep) const override { const AstAssocArrayDType* asamep = static_cast(samep); + if (!asamep->subDTypep()) return false; + if (!asamep->keyDTypep()) return false; return (subDTypep() == asamep->subDTypep() && keyDTypep() == asamep->keyDTypep()); } virtual bool similarDType(AstNodeDType* samep) const override { const AstAssocArrayDType* asamep = static_cast(samep); + if (!asamep->subDTypep()) return false; return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); } virtual string prettyDTypeName() const override; @@ -635,10 +638,12 @@ public: } virtual bool same(const AstNode* samep) const override { const AstAssocArrayDType* asamep = static_cast(samep); + if (!asamep->subDTypep()) return false; return subDTypep() == asamep->subDTypep(); } virtual bool similarDType(AstNodeDType* samep) const override { const AstAssocArrayDType* asamep = static_cast(samep); + if (!asamep->subDTypep()) return false; return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); } virtual string prettyDTypeName() const override; @@ -741,10 +746,12 @@ public: } virtual bool same(const AstNode* samep) const override { const AstNodeArrayDType* asamep = static_cast(samep); + if (!asamep->subDTypep()) return false; return (subDTypep() == asamep->subDTypep()); } virtual bool similarDType(AstNodeDType* samep) const override { const AstNodeArrayDType* asamep = static_cast(samep); + if (!asamep->subDTypep()) return false; return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); } virtual void dumpSmall(std::ostream& str) const override; @@ -1104,10 +1111,12 @@ public: } virtual bool same(const AstNode* samep) const override { const AstQueueDType* asamep = static_cast(samep); + if (!asamep->subDTypep()) return false; return (subDTypep() == asamep->subDTypep()); } virtual bool similarDType(AstNodeDType* samep) const override { const AstQueueDType* asamep = static_cast(samep); + if (!asamep->subDTypep()) return false; return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); } virtual void dumpSmall(std::ostream& str) const override; @@ -1669,7 +1678,7 @@ class AstSel : public AstNodeTriop { // Multiple bit range extraction // Parents: math|stmt // Children: varref|arraysel, math, constant math - // Tempting to have an lvalue() style method here as LHS selects are quite + // Tempting to have an access() style method here as LHS selects are quite // different, but that doesn't play well with V3Inst and bidirects which don't know direction private: VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid @@ -2177,7 +2186,7 @@ public: private: class VlArgTypeRecursed; VlArgTypeRecursed vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep, - bool compound = false) const; + bool compound) const; }; class AstDefParam : public AstNode { @@ -2319,15 +2328,15 @@ public: class AstVarRef : public AstNodeVarRef { // A reference to a variable (lvalue or rvalue) public: - AstVarRef(FileLine* fl, const string& name, bool lvalue) - : ASTGEN_SUPER(fl, name, nullptr, lvalue) {} + AstVarRef(FileLine* fl, const string& name, const VAccess& access) + : ASTGEN_SUPER(fl, name, nullptr, access) {} // This form only allowed post-link because output/wire compression may // lead to deletion of AstVar's - AstVarRef(FileLine* fl, AstVar* varp, bool lvalue) - : ASTGEN_SUPER(fl, varp->name(), varp, lvalue) {} + AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access) + : ASTGEN_SUPER(fl, varp->name(), varp, access) {} // This form only allowed post-link (see above) - AstVarRef(FileLine* fl, AstVarScope* varscp, bool lvalue) - : ASTGEN_SUPER(fl, varscp->varp()->name(), varscp->varp(), lvalue) { + AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access) + : ASTGEN_SUPER(fl, varscp->varp()->name(), varscp->varp(), access) { varScopep(varscp); } ASTNODE_NODE_FUNCS(VarRef) @@ -2340,21 +2349,23 @@ public: } inline bool same(const AstVarRef* samep) const { if (varScopep()) { - return (varScopep() == samep->varScopep() && lvalue() == samep->lvalue()); + return (varScopep() == samep->varScopep() && access() == samep->access()); } else { return (hiername() == samep->hiername() && varp()->name() == samep->varp()->name() - && lvalue() == samep->lvalue()); + && access() == samep->access()); } } inline bool sameNoLvalue(AstVarRef* samep) const { if (varScopep()) { return (varScopep() == samep->varScopep()); } else { - return (hiername() == samep->hiername() && varp()->name() == samep->varp()->name()); + return (hiername() == samep->hiername() + && (hiername() != "" || samep->hiername() != "") + && varp()->name() == samep->varp()->name()); } } virtual int instrCount() const override { - return widthInstrs() * (lvalue() ? 1 : instrCountLd()); + return widthInstrs() * (access().isWrite() ? 1 : instrCountLd()); } virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } virtual string emitC() override { V3ERROR_NA_RETURN(""); } @@ -2368,11 +2379,11 @@ private: string m_dotted; // Dotted part of scope the name()'ed reference is under or "" string m_inlinedDots; // Dotted hierarchy flattened out public: - AstVarXRef(FileLine* fl, const string& name, const string& dotted, bool lvalue) - : ASTGEN_SUPER(fl, name, nullptr, lvalue) + AstVarXRef(FileLine* fl, const string& name, const string& dotted, const VAccess& access) + : ASTGEN_SUPER(fl, name, nullptr, access) , m_dotted{dotted} {} - AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, bool lvalue) - : ASTGEN_SUPER(fl, varp->name(), varp, lvalue) + AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const VAccess& access) + : ASTGEN_SUPER(fl, varp->name(), varp, access) , m_dotted{dotted} { dtypeFrom(varp); } @@ -8235,6 +8246,32 @@ public: void isDefault(bool flag) { m_default = flag; } }; +class AstImplication : public AstNodeMath { + // Verilog |-> |=> + // Parents: math + // Children: expression +public: + AstImplication(FileLine* fl, AstNode* lhs, AstNode* rhs) + : ASTGEN_SUPER(fl) { + setOp1p(lhs); + setOp2p(rhs); + } + ASTNODE_NODE_FUNCS(Implication) + virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } + virtual string emitC() override { V3ERROR_NA_RETURN(""); } + virtual string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } + virtual int instrCount() const override { return widthInstrs(); } + AstNode* lhsp() const { return op1p(); } + AstNode* rhsp() const { return op2p(); } + void lhsp(AstNode* nodep) { return setOp1p(nodep); } + void rhsp(AstNode* nodep) { return setOp2p(nodep); } + AstSenTree* sentreep() const { return VN_CAST(op4p(), SenTree); } // op4 = clock domain + void sentreep(AstSenTree* sentreep) { addOp4p(sentreep); } // op4 = clock domain + virtual V3Hash sameHash() const override { return V3Hash(); } + virtual bool same(const AstNode* samep) const override { return true; } +}; + //====================================================================== // Assertions @@ -8461,6 +8498,7 @@ public: m_name = name; } ASTNODE_BASE_FUNCS(NodeFile) + virtual void dump(std::ostream& str) const override; virtual string name() const override { return m_name; } virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index f5a7668ec..262054805 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -203,7 +203,7 @@ private: } virtual void visit(AstVarXRef* nodep) override { UINFO(9, " VARXREF " << nodep << endl); - if (m_namedScope != "" && nodep->inlinedDots() == "") { + if (m_namedScope != "" && nodep->inlinedDots() == "" && !m_ftaskp) { nodep->inlinedDots(m_namedScope); UINFO(9, " rescope to " << nodep << endl); } diff --git a/src/V3Broken.cpp b/src/V3Broken.cpp index 4af93f4ec..9c1082689 100644 --- a/src/V3Broken.cpp +++ b/src/V3Broken.cpp @@ -275,7 +275,7 @@ private: processAndIterate(nodep); UASSERT_OBJ(!(v3Global.assertDTypesResolved() && nodep->brokeLhsMustBeLvalue() && VN_IS(nodep->lhsp(), NodeVarRef) - && !VN_CAST(nodep->lhsp(), NodeVarRef)->lvalue()), + && !VN_CAST(nodep->lhsp(), NodeVarRef)->access().isWrite()), nodep, "Assignment LHS is not an lvalue"); } virtual void visit(AstNode* nodep) override { diff --git a/src/V3CCtors.cpp b/src/V3CCtors.cpp index 55c60685e..94a0b1306 100644 --- a/src/V3CCtors.cpp +++ b/src/V3CCtors.cpp @@ -111,7 +111,7 @@ void V3CCtors::evalAsserts() { int lastWordWidth = varp->width() % storedWidth; if (lastWordWidth != 0) { // if (signal & CONST(upper_non_clean_mask)) { fail; } - AstNode* newp = new AstVarRef(varp->fileline(), varp, false); + AstNode* newp = new AstVarRef(varp->fileline(), varp, VAccess::READ); if (varp->isWide()) { newp = new AstWordSel( varp->fileline(), newp, @@ -151,8 +151,9 @@ void V3CCtors::cctorsAll() { for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) { if (AstVar* varp = VN_CAST(np, Var)) { if (!varp->isIfaceParent() && !varp->isIfaceRef() && !varp->noReset()) { - var_reset.add(new AstCReset(varp->fileline(), - new AstVarRef(varp->fileline(), varp, true))); + var_reset.add( + new AstCReset(varp->fileline(), + new AstVarRef(varp->fileline(), varp, VAccess::WRITE))); } } } diff --git a/src/V3CUse.cpp b/src/V3CUse.cpp index 087418028..dc33b101e 100644 --- a/src/V3CUse.cpp +++ b/src/V3CUse.cpp @@ -167,7 +167,14 @@ class CUseVisitor : public AstNVisitor { stmt += comma; comma = ", "; stmt += itemp->origNameProtect(); - stmt += ":\" + VL_TO_STRING("; + stmt += ":\" + "; + if (itemp->isWide()) { + stmt += "VL_TO_STRING_W("; + stmt += cvtToStr(itemp->widthWords()); + stmt += ", "; + } else { + stmt += "VL_TO_STRING("; + } stmt += itemp->nameProtect(); stmt += ");\n"; nodep->user1(true); // So what we extend dumps this diff --git a/src/V3Cast.cpp b/src/V3Cast.cpp index 66fb537c0..1f0fb7d86 100644 --- a/src/V3Cast.cpp +++ b/src/V3Cast.cpp @@ -154,9 +154,9 @@ private: } } virtual void visit(AstVarRef* nodep) override { - if (!nodep->lvalue() && !VN_IS(nodep->backp(), CCast) && VN_IS(nodep->backp(), NodeMath) - && !VN_IS(nodep->backp(), ArraySel) && nodep->backp()->width() - && castSize(nodep) != castSize(nodep->varp())) { + if (nodep->access().isRead() && !VN_IS(nodep->backp(), CCast) + && VN_IS(nodep->backp(), NodeMath) && !VN_IS(nodep->backp(), ArraySel) + && nodep->backp()->width() && castSize(nodep) != castSize(nodep->varp())) { // Cast vars to IData first, else below has upper bits wrongly set // CData x=3; out = (QData)(x<<30); insertCast(nodep, castSize(nodep)); diff --git a/src/V3Cdc.cpp b/src/V3Cdc.cpp index 24f9703aa..72d4bc243 100644 --- a/src/V3Cdc.cpp +++ b/src/V3Cdc.cpp @@ -661,7 +661,7 @@ private: // We use weight of one for normal edges, // Weight of CDC_WEIGHT_ASYNC to indicate feeds async (for reporting) // When simplify we'll take the MAX weight - if (nodep->lvalue()) { + if (nodep->access().isWrite()) { new V3GraphEdge(&m_graph, m_logicVertexp, varvertexp, 1); if (m_inDly) { varvertexp->fromFlop(true); diff --git a/src/V3Changed.cpp b/src/V3Changed.cpp index 471d0d03c..922d0686c 100644 --- a/src/V3Changed.cpp +++ b/src/V3Changed.cpp @@ -199,9 +199,9 @@ public: m_newvscp = new AstVarScope(m_vscp->fileline(), m_statep->m_scopetopp, newvarp); m_statep->m_scopetopp->addVarp(m_newvscp); - m_varEqnp = new AstVarRef(m_vscp->fileline(), m_vscp, false); - m_newLvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, true); - m_newRvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, false); + m_varEqnp = new AstVarRef(m_vscp->fileline(), m_vscp, VAccess::READ); + m_newLvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, VAccess::WRITE); + m_newRvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, VAccess::READ); } iterate(vscp->dtypep()->skipRefp()); m_varEqnp->deleteTree(); diff --git a/src/V3Clock.cpp b/src/V3Clock.cpp index 378bf4245..1c39a0c9b 100644 --- a/src/V3Clock.cpp +++ b/src/V3Clock.cpp @@ -79,15 +79,15 @@ private: vscp->user1p(newvscp); m_scopep->addVarp(newvscp); // Add init - AstNode* fromp = new AstVarRef(newvarp->fileline(), vscp, false); + AstNode* fromp = new AstVarRef(newvarp->fileline(), vscp, VAccess::READ); if (v3Global.opt.xInitialEdge()) fromp = new AstNot(fromp->fileline(), fromp); AstNode* newinitp = new AstAssign( - vscp->fileline(), new AstVarRef(newvarp->fileline(), newvscp, true), fromp); + vscp->fileline(), new AstVarRef(newvarp->fileline(), newvscp, VAccess::WRITE), fromp); addToInitial(newinitp); // At bottom, assign them - AstAssign* finalp - = new AstAssign(vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, true), - new AstVarRef(vscp->fileline(), vscp, false)); + AstAssign* finalp = new AstAssign(vscp->fileline(), + new AstVarRef(vscp->fileline(), newvscp, VAccess::WRITE), + new AstVarRef(vscp->fileline(), vscp, VAccess::READ)); m_evalFuncp->addFinalsp(finalp); // UINFO(4, "New Last: " << newvscp << endl); @@ -112,25 +112,28 @@ private: AstVarScope* lastVscp = getCreateLastClk(clkvscp); newp = new AstAnd( nodep->fileline(), - new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false), - new AstNot(nodep->fileline(), new AstVarRef(nodep->fileline(), lastVscp, false))); + new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), VAccess::READ), + new AstNot(nodep->fileline(), + new AstVarRef(nodep->fileline(), lastVscp, VAccess::READ))); } else if (nodep->edgeType() == VEdgeType::ET_NEGEDGE) { AstVarScope* lastVscp = getCreateLastClk(clkvscp); newp = new AstAnd( nodep->fileline(), new AstNot(nodep->fileline(), - new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false)), - new AstVarRef(nodep->fileline(), lastVscp, false)); + new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), + VAccess::READ)), + new AstVarRef(nodep->fileline(), lastVscp, VAccess::READ)); } else if (nodep->edgeType() == VEdgeType::ET_BOTHEDGE) { AstVarScope* lastVscp = getCreateLastClk(clkvscp); newp = new AstXor( nodep->fileline(), - new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false), - new AstVarRef(nodep->fileline(), lastVscp, false)); + new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), VAccess::READ), + new AstVarRef(nodep->fileline(), lastVscp, VAccess::READ)); } else if (nodep->edgeType() == VEdgeType::ET_HIGHEDGE) { - newp = new AstVarRef(nodep->fileline(), clkvscp, false); + newp = new AstVarRef(nodep->fileline(), clkvscp, VAccess::READ); } else if (nodep->edgeType() == VEdgeType::ET_LOWEDGE) { - newp = new AstNot(nodep->fileline(), new AstVarRef(nodep->fileline(), clkvscp, false)); + newp = new AstNot(nodep->fileline(), + new AstVarRef(nodep->fileline(), clkvscp, VAccess::READ)); } else { nodep->v3fatalSrc("Bad edge type"); } diff --git a/src/V3Const.cpp b/src/V3Const.cpp index ef617c634..bfadcab72 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -314,7 +314,7 @@ private: // It was an expression, then got constified. In reality, the WordSel // must be wrapped in a Cond, that will be false. return (VN_IS(nodep->rhsp(), Const) && VN_IS(nodep->fromp(), NodeVarRef) - && !VN_CAST_CONST(nodep->fromp(), NodeVarRef)->lvalue() + && !VN_CAST_CONST(nodep->fromp(), NodeVarRef)->access().isWrite() && (static_cast(VN_CAST_CONST(nodep->rhsp(), Const)->toUInt()) >= VN_CAST(nodep->fromp(), NodeVarRef)->varp()->widthWords())); } @@ -1132,18 +1132,22 @@ private: VFlagLogicPacked(), msb2 - lsb2 + 1); m_modp->addStmtp(temp1p); m_modp->addStmtp(temp2p); - AstNodeAssign* asn1ap = VN_CAST( - nodep->cloneType(new AstVarRef(sel1p->fileline(), temp1p, true), sel1p), - NodeAssign); - AstNodeAssign* asn2ap = VN_CAST( - nodep->cloneType(new AstVarRef(sel2p->fileline(), temp2p, true), sel2p), - NodeAssign); - AstNodeAssign* asn1bp = VN_CAST( - nodep->cloneType(lc1p, new AstVarRef(sel1p->fileline(), temp1p, false)), - NodeAssign); - AstNodeAssign* asn2bp = VN_CAST( - nodep->cloneType(lc2p, new AstVarRef(sel2p->fileline(), temp2p, false)), - NodeAssign); + AstNodeAssign* asn1ap + = VN_CAST(nodep->cloneType( + new AstVarRef(sel1p->fileline(), temp1p, VAccess::WRITE), sel1p), + NodeAssign); + AstNodeAssign* asn2ap + = VN_CAST(nodep->cloneType( + new AstVarRef(sel2p->fileline(), temp2p, VAccess::WRITE), sel2p), + NodeAssign); + AstNodeAssign* asn1bp + = VN_CAST(nodep->cloneType( + lc1p, new AstVarRef(sel1p->fileline(), temp1p, VAccess::READ)), + NodeAssign); + AstNodeAssign* asn2bp + = VN_CAST(nodep->cloneType( + lc2p, new AstVarRef(sel2p->fileline(), temp2p, VAccess::READ)), + NodeAssign); asn1ap->dtypeFrom(temp1p); asn1bp->dtypeFrom(temp1p); asn2ap->dtypeFrom(temp2p); @@ -1601,7 +1605,7 @@ private: // if (debug()) valuep->dumpTree(cout, " visitvaref: "); iterateAndNextNull(nodep->varp()->valuep()); // May change nodep->varp()->valuep() AstNode* valuep = nodep->varp()->valuep(); - if (!nodep->lvalue() + if (!nodep->access().isWrite() && ((!m_params // Can reduce constant wires into equations && m_doNConst && v3Global.opt.oConst() diff --git a/src/V3Coverage.cpp b/src/V3Coverage.cpp index f371d4fa8..344d24d28 100644 --- a/src/V3Coverage.cpp +++ b/src/V3Coverage.cpp @@ -130,8 +130,8 @@ private: m_modp->addStmtp(varp); UINFO(5, "New coverage trace: " << varp << endl); AstAssign* assp = new AstAssign( - incp->fileline(), new AstVarRef(incp->fileline(), varp, true), - new AstAdd(incp->fileline(), new AstVarRef(incp->fileline(), varp, false), + incp->fileline(), new AstVarRef(incp->fileline(), varp, VAccess::WRITE), + new AstAdd(incp->fileline(), new AstVarRef(incp->fileline(), varp, VAccess::READ), new AstConst(incp->fileline(), AstConst::WidthedValue(), 32, 1))); incp->addNext(assp); } @@ -288,8 +288,9 @@ private: // This is necessarily an O(n^2) expansion, which is why // we limit coverage to signals with < 256 bits. - ToggleEnt newvec(string(""), new AstVarRef(nodep->fileline(), nodep, false), - new AstVarRef(nodep->fileline(), chgVarp, true)); + ToggleEnt newvec(string(""), + new AstVarRef(nodep->fileline(), nodep, VAccess::READ), + new AstVarRef(nodep->fileline(), chgVarp, VAccess::WRITE)); toggleVarRecurse(nodep->dtypeSkipRefp(), 0, newvec, nodep, chgVarp); newvec.cleanup(); } diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index 4ba1acb24..c042968f9 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -228,9 +228,10 @@ private: AstVarScope* bitvscp = createVarSc(varrefp->varScopep(), bitvarname, dimp->width(), nullptr); AstAssign* bitassignp = new AstAssign( - nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, true), dimp); + nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, VAccess::WRITE), + dimp); nodep->addNextHere(bitassignp); - dimreadps.push_front(new AstVarRef(nodep->fileline(), bitvscp, false)); + dimreadps.push_front(new AstVarRef(nodep->fileline(), bitvscp, VAccess::READ)); } } // @@ -247,9 +248,10 @@ private: AstVarScope* bitvscp = createVarSc(varrefp->varScopep(), bitvarname, lsbvaluep->width(), nullptr); AstAssign* bitassignp = new AstAssign( - nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, true), lsbvaluep); + nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, VAccess::WRITE), + lsbvaluep); nodep->addNextHere(bitassignp); - bitreadp = new AstVarRef(nodep->fileline(), bitvscp, false); + bitreadp = new AstVarRef(nodep->fileline(), bitvscp, VAccess::READ); } } // @@ -263,8 +265,8 @@ private: = (string("__Vdlyvval__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum)); AstVarScope* valvscp = createVarSc(varrefp->varScopep(), valvarname, 0, nodep->rhsp()->dtypep()); - newlhsp = new AstVarRef(nodep->fileline(), valvscp, true); - valreadp = new AstVarRef(nodep->fileline(), valvscp, false); + newlhsp = new AstVarRef(nodep->fileline(), valvscp, VAccess::WRITE); + valreadp = new AstVarRef(nodep->fileline(), valvscp, VAccess::READ); } // //=== Setting/not setting boolean: __Vdlyvset__ @@ -283,11 +285,11 @@ private: = (string("__Vdlyvset__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum)); setvscp = createVarSc(varrefp->varScopep(), setvarname, 1, nullptr); setinitp = new AstAssignPre(nodep->fileline(), - new AstVarRef(nodep->fileline(), setvscp, true), + new AstVarRef(nodep->fileline(), setvscp, VAccess::WRITE), new AstConst(nodep->fileline(), 0)); - AstAssign* setassignp - = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, true), - new AstConst(nodep->fileline(), AstConst::LogicTrue())); + AstAssign* setassignp = new AstAssign( + nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, VAccess::WRITE), + new AstConst(nodep->fileline(), AstConst::LogicTrue())); nodep->addNextHere(setassignp); } if (m_nextDlyp) { // Tell next assigndly it can share the variable @@ -332,9 +334,9 @@ private: UASSERT_OBJ(postLogicp, nodep, "Delayed assignment misoptimized; prev var found w/o associated IF"); } else { - postLogicp - = new AstIf(nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, false), - nullptr, nullptr); + postLogicp = new AstIf(nodep->fileline(), + new AstVarRef(nodep->fileline(), setvscp, VAccess::READ), + nullptr, nullptr); UINFO(9, " Created " << postLogicp << endl); finalp->addBodysp(postLogicp); finalp->user3p(setvscp); // Remember IF's vset variable @@ -406,7 +408,7 @@ private: virtual void visit(AstVarRef* nodep) override { if (!nodep->user2Inc()) { // Not done yet - if (m_inDly && nodep->lvalue()) { + if (m_inDly && nodep->access().isWrite()) { UINFO(4, "AssignDlyVar: " << nodep << endl); markVarUsage(nodep->varScopep(), VU_DLY); UASSERT_OBJ(m_activep, nodep, "<= not under sensitivity block"); @@ -429,16 +431,19 @@ private: if (basicp && basicp->isEventValue()) { // Events go to zero on next timestep unless reactivated prep = new AstAssignPre( - nodep->fileline(), new AstVarRef(nodep->fileline(), dlyvscp, true), + nodep->fileline(), + new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE), new AstConst(nodep->fileline(), AstConst::LogicFalse())); } else { - prep = new AstAssignPre(nodep->fileline(), - new AstVarRef(nodep->fileline(), dlyvscp, true), - new AstVarRef(nodep->fileline(), oldvscp, false)); + prep = new AstAssignPre( + nodep->fileline(), + new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE), + new AstVarRef(nodep->fileline(), oldvscp, VAccess::READ)); } AstNodeAssign* postp = new AstAssignPost( - nodep->fileline(), new AstVarRef(nodep->fileline(), oldvscp, true), - new AstVarRef(nodep->fileline(), dlyvscp, false)); + nodep->fileline(), + new AstVarRef(nodep->fileline(), oldvscp, VAccess::WRITE), + new AstVarRef(nodep->fileline(), dlyvscp, VAccess::READ)); postp->lhsp()->user2(true); // Don't detect this assignment oldvscp->user1p(dlyvscp); // So we can find it later // Make new ACTIVE with identical sensitivity tree @@ -447,11 +452,11 @@ private: newactp->addStmtsp(prep); // Add to FRONT of statements newactp->addStmtsp(postp); } - AstVarRef* newrefp = new AstVarRef(nodep->fileline(), dlyvscp, true); + AstVarRef* newrefp = new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE); newrefp->user2(true); // No reason to do it again nodep->replaceWith(newrefp); VL_DO_DANGLING(nodep->deleteTree(), nodep); - } else if (!m_inDly && nodep->lvalue()) { + } else if (!m_inDly && nodep->access().isWrite()) { // UINFO(9, "NBA " << nodep << endl); if (!m_inInitial) { UINFO(4, "AssignNDlyVar: " << nodep << endl); diff --git a/src/V3Depth.cpp b/src/V3Depth.cpp index d76a5cc11..0eee958f0 100644 --- a/src/V3Depth.cpp +++ b/src/V3Depth.cpp @@ -64,11 +64,11 @@ private: UASSERT_OBJ(m_funcp, nodep, "Deep expression not under a function"); m_funcp->addInitsp(varp); // Replace node tree with reference to var - AstVarRef* newp = new AstVarRef(nodep->fileline(), varp, false); + AstVarRef* newp = new AstVarRef(nodep->fileline(), varp, VAccess::READ); nodep->replaceWith(newp); // Put assignment before the referencing statement - AstAssign* assp = new AstAssign(nodep->fileline(), - new AstVarRef(nodep->fileline(), varp, true), nodep); + AstAssign* assp = new AstAssign( + nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::WRITE), nodep); AstNRelinker linker2; m_stmtp->unlinkFrBack(&linker2); assp->addNext(m_stmtp); diff --git a/src/V3Descope.cpp b/src/V3Descope.cpp index 007c8236e..9bbb522da 100644 --- a/src/V3Descope.cpp +++ b/src/V3Descope.cpp @@ -184,8 +184,9 @@ private: for (AstNode* stmtp = newfuncp->argsp(); stmtp; stmtp = stmtp->nextp()) { if (AstVar* portp = VN_CAST(stmtp, Var)) { if (portp->isIO() && !portp->isFuncReturn()) { - AstNode* newp - = new AstVarRef(portp->fileline(), portp, portp->isWritable()); + AstNode* newp = new AstVarRef(portp->fileline(), portp, + portp->isWritable() ? VAccess::WRITE + : VAccess::READ); argsp = argsp ? argsp->addNextNull(newp) : newp; } } diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp index 8139cd418..2b14984fc 100644 --- a/src/V3EmitCMake.cpp +++ b/src/V3EmitCMake.cpp @@ -204,15 +204,14 @@ class CMakeEmitter { *of << "# Verilate hierarchical blocks\n"; // Sorted hierarchical blocks in order of leaf-first. const V3HierBlockPlan::HierVector& hierBlocks = planp->hierBlocksSorted(); - const string topTarget = v3Global.opt.protectLib().empty() ? v3Global.opt.prefix() - : v3Global.opt.protectLib(); + *of << "get_target_property(TOP_TARGET_NAME \"${TARGET}\" NAME)\n"; for (V3HierBlockPlan::HierVector::const_iterator it = hierBlocks.begin(); it != hierBlocks.end(); ++it) { const V3HierBlock* hblockp = *it; const V3HierBlock::HierBlockSet& children = hblockp->children(); const string prefix = hblockp->hierPrefix(); *of << "add_library(" << prefix << " STATIC)\n"; - *of << "target_link_libraries(" << topTarget << " PRIVATE " << prefix << ")\n"; + *of << "target_link_libraries(${TOP_TARGET_NAME} PRIVATE " << prefix << ")\n"; if (!children.empty()) { *of << "target_link_libraries(" << prefix << " INTERFACE"; for (V3HierBlock::HierBlockSet::const_iterator child = children.begin(); @@ -223,14 +222,17 @@ class CMakeEmitter { } *of << "verilate(" << prefix << " PREFIX " << prefix << " TOP_MODULE " << hblockp->modp()->name() << " DIRECTORY " - << deslash("${CMAKE_CURRENT_BINARY_DIR}/" + prefix) << " SOURCES "; + << deslash(v3Global.opt.makeDir() + "/" + prefix) << " SOURCES "; for (V3HierBlock::HierBlockSet::const_iterator child = children.begin(); child != children.end(); ++child) { - *of << deslash(" ${CMAKE_CURRENT_BINARY_DIR}/" + (*child)->hierWrapper(true)); + *of << " " + << deslash(v3Global.opt.makeDir() + "/" + (*child)->hierWrapper(true)); } *of << " "; + const string vFile = hblockp->vFileIfNecessary(); + if (!vFile.empty()) *of << vFile << " "; const V3StringList& vFiles = v3Global.opt.vFiles(); - for (const string& i : vFiles) *of << V3Os::filenameRealPath(i); + for (const string& i : vFiles) *of << V3Os::filenameRealPath(i) << " "; *of << " VERILATOR_ARGS "; *of << "-f " << deslash(hblockp->commandArgsFileName(true)) << " -CFLAGS -fPIC" // hierarchical block will be static, but may be linked @@ -238,11 +240,12 @@ class CMakeEmitter { << ")\n"; } *of << "\n# Verilate the top module that refers protect-lib wrappers of above\n"; - *of << "verilate(" << topTarget << " PREFIX " << v3Global.opt.prefix() - << " TOP_MODULE " << v3Global.rootp()->topModulep()->name() << " DIRECTORY " - << deslash("${CMAKE_CURRENT_BINARY_DIR}/" + topTarget + ".dir") << " SOURCES "; + *of << "verilate(${TOP_TARGET_NAME} PREFIX " << v3Global.opt.prefix() << " TOP_MODULE " + << v3Global.rootp()->topModulep()->name() << " DIRECTORY " + << deslash(v3Global.opt.makeDir()) << " SOURCES "; for (V3HierBlockPlan::const_iterator it = planp->begin(); it != planp->end(); ++it) { - *of << deslash(" ${CMAKE_CURRENT_BINARY_DIR}/" + it->second->hierWrapper(true)); + *of << " " + << deslash(v3Global.opt.makeDir() + "/" + it->second->hierWrapper(true)); } *of << " " << deslash(cmake_list(v3Global.opt.vFiles())); *of << " VERILATOR_ARGS "; diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index e0cfd151a..55312dbe3 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -65,6 +65,10 @@ public: of.puts("VM_TRACE = "); of.puts(v3Global.opt.trace() ? "1" : "0"); of.puts("\n"); + of.puts("# Tracing output mode in FST format? 0/1 (from --trace-fst)\n"); + of.puts("VM_TRACE_FST = "); + of.puts(v3Global.opt.trace() && v3Global.opt.traceFormat().fst() ? "1" : "0"); + of.puts("\n"); of.puts("# Tracing threaded output mode? 0/1/N threads (from --trace-thread)\n"); of.puts("VM_TRACE_THREADS = "); of.puts(cvtToStr(v3Global.opt.trueTraceThreads())); diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 6ebfece29..2cd744a85 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -31,6 +31,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { // MEMBERS bool m_suppressSemi = false; + bool m_suppressUnknown = false; AstSenTree* m_sensesp; // Domain for printing one a ALWAYS under a ACTIVE // METHODS @@ -51,12 +52,13 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { } // VISITORS - virtual void visit(AstNetlist* nodep) override { iterateChildren(nodep); } + virtual void visit(AstNetlist* nodep) override { iterateAndNextNull(nodep->modulesp()); } virtual void visit(AstNodeModule* nodep) override { putfs(nodep, nodep->verilogKwd() + " " + prefixNameProtect(nodep) + ";\n"); iterateChildren(nodep); putqs(nodep, "end" + nodep->verilogKwd() + "\n"); } + virtual void visit(AstPort* nodep) override {} virtual void visit(AstNodeFTask* nodep) override { putfs(nodep, nodep->isFunction() ? "function" : "task"); puts(" "); @@ -212,14 +214,14 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { void visitNodeDisplay(AstNode* nodep, AstNode* fileOrStrgp, const string& text, AstNode* exprsp) { putfs(nodep, nodep->verilogKwd()); - putbs(" ("); + putbs("("); if (fileOrStrgp) { iterateAndNextNull(fileOrStrgp); - putbs(","); + putbs(", "); } putsQuoted(text); for (AstNode* expp = exprsp; expp; expp = expp->nextp()) { - puts(","); + puts(", "); iterateAndNextNull(expp); } puts(");\n"); @@ -247,7 +249,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { putfs(nodep, nodep->verilogKwd()); putbs("("); iterateAndNextNull(nodep->filenamep()); - putbs(","); + putbs(", "); iterateAndNextNull(nodep->modep()); puts(");\n"); } @@ -259,13 +261,13 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { } virtual void visit(AstFClose* nodep) override { putfs(nodep, nodep->verilogKwd()); - putbs(" ("); + putbs("("); if (nodep->filep()) iterateAndNextNull(nodep->filep()); puts(");\n"); } virtual void visit(AstFFlush* nodep) override { putfs(nodep, nodep->verilogKwd()); - putbs(" ("); + putbs("("); if (nodep->filep()) iterateAndNextNull(nodep->filep()); puts(");\n"); } @@ -282,16 +284,16 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { } virtual void visit(AstNodeReadWriteMem* nodep) override { putfs(nodep, nodep->verilogKwd()); - putbs(" ("); + putbs("("); if (nodep->filenamep()) iterateAndNextNull(nodep->filenamep()); - putbs(","); + putbs(", "); if (nodep->memp()) iterateAndNextNull(nodep->memp()); if (nodep->lsbp()) { - putbs(","); + putbs(", "); iterateAndNextNull(nodep->lsbp()); } if (nodep->msbp()) { - putbs(","); + putbs(", "); iterateAndNextNull(nodep->msbp()); } puts(");\n"); @@ -302,7 +304,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { } virtual void visit(AstSysIgnore* nodep) override { putfs(nodep, nodep->verilogKwd()); - putbs(" ("); + putbs("("); iterateAndNextNull(nodep->exprsp()); puts(");\n"); } @@ -358,7 +360,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { putfs(nodep, "$past("); iterateAndNextNull(nodep->exprp()); if (nodep->ticksp()) { - puts(","); + puts(", "); iterateAndNextNull(nodep->ticksp()); } puts(")"); @@ -482,7 +484,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { putfs(nodep, "$_ATTROF("); iterateAndNextNull(nodep->fromp()); if (nodep->dimp()) { - putbs(","); + putbs(", "); iterateAndNextNull(nodep->dimp()); } puts(")"); @@ -654,13 +656,17 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { puts(string("\n???? // ") + nodep->prettyTypeName() + "\n"); iterateChildren(nodep); // Not v3fatalSrc so we keep processing - nodep->v3error("Internal: Unknown node type reached emitter: " << nodep->prettyTypeName()); + if (!m_suppressUnknown) { + nodep->v3error( + "Internal: Unknown node type reached emitter: " << nodep->prettyTypeName()); + } } public: bool m_suppressVarSemi = false; // Suppress emitting semicolon for AstVars - explicit EmitVBaseVisitor(AstSenTree* domainp = nullptr) - : m_sensesp{domainp} {} + explicit EmitVBaseVisitor(bool suppressUnknown, AstSenTree* domainp) + : m_suppressUnknown{suppressUnknown} + , m_sensesp{domainp} {} virtual ~EmitVBaseVisitor() override {} }; @@ -679,8 +685,9 @@ class EmitVFileVisitor : public EmitVBaseVisitor { virtual void putsNoTracking(const string& str) override { ofp()->putsNoTracking(str); } public: - EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText = false, - bool suppressVarSemi = false) { + EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText, bool suppressVarSemi, + bool suppressUnknown) + : EmitVBaseVisitor{suppressUnknown, nullptr} { m_ofp = ofp; m_trackText = trackText; m_suppressVarSemi = suppressVarSemi; @@ -704,7 +711,8 @@ class EmitVStreamVisitor : public EmitVBaseVisitor { public: EmitVStreamVisitor(AstNode* nodep, std::ostream& os) - : m_os(os) { // Need () or GCC 4.8 false warning + : EmitVBaseVisitor{false, nullptr} + , m_os(os) { // Need () or GCC 4.8 false warning iterate(nodep); } virtual ~EmitVStreamVisitor() override {} @@ -747,9 +755,8 @@ public: , m_prefix{prefix} , m_flWidth{flWidth} { m_column = 0; - m_prefixFl - = v3Global.rootp() - ->fileline(); // NETLIST's fileline instead of nullptr to avoid nullptr checks + m_prefixFl = v3Global.rootp()->fileline(); // NETLIST's fileline instead of nullptr to + // avoid nullptr checks } virtual ~EmitVPrefixedFormatter() override { if (m_column) puts("\n"); @@ -780,7 +787,7 @@ class EmitVPrefixedVisitor : public EmitVBaseVisitor { public: EmitVPrefixedVisitor(AstNode* nodep, std::ostream& os, const string& prefix, int flWidth, AstSenTree* domainp, bool user3mark) - : EmitVBaseVisitor{domainp} + : EmitVBaseVisitor{false, domainp} , m_formatter{os, prefix, flWidth} { if (user3mark) { AstUser3InUse::check(); } iterate(nodep); @@ -807,7 +814,14 @@ void V3EmitV::emitvFiles() { V3OutVFile of(vfilep->name()); of.puts("// DESCR" "IPTION: Verilator generated Verilog\n"); - EmitVFileVisitor visitor(vfilep->tblockp(), &of, true, true); + EmitVFileVisitor visitor(vfilep->tblockp(), &of, true, true, false); } } } + +void V3EmitV::debugEmitV(const string& stage) { + UINFO(2, __FUNCTION__ << ": " << endl); + string filename = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__" + stage + ".v"; + V3OutVFile of(filename); + EmitVFileVisitor visitor(v3Global.rootp(), &of, true, false, true); +} diff --git a/src/V3EmitV.h b/src/V3EmitV.h index 5ccf5c9b8..4a4900895 100644 --- a/src/V3EmitV.h +++ b/src/V3EmitV.h @@ -31,6 +31,7 @@ public: static void verilogPrefixedTree(AstNode* nodep, std::ostream& os, const string& prefix, int flWidth, AstSenTree* domainp, bool user3mark); static void emitvFiles(); + static void debugEmitV(const string& stage); }; #endif // Guard diff --git a/src/V3Expand.cpp b/src/V3Expand.cpp index a1b9d4ed0..fb6bc7c43 100644 --- a/src/V3Expand.cpp +++ b/src/V3Expand.cpp @@ -94,7 +94,7 @@ private: void fixCloneLvalue(AstNode* nodep) { // In AstSel transforms, we call clone() on VarRefs that were lvalues, // but are now being used on the RHS of the assignment - if (VN_IS(nodep, VarRef)) VN_CAST(nodep, VarRef)->lvalue(false); + if (VN_IS(nodep, VarRef)) VN_CAST(nodep, VarRef)->access(VAccess::READ); // Iterate if (nodep->op1p()) fixCloneLvalue(nodep->op1p()); if (nodep->op2p()) fixCloneLvalue(nodep->op2p()); diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 085586bf5..3bf82c08c 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -220,7 +220,7 @@ private: if (nodep->varScopep()->varp()->isSc()) { clearSimple("SystemC sig"); // Don't want to eliminate the VL_ASSIGN_SI's } - if (nodep->lvalue()) { + if (nodep->access().isWrite()) { if (m_lhsVarRef) clearSimple(">1 lhs varRefs"); m_lhsVarRef = nodep; } else { @@ -448,7 +448,7 @@ private: vvertexp->setIsClock(); // For SYNCASYNCNET varscp->user2(true); - } else if (m_activep && m_activep->hasClocked() && !nodep->lvalue()) { + } else if (m_activep && m_activep->hasClocked() && !nodep->access().isWrite()) { if (varscp->user2()) { if (!vvertexp->rstAsyncNodep()) vvertexp->rstAsyncNodep(nodep); } else { @@ -457,7 +457,7 @@ private: } // We use weight of one; if we ref the var more than once, when we simplify, // the weight will increase - if (nodep->lvalue()) { + if (nodep->access().isWrite()) { new V3GraphEdge(&m_graph, m_logicVertexp, vvertexp, 1); } else { new V3GraphEdge(&m_graph, vvertexp, m_logicVertexp, 1); @@ -525,10 +525,7 @@ private: public: // CONSTRUCTORS - explicit GateVisitor(AstNode* nodep) { - AstNode::user1ClearTree(); - iterate(nodep); - } + explicit GateVisitor(AstNode* nodep) { iterate(nodep); } virtual ~GateVisitor() override { V3Stats::addStat("Optimizations, Gate sigs deleted", m_statSigs); V3Stats::addStat("Optimizations, Gate inputs replaced", m_statRefs); @@ -845,7 +842,7 @@ private: // It's possible we substitute into something that will be reduced more later, // however, as we never delete the top Always/initial statement, all should be well. m_didReplace = true; - UASSERT_OBJ(!nodep->lvalue(), nodep, + UASSERT_OBJ(!nodep->access().isWrite(), nodep, "Can't replace lvalue assignments with const var"); AstNode* substp = m_replaceTreep->cloneTree(false); UASSERT_OBJ( @@ -859,7 +856,8 @@ private: // to throw warnings that point to a PIN rather than where the pin us used. if (VN_IS(substp, VarRef)) substp->fileline(nodep->fileline()); // Make the substp an rvalue like nodep. This facilitates the hashing in dedupe. - if (AstNodeVarRef* varrefp = VN_CAST(substp, NodeVarRef)) varrefp->lvalue(false); + if (AstNodeVarRef* varrefp = VN_CAST(substp, NodeVarRef)) + varrefp->access(VAccess::READ); hashReplace(nodep, substp); nodep->replaceWith(substp); VL_DO_DANGLING(nodep->deleteTree(), nodep); @@ -1514,7 +1512,7 @@ private: UINFO(9, "CLK DECOMP Connecting - " << assignp->lhsp() << endl); UINFO(9, " to - " << m_clk_vsp << endl); AstNode* rhsp = assignp->rhsp(); - rhsp->replaceWith(new AstVarRef(rhsp->fileline(), m_clk_vsp, false)); + rhsp->replaceWith(new AstVarRef(rhsp->fileline(), m_clk_vsp, VAccess::READ)); while (V3GraphEdge* edgep = lvertexp->inBeginp()) { VL_DO_DANGLING(edgep->unlinkDelete(), edgep); } diff --git a/src/V3GenClk.cpp b/src/V3GenClk.cpp index 60ba799df..729708b7e 100644 --- a/src/V3GenClk.cpp +++ b/src/V3GenClk.cpp @@ -67,9 +67,9 @@ private: m_topModp->addStmtp(newvarp); AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp); m_scopetopp->addVarp(newvscp); - AstAssign* asninitp - = new AstAssign(vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, true), - new AstVarRef(vscp->fileline(), vscp, false)); + AstAssign* asninitp = new AstAssign( + vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, VAccess::WRITE), + new AstVarRef(vscp->fileline(), vscp, VAccess::READ)); m_scopetopp->addFinalClkp(asninitp); // vscp->user2p(newvscp); @@ -98,7 +98,7 @@ private: UINFO(8, " VarActReplace " << nodep << endl); // Replace with the new variable AstVarScope* newvscp = genInpClk(vscp); - AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->lvalue()); + AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->access()); nodep->replaceWith(newrefp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } @@ -186,7 +186,7 @@ private: UINFO(8, " VarAct " << nodep << endl); vscp->user1(true); } - if (m_assignp && nodep->lvalue() && vscp->user1()) { + if (m_assignp && nodep->access().isWrite() && vscp->user1()) { // Variable was previously used as a clock, and is now being set // Thus a unordered generated clock... UINFO(8, " VarSetAct " << nodep << endl); diff --git a/src/V3Global.cpp b/src/V3Global.cpp index 2b8a627fe..bfdfc1311 100644 --- a/src/V3Global.cpp +++ b/src/V3Global.cpp @@ -35,6 +35,12 @@ AstNetlist* V3Global::makeNetlist() { return newp; } +void V3Global::clear() { +#ifdef VL_LEAK_CHECK + if (m_rootp) VL_DO_CLEAR(m_rootp->deleteTree(), m_rootp = nullptr); +#endif +} + void V3Global::shutdown() { VL_DO_CLEAR(delete m_hierPlanp, m_hierPlanp = nullptr); // delete nullptr is safe } diff --git a/src/V3Global.h b/src/V3Global.h index 3c607052e..ec4b6d0f1 100644 --- a/src/V3Global.h +++ b/src/V3Global.h @@ -119,6 +119,7 @@ public: UASSERT(!m_rootp, "call once"); m_rootp = makeNetlist(); } + void clear(); void shutdown(); // Release allocated resorces // ACCESSORS (general) AstNetlist* rootp() const { return m_rootp; } diff --git a/src/V3HierBlock.cpp b/src/V3HierBlock.cpp index 59adf8211..f1858cdf0 100644 --- a/src/V3HierBlock.cpp +++ b/src/V3HierBlock.cpp @@ -80,6 +80,7 @@ #include "V3Error.h" #include "V3File.h" #include "V3HierBlock.h" +#include "V3Os.h" #include "V3String.h" #include "V3Stats.h" @@ -88,13 +89,18 @@ static string V3HierCommandArgsFileName(const string& prefix, bool forCMake) { + (forCMake ? "_hierCMakeArgs.f" : "_hierMkArgs.f"); } -static void V3HierWriteCommonInputs(std::ostream* of, bool forCMake) { +static void V3HierWriteCommonInputs(const V3HierBlock* hblockp, std::ostream* of, bool forCMake) { + string topModuleFile; + if (hblockp) topModuleFile = hblockp->vFileIfNecessary(); if (!forCMake) { + if (!topModuleFile.empty()) *of << topModuleFile << "\n"; const V3StringList& vFiles = v3Global.opt.vFiles(); for (const string& i : vFiles) *of << i << "\n"; } const V3StringSet& libraryFiles = v3Global.opt.libraryFiles(); - for (const string& i : libraryFiles) *of << "-v " << i << "\n"; + for (const string& i : libraryFiles) { + if (V3Os::filenameRealPath(i) != topModuleFile) *of << "-v " << i << "\n"; + } } //###################################################################### @@ -194,6 +200,15 @@ string V3HierBlock::hierGenerated(bool withDir) const { return hierWrapper(withDir) + ' ' + hierMk(withDir); } +string V3HierBlock::vFileIfNecessary() const { + const string filename = V3Os::filenameRealPath(m_modp->fileline()->filename()); + for (const string& v : v3Global.opt.vFiles()) { + // Already listed in vFiles, so no need to add the file. + if (filename == V3Os::filenameRealPath(v)) return ""; + } + return filename; +} + void V3HierBlock::writeCommandArgsFile(bool forCMake) const { std::unique_ptr of(V3File::new_ofstream(commandArgsFileName(forCMake))); *of << "--cc\n"; @@ -203,9 +218,9 @@ void V3HierBlock::writeCommandArgsFile(bool forCMake) const { child != m_children.end(); ++child) { *of << v3Global.opt.makeDir() << "/" << (*child)->hierWrapper(true) << "\n"; } + *of << "-Mdir " << v3Global.opt.makeDir() << "/" << hierPrefix() << " \n"; } - *of << "-Mdir " << v3Global.opt.makeDir() << "/" << hierPrefix() << " \n"; - V3HierWriteCommonInputs(of.get(), forCMake); + V3HierWriteCommonInputs(this, of.get(), forCMake); const V3StringList& commandOpts = commandArgs(false); for (const string& opt : commandOpts) *of << opt << "\n"; *of << hierBlockArgs().front() << "\n"; @@ -213,6 +228,9 @@ void V3HierBlock::writeCommandArgsFile(bool forCMake) const { ++child) { *of << (*child)->hierBlockArgs().front() << "\n"; } + // Hierarchical blocks should not use multi-threading, + // but needs to be thread safe when top is multi-threaded. + if (v3Global.opt.threads() > 0) { *of << "--threads 1\n"; } *of << v3Global.opt.allArgsStringForHierBlock(false) << "\n"; } @@ -394,7 +412,7 @@ void V3HierBlockPlan::writeCommandArgsFiles(bool forCMake) const { *of << it->second->hierWrapper(true) << "\n"; } } - V3HierWriteCommonInputs(of.get(), forCMake); + V3HierWriteCommonInputs(nullptr, of.get(), forCMake); if (!forCMake) { const V3StringSet& cppFiles = v3Global.opt.cppFiles(); for (const string& i : cppFiles) *of << i << "\n"; @@ -411,6 +429,9 @@ void V3HierBlockPlan::writeCommandArgsFiles(bool forCMake) const { *of << "--protect-lib " << v3Global.opt.protectLib() << "\n"; *of << "--protect-key " << v3Global.opt.protectKeyDefaulted() << "\n"; } + if (v3Global.opt.threads() > 0) { + *of << "--threads " << cvtToStr(v3Global.opt.threads()) << "\n"; + } *of << (v3Global.opt.systemC() ? "--sc" : "--cc") << "\n"; *of << v3Global.opt.allArgsStringForHierBlock(true) << "\n"; } diff --git a/src/V3HierBlock.h b/src/V3HierBlock.h index 6bc0ce285..8a04dd3fb 100644 --- a/src/V3HierBlock.h +++ b/src/V3HierBlock.h @@ -85,6 +85,8 @@ public: string hierMk(bool withDir) const; string hierLib(bool withDir) const; string hierGenerated(bool withDir) const; + // Returns the original HDL file if it is not included in v3Global.opt.vFiles(). + string vFileIfNecessary() const; // Write command line argumuents to .f file for this hierarchical block void writeCommandArgsFile(bool forCMake) const; string commandArgsFileName(bool forCMake) const; diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index 9a0c9af82..b42e14d4c 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -313,9 +313,9 @@ private: UASSERT_OBJ(exprconstp || exprvarrefp, nodep, "Unknown interconnect type; pinReconnectSimple should have cleared up"); if (exprconstp) { - m_modp->addStmtp(new AstAssignW(nodep->fileline(), - new AstVarRef(nodep->fileline(), nodep, true), - exprconstp->cloneTree(true))); + m_modp->addStmtp(new AstAssignW( + nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, VAccess::WRITE), + exprconstp->cloneTree(true))); } else if (nodep->user3()) { // Public variable at the lower module end - we need to make sure we propagate // the logic changes up and down; if we aliased, we might @@ -323,20 +323,22 @@ private: UINFO(9, "public pin assign: " << exprvarrefp << endl); UASSERT_OBJ(!nodep->isNonOutput(), nodep, "Outputs only - inputs use AssignAlias"); m_modp->addStmtp(new AstAssignW( - nodep->fileline(), new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true), - new AstVarRef(nodep->fileline(), nodep, false))); + nodep->fileline(), + new AstVarRef(nodep->fileline(), exprvarrefp->varp(), VAccess::WRITE), + new AstVarRef(nodep->fileline(), nodep, VAccess::READ))); } else if (nodep->isSigPublic() && VN_IS(nodep->dtypep(), UnpackArrayDType)) { // Public variable at this end and it is an unpacked array. We need to assign // instead of aliased, because otherwise it will pass V3Slice and invalid // code will be emitted. UINFO(9, "assign to public and unpacked: " << nodep << endl); m_modp->addStmtp(new AstAssignW( - nodep->fileline(), new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true), - new AstVarRef(nodep->fileline(), nodep, false))); + nodep->fileline(), + new AstVarRef(nodep->fileline(), exprvarrefp->varp(), VAccess::WRITE), + new AstVarRef(nodep->fileline(), nodep, VAccess::READ))); } else if (nodep->isIfaceRef()) { m_modp->addStmtp(new AstAssignVarScope( - nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, true), - new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false))); + nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, VAccess::WRITE), + new AstVarRef(nodep->fileline(), exprvarrefp->varp(), VAccess::READ))); AstNode* nodebp = exprvarrefp->varp(); nodep->fileline()->modifyStateInherit(nodebp->fileline()); nodebp->fileline()->modifyStateInherit(nodep->fileline()); @@ -344,8 +346,8 @@ private: // Do to inlining child's variable now within the same // module, so a AstVarRef not AstVarXRef below m_modp->addStmtp(new AstAssignAlias( - nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, true), - new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false))); + nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, VAccess::WRITE), + new AstVarRef(nodep->fileline(), exprvarrefp->varp(), VAccess::READ))); AstNode* nodebp = exprvarrefp->varp(); nodep->fileline()->modifyStateInherit(nodebp->fileline()); nodebp->fileline()->modifyStateInherit(nodep->fileline()); diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index 7919c547f..6c4c1922f 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -76,17 +76,17 @@ private: if (nodep->modVarp()->isInoutish()) { nodep->v3fatalSrc("Unsupported: Verilator is a 2-state simulator"); } else if (nodep->modVarp()->isWritable()) { - AstNode* rhsp - = new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), false); + AstNode* rhsp = new AstVarXRef(exprp->fileline(), nodep->modVarp(), + m_cellp->name(), VAccess::READ); AstAssignW* assp = new AstAssignW(exprp->fileline(), exprp, rhsp); m_cellp->addNextHere(assp); } else if (nodep->modVarp()->isNonOutput()) { // Don't bother moving constants now, // we'll be pushing the const down to the cell soon enough. - AstNode* assp = new AstAssignW( - exprp->fileline(), - new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), true), - exprp); + AstNode* assp = new AstAssignW(exprp->fileline(), + new AstVarXRef(exprp->fileline(), nodep->modVarp(), + m_cellp->name(), VAccess::WRITE), + exprp); m_cellp->addNextHere(assp); if (debug() >= 9) assp->dumpTree(cout, " _new: "); } else if (nodep->modVarp()->isIfaceRef() @@ -96,8 +96,8 @@ private: IfaceRefDType))) { // Create an AstAssignVarScope for Vars to Cells so we can // link with their scope later - AstNode* lhsp - = new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), false); + AstNode* lhsp = new AstVarXRef(exprp->fileline(), nodep->modVarp(), + m_cellp->name(), VAccess::READ); const AstVarRef* refp = VN_CAST(exprp, VarRef); const AstVarXRef* xrefp = VN_CAST(exprp, VarXRef); UASSERT_OBJ(refp || xrefp, exprp, @@ -379,8 +379,9 @@ private: } string index = AstNode::encodeNumber(constp->toSInt()); AstVarRef* varrefp = VN_CAST(arrselp->lhsp(), VarRef); - AstVarXRef* newp = new AstVarXRef( - nodep->fileline(), varrefp->name() + "__BRA__" + index + "__KET__", "", true); + AstVarXRef* newp = new AstVarXRef(nodep->fileline(), + varrefp->name() + "__BRA__" + index + "__KET__", + "", VAccess::WRITE); newp->dtypep(nodep->modVarp()->dtypep()); newp->packagep(varrefp->packagep()); arrselp->addNextHere(newp); @@ -438,7 +439,8 @@ private: } if (!varrefp) { newp->exprp()->v3error("Unexpected connection to arrayed port"); } string newname = varrefp->name() + "__BRA__" + cvtToStr(i + offset) + "__KET__"; - AstVarXRef* newVarXRefp = new AstVarXRef(nodep->fileline(), newname, "", true); + AstVarXRef* newVarXRefp + = new AstVarXRef(nodep->fileline(), newname, "", VAccess::WRITE); newVarXRefp->varp(newp->modVarp()); newp->exprp()->unlinkFrBack()->deleteTree(); newp->exprp(newVarXRefp); @@ -553,18 +555,19 @@ public: " direct one-to-one connection (without any expression)"); } else if (pinVarp->isWritable()) { // See also V3Inst - AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, false); + AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, VAccess::READ); UINFO(5, "pinRecon width " << pinVarp->width() << " >? " << rhsp->width() << " >? " << pinexprp->width() << endl); rhsp = extendOrSel(pinp->fileline(), rhsp, pinVarp); - pinp->exprp(new AstVarRef(newvarp->fileline(), newvarp, true)); + pinp->exprp(new AstVarRef(newvarp->fileline(), newvarp, VAccess::WRITE)); AstNode* rhsSelp = extendOrSel(pinp->fileline(), rhsp, pinexprp); assignp = new AstAssignW(pinp->fileline(), pinexprp, rhsSelp); } else { // V3 width should have range/extended to make the widths correct assignp = new AstAssignW(pinp->fileline(), - new AstVarRef(pinp->fileline(), newvarp, true), pinexprp); - pinp->exprp(new AstVarRef(pinexprp->fileline(), newvarp, false)); + new AstVarRef(pinp->fileline(), newvarp, VAccess::WRITE), + pinexprp); + pinp->exprp(new AstVarRef(pinexprp->fileline(), newvarp, VAccess::READ)); } if (assignp) cellp->addNextHere(assignp); // if (debug()) { pinp->dumpTree(cout, "- out:"); } diff --git a/src/V3LanguageWords.h b/src/V3LanguageWords.h index a11a6a222..907095605 100644 --- a/src/V3LanguageWords.h +++ b/src/V3LanguageWords.h @@ -48,7 +48,7 @@ public: private: static Singleton& s() { - static Singleton s_s; + static Singleton s_s; // LCOV_EXCL_BR_LINE return s_s; } }; diff --git a/src/V3Life.cpp b/src/V3Life.cpp index dff42a07e..aa8ca95ec 100644 --- a/src/V3Life.cpp +++ b/src/V3Life.cpp @@ -300,7 +300,7 @@ private: // AstVarScope* vscp = nodep->varScopep(); UASSERT_OBJ(vscp, nodep, "Scope not assigned"); - if (nodep->lvalue()) { + if (nodep->access().isWrite()) { m_sideEffect = true; // $sscanf etc may have RHS vars that are lvalues m_lifep->complexAssign(vscp); } else { diff --git a/src/V3LifePost.cpp b/src/V3LifePost.cpp index 65ee17693..c3ba15bbd 100644 --- a/src/V3LifePost.cpp +++ b/src/V3LifePost.cpp @@ -58,7 +58,7 @@ private: UASSERT_OBJ(vscp, nodep, "Scope not assigned"); if (AstVarScope* newvscp = reinterpret_cast(vscp->user4p())) { UINFO(9, " Replace " << nodep << " to " << newvscp << endl); - AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->lvalue()); + AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->access()); nodep->replaceWith(newrefp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } @@ -284,7 +284,7 @@ private: UASSERT_OBJ(vscp, nodep, "Scope not assigned"); LifeLocation loc(m_execMTaskp, ++m_sequence); - if (nodep->lvalue()) { + if (nodep->access().isWrite()) { m_writes[vscp].insert(loc); } else { m_reads[vscp].insert(loc); diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 1ec6fc337..0bf9e5af6 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1128,6 +1128,7 @@ class LinkDotFindVisitor : public AstNVisitor { AstVar* newp = new AstVar(nodep->fileline(), AstVarType(AstVarType::GPARAM), nodep->name(), nodep); + newp->combineType(nodep); string svalue = v3Global.opt.parameter(nodep->name()); if (AstNode* valuep = AstConst::parseParamLiteral(nodep->fileline(), svalue)) { @@ -1960,8 +1961,18 @@ private: m_ds.m_dotp = nodep; // Always, not just at start m_ds.m_dotPos = DP_SCOPE; - // m_ds.m_dotText communicates the cell prefix between stages - if (VN_IS(nodep->lhsp(), ClassOrPackageRef)) { + if (VN_IS(nodep->lhsp(), ParseRef) && nodep->lhsp()->name() == "this") { + VSymEnt* classSymp = m_ds.m_dotSymp; + do { + classSymp = classSymp->fallbackp(); + } while (classSymp && !VN_IS(classSymp->nodep(), Class)); + m_ds.m_dotSymp = classSymp; + if (!classSymp) { + nodep->v3error("'this' used outside class"); + m_ds.m_dotErr = true; + } + } else if (VN_IS(nodep->lhsp(), ClassOrPackageRef)) { + // m_ds.m_dotText communicates the cell prefix between stages // 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; @@ -2018,21 +2029,14 @@ private: // Generally resolved during Primay, but might be at param time under AstUnlinkedRef UASSERT_OBJ(m_statep->forPrimary() || m_statep->forPrearray(), nodep, "ParseRefs should no longer exist"); - if (nodep->name() == "this") { - nodep->v3warn(E_UNSUPPORTED, "Unsupported: this"); - } else if (nodep->name() == "super") { - nodep->v3warn(E_UNSUPPORTED, "Unsupported: super"); - } + if (nodep->name() == "super") { nodep->v3warn(E_UNSUPPORTED, "Unsupported: super"); } DotStates lastStates = m_ds; bool start = (m_ds.m_dotPos == DP_NONE); // Save, as m_dotp will be changed if (start) { m_ds.init(m_curSymp); // Note m_ds.m_dot remains nullptr; this is a reference not under a dot } - if (nodep->name() == "this") { - nodep->v3warn(E_UNSUPPORTED, "Unsupported: this"); - m_ds.m_dotErr = true; - } else if (nodep->name() == "super") { + if (nodep->name() == "super") { nodep->v3warn(E_UNSUPPORTED, "Unsupported: super"); m_ds.m_dotErr = true; } @@ -2132,7 +2136,7 @@ private: m_ds.m_dotPos = DP_SCOPE; UINFO(9, " cell -> iface varref " << foundp->nodep() << endl); AstNode* newp - = new AstVarRef(ifaceRefVarp->fileline(), ifaceRefVarp, false); + = new AstVarRef(ifaceRefVarp->fileline(), ifaceRefVarp, VAccess::READ); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } else if (VN_IS(cellp->modp(), NotFoundModule)) { @@ -2150,7 +2154,7 @@ private: m_ds.m_dotSymp = m_statep->getNodeSym(ifacerefp->ifaceViaCellp()); m_ds.m_dotPos = DP_SCOPE; ok = true; - AstNode* newp = new AstVarRef(nodep->fileline(), varp, false); + AstNode* newp = new AstVarRef(nodep->fileline(), varp, VAccess::READ); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } else if (allowVar) { @@ -2158,7 +2162,7 @@ private: if (m_ds.m_dotText != "") { AstVarXRef* refp = new AstVarXRef(nodep->fileline(), nodep->name(), m_ds.m_dotText, - false); // lvalue'ness computed later + VAccess::READ); // lvalue'ness computed later refp->varp(varp); if (varp->attrSplitVar()) { refp->v3warn( @@ -2188,8 +2192,9 @@ private: newp = refp; } } else { - AstVarRef* refp = new AstVarRef(nodep->fileline(), varp, - false); // lvalue'ness computed later + AstVarRef* refp + = new AstVarRef(nodep->fileline(), varp, + VAccess::READ); // lvalue'ness computed later refp->packagep(foundp->packagep()); newp = refp; } @@ -2224,7 +2229,7 @@ private: m_ds.m_dotPos = DP_SCOPE; ok = true; AstVar* varp = makeIfaceModportVar(nodep->fileline(), cellp, ifacep, modportp); - AstVarRef* refp = new AstVarRef(varp->fileline(), varp, false); + AstVarRef* refp = new AstVarRef(varp->fileline(), varp, VAccess::READ); nodep->replaceWith(refp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } @@ -2274,7 +2279,8 @@ private: if (checkImplicit) { // Create if implicit, and also if error (so only complain once) // Else if a scope is allowed, making a signal won't help error cascade - AstVarRef* newp = new AstVarRef(nodep->fileline(), nodep->name(), false); + AstVarRef* newp + = new AstVarRef(nodep->fileline(), nodep->name(), VAccess::READ); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); createImplicitVar(m_curSymp, newp, m_modp, m_modSymp, err); @@ -2293,7 +2299,7 @@ private: UINFO(9, " linkVarRef se" << cvtToHex(m_curSymp) << " n=" << nodep << endl); UASSERT_OBJ(m_curSymp, nodep, "nullptr lookup symbol table"); VSymEnt* foundp = m_curSymp->findIdFallback(nodep->name()); - if (AstVar* varp = foundp ? foundToVarp(foundp, nodep, nodep->lvalue()) : nullptr) { + if (AstVar* varp = foundp ? foundToVarp(foundp, nodep, nodep->access()) : nullptr) { nodep->varp(varp); // Generally set by parse, but might be an import nodep->packagep(foundp->packagep()); @@ -2333,7 +2339,7 @@ private: okSymp); // Maybe nullptr if (!m_statep->forScopeCreation()) { VSymEnt* foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot); - AstVar* varp = foundp ? foundToVarp(foundp, nodep, nodep->lvalue()) : nullptr; + AstVar* varp = foundp ? foundToVarp(foundp, nodep, nodep->access()) : nullptr; nodep->varp(varp); UINFO(7, " Resolved " << nodep << endl); // Also prints varp if (!nodep->varp()) { @@ -2349,7 +2355,7 @@ private: if (!m_statep->forPrearray() && !m_statep->forScopeCreation()) { if (VN_IS(nodep->dtypep(), IfaceRefDType)) { AstVarRef* newrefp - = new AstVarRef(nodep->fileline(), nodep->varp(), nodep->lvalue()); + = new AstVarRef(nodep->fileline(), nodep->varp(), nodep->access()); nodep->replaceWith(newrefp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } @@ -2373,7 +2379,7 @@ private: nodep->varp(vscp->varp()); nodep->varScopep(vscp); UINFO(7, " Resolved " << nodep << endl); // Also prints taskp - AstVarRef* newvscp = new AstVarRef(nodep->fileline(), vscp, nodep->lvalue()); + AstVarRef* newvscp = new AstVarRef(nodep->fileline(), vscp, nodep->access()); nodep->replaceWith(newvscp); VL_DO_DANGLING(nodep->deleteTree(), nodep); UINFO(9, " new " << newvscp << endl); // Also prints taskp diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp index fdcdbebed..c7cf6298a 100644 --- a/src/V3LinkInc.cpp +++ b/src/V3LinkInc.cpp @@ -199,30 +199,33 @@ private: // Define what operation will we be doing AstNode* operp; if (VN_IS(nodep, PostSub) || VN_IS(nodep, PreSub)) { - operp = new AstSub(fl, new AstVarRef(fl, varrefp->varp(), false), newconstp); + operp = new AstSub(fl, new AstVarRef(fl, varrefp->varp(), VAccess::READ), newconstp); } else { - operp = new AstAdd(fl, new AstVarRef(fl, varrefp->varp(), false), newconstp); + operp = new AstAdd(fl, new AstVarRef(fl, varrefp->varp(), VAccess::READ), newconstp); } if (VN_IS(nodep, PreAdd) || VN_IS(nodep, PreSub)) { // PreAdd/PreSub operations // Immediately after declaration - increment it by one - m_insStmtp->addHereThisAsNext(new AstAssign(fl, new AstVarRef(fl, varp, true), operp)); + m_insStmtp->addHereThisAsNext( + new AstAssign(fl, new AstVarRef(fl, varp, VAccess::WRITE), operp)); // Immediately after incrementing - assign it to the original variable - m_insStmtp->addHereThisAsNext(new AstAssign( - fl, new AstVarRef(fl, varrefp->varp(), true), new AstVarRef(fl, varp, false))); + m_insStmtp->addHereThisAsNext( + new AstAssign(fl, new AstVarRef(fl, varrefp->varp(), VAccess::WRITE), + new AstVarRef(fl, varp, VAccess::READ))); } else { // PostAdd/PostSub operations // assign the original variable to the temporary one - m_insStmtp->addHereThisAsNext(new AstAssign( - fl, new AstVarRef(fl, varp, true), new AstVarRef(fl, varrefp->varp(), false))); + m_insStmtp->addHereThisAsNext( + new AstAssign(fl, new AstVarRef(fl, varp, VAccess::WRITE), + new AstVarRef(fl, varrefp->varp(), VAccess::READ))); // Increment the original variable by one m_insStmtp->addHereThisAsNext( - new AstAssign(fl, new AstVarRef(fl, varrefp->varp(), true), operp)); + new AstAssign(fl, new AstVarRef(fl, varrefp->varp(), VAccess::WRITE), operp)); } // Replace the node with the temporary - nodep->replaceWith(new AstVarRef(varrefp->fileline(), varp, true)); + nodep->replaceWith(new AstVarRef(varrefp->fileline(), varp, VAccess::WRITE)); VL_DO_DANGLING(nodep->deleteTree(), nodep); } virtual void visit(AstPreAdd* nodep) override { prepost_visit(nodep); } diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp index 076ce57a4..0bccce54a 100644 --- a/src/V3LinkJump.cpp +++ b/src/V3LinkJump.cpp @@ -153,15 +153,15 @@ private: nodep->findSigned32DType()); varp->usedLoopIdx(true); m_modp->addStmtp(varp); - AstNode* initsp = new AstAssign(nodep->fileline(), - new AstVarRef(nodep->fileline(), varp, true), countp); + AstNode* initsp = new AstAssign( + nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::WRITE), countp); AstNode* decp = new AstAssign( - nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true), - new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false), + nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::WRITE), + new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::READ), new AstConst(nodep->fileline(), 1))); AstNode* zerosp = new AstConst(nodep->fileline(), AstConst::Signed32(), 0); - AstNode* condp - = new AstGtS(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false), zerosp); + AstNode* condp = new AstGtS(nodep->fileline(), + new AstVarRef(nodep->fileline(), varp, VAccess::READ), zerosp); AstNode* bodysp = nodep->bodysp(); if (bodysp) bodysp->unlinkFrBackWithNext(); AstNode* newp = new AstWhile(nodep->fileline(), condp, bodysp, decp); @@ -213,7 +213,7 @@ private: // Set output variable to return value nodep->addPrev(new AstAssign( nodep->fileline(), - new AstVarRef(nodep->fileline(), VN_CAST(funcp->fvarp(), Var), true), + new AstVarRef(nodep->fileline(), VN_CAST(funcp->fvarp(), Var), VAccess::WRITE), nodep->lhsp()->unlinkFrBackWithNext())); } // Jump to the end of the function call diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp index 7db59b71c..cdfdd11e8 100644 --- a/src/V3LinkLValue.cpp +++ b/src/V3LinkLValue.cpp @@ -45,9 +45,9 @@ private: // Result handing virtual void visit(AstNodeVarRef* nodep) override { // VarRef: LValue its reference - if (m_setRefLvalue) nodep->lvalue(true); + if (m_setRefLvalue) nodep->access(VAccess::WRITE); if (nodep->varp()) { - if (nodep->lvalue() && !m_ftaskp && nodep->varp()->isReadOnly()) { + if (nodep->access().isWrite() && !m_ftaskp && nodep->varp()->isReadOnly()) { nodep->v3warn(ASSIGNIN, "Assigning to input/const variable: " << nodep->prettyNameQ()); } @@ -60,7 +60,7 @@ private: if (nodep->modVarp() && nodep->modVarp()->isWritable()) { // When the varref's were created, we didn't know the I/O state // Now that we do, and it's from a output, we know it's a lvalue - m_setRefLvalue = true; + m_setRefLvalue = VAccess::WRITE; iterateChildren(nodep); m_setRefLvalue = false; } else { @@ -70,7 +70,7 @@ private: virtual void visit(AstNodeAssign* nodep) override { VL_RESTORER(m_setRefLvalue); { - m_setRefLvalue = true; + m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->lhsp()); m_setRefLvalue = false; iterateAndNextNull(nodep->rhsp()); @@ -79,7 +79,7 @@ private: virtual void visit(AstFOpen* nodep) override { VL_RESTORER(m_setRefLvalue); { - m_setRefLvalue = true; + m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->filep()); m_setRefLvalue = false; iterateAndNextNull(nodep->filenamep()); @@ -89,7 +89,7 @@ private: virtual void visit(AstFOpenMcd* nodep) override { VL_RESTORER(m_setRefLvalue); { - m_setRefLvalue = true; + m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->filep()); m_setRefLvalue = false; iterateAndNextNull(nodep->filenamep()); @@ -98,14 +98,14 @@ private: virtual void visit(AstFClose* nodep) override { VL_RESTORER(m_setRefLvalue); { - m_setRefLvalue = true; + m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->filep()); } } virtual void visit(AstFError* nodep) override { VL_RESTORER(m_setRefLvalue); { - m_setRefLvalue = true; + m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->filep()); iterateAndNextNull(nodep->strp()); } @@ -113,21 +113,21 @@ private: virtual void visit(AstFFlush* nodep) override { VL_RESTORER(m_setRefLvalue); { - m_setRefLvalue = true; + m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->filep()); } } virtual void visit(AstFGetC* nodep) override { VL_RESTORER(m_setRefLvalue); { - m_setRefLvalue = true; + m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->filep()); } } virtual void visit(AstFGetS* nodep) override { VL_RESTORER(m_setRefLvalue); { - m_setRefLvalue = true; + m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->filep()); iterateAndNextNull(nodep->strgp()); } @@ -135,7 +135,7 @@ private: virtual void visit(AstFRead* nodep) override { VL_RESTORER(m_setRefLvalue); { - m_setRefLvalue = true; + m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->memp()); iterateAndNextNull(nodep->filep()); } @@ -143,7 +143,7 @@ private: virtual void visit(AstFScanF* nodep) override { VL_RESTORER(m_setRefLvalue); { - m_setRefLvalue = true; + m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->filep()); iterateAndNextNull(nodep->exprsp()); } @@ -151,14 +151,14 @@ private: virtual void visit(AstFUngetC* nodep) override { VL_RESTORER(m_setRefLvalue); { - m_setRefLvalue = true; + m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->filep()); } } virtual void visit(AstSScanF* nodep) override { VL_RESTORER(m_setRefLvalue); { - m_setRefLvalue = true; + m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->exprsp()); } } @@ -170,7 +170,7 @@ private: virtual void visit(AstReadMem* nodep) override { VL_RESTORER(m_setRefLvalue); { - m_setRefLvalue = true; + m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->memp()); m_setRefLvalue = false; iterateAndNextNull(nodep->filenamep()); @@ -183,14 +183,14 @@ private: { m_setRefLvalue = false; iterateAndNextNull(nodep->searchp()); - m_setRefLvalue = true; + m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->outp()); } } virtual void visit(AstSFormat* nodep) override { VL_RESTORER(m_setRefLvalue); { - m_setRefLvalue = true; + m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->lhsp()); m_setRefLvalue = false; iterateAndNextNull(nodep->fmtp()); @@ -202,7 +202,7 @@ private: m_setRefLvalue = false; iterateAndNextNull(nodep->lhsp()); iterateAndNextNull(nodep->rhsp()); - m_setRefLvalue = true; + m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->thsp()); } } @@ -260,7 +260,7 @@ private: if (const AstVar* portp = VN_CAST(stmtp, Var)) { if (portp->isIO()) { if (portp->isWritable()) { - m_setRefLvalue = true; + m_setRefLvalue = VAccess::WRITE; iterate(pinp); m_setRefLvalue = false; } else { diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index 8b6a7d7e7..e59d87ffe 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -233,9 +233,10 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) { varp->trace(false); } - AstPin* pinp - = new AstPin(oldvarp->fileline(), 0, varp->name(), - new AstVarRef(varp->fileline(), varp, oldvarp->isWritable())); + AstPin* pinp = new AstPin( + oldvarp->fileline(), 0, varp->name(), + new AstVarRef(varp->fileline(), varp, + oldvarp->isWritable() ? VAccess::WRITE : VAccess::READ)); // Skip length and width comp; we know it's a direct assignment pinp->modVarp(oldvarp); cellp->addPinsp(pinp); diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 9da01d844..09ebb7fb3 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -226,9 +226,9 @@ private: } else if (VN_IS(m_modp, Class)) { // 2. Class member init become initials (as might call functions) // later move into class constructor - nodep->addNextHere( - new AstInitial(fl, new AstAssign(fl, new AstVarRef(fl, nodep->name(), true), - nodep->valuep()->unlinkFrBack()))); + nodep->addNextHere(new AstInitial( + fl, new AstAssign(fl, new AstVarRef(fl, nodep->name(), VAccess::WRITE), + nodep->valuep()->unlinkFrBack()))); } else if (!m_ftaskp && nodep->isNonOutput()) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: Default value on module input: " << nodep->prettyNameQ()); @@ -239,11 +239,13 @@ private: FileLine* newfl = new FileLine(fl); newfl->warnOff(V3ErrorCode::PROCASSWIRE, true); nodep->addNextHere(new AstInitial( - newfl, new AstAssign(newfl, new AstVarRef(newfl, nodep->name(), true), - nodep->valuep()->unlinkFrBack()))); + newfl, + new AstAssign(newfl, new AstVarRef(newfl, nodep->name(), VAccess::WRITE), + nodep->valuep()->unlinkFrBack()))); } // 4. Under blocks, it's an initial value to be under an assign else { - nodep->addNextHere(new AstAssign(fl, new AstVarRef(fl, nodep->name(), true), + nodep->addNextHere(new AstAssign(fl, + new AstVarRef(fl, nodep->name(), VAccess::WRITE), nodep->valuep()->unlinkFrBack())); } } @@ -333,7 +335,8 @@ private: // lvalue is true, because we know we have a verilator public_flat_rw // but someday we may be more general bool lvalue = m_varp->isSigUserRWPublic(); - nodep->addStmtp(new AstVarRef(nodep->fileline(), m_varp, lvalue)); + nodep->addStmtp( + new AstVarRef(nodep->fileline(), m_varp, lvalue ? VAccess::WRITE : VAccess::READ)); } } @@ -445,7 +448,8 @@ private: new AstConst(fl, dimension)); AstNode* stmtsp = varp; // Assign left-dimension into the loop var: - stmtsp->addNext(new AstAssign(fl, new AstVarRef(fl, varp->name(), true), leftp)); + stmtsp->addNext( + new AstAssign(fl, new AstVarRef(fl, varp->name(), VAccess::WRITE), leftp)); // This will turn into a constant bool for static arrays AstNode* notemptyp = new AstGt(fl, sizep, new AstConst(fl, 0)); // This will turn into a bool constant, indicating whether @@ -454,14 +458,15 @@ private: AstNode* comparep = new AstCond( fl, countupp->cloneTree(true), // Left increments up to right - new AstLte(fl, new AstVarRef(fl, varp->name(), false), rightp->cloneTree(true)), + new AstLte(fl, new AstVarRef(fl, varp->name(), VAccess::READ), + rightp->cloneTree(true)), // Left decrements down to right - new AstGte(fl, new AstVarRef(fl, varp->name(), false), rightp)); + new AstGte(fl, new AstVarRef(fl, varp->name(), VAccess::READ), rightp)); // This will reduce to comparep for static arrays AstNode* condp = new AstAnd(fl, notemptyp, comparep); AstNode* incp = new AstAssign( - fl, new AstVarRef(fl, varp->name(), true), - new AstAdd(fl, new AstVarRef(fl, varp->name(), false), + fl, new AstVarRef(fl, varp->name(), VAccess::WRITE), + new AstAdd(fl, new AstVarRef(fl, varp->name(), VAccess::READ), new AstCond(fl, countupp, new AstConst(fl, 1), new AstConst(fl, -1)))); stmtsp->addNext(new AstWhile(fl, condp, newp, incp)); newp = new AstBegin(nodep->fileline(), "", stmtsp, false, true); diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index d81e1a6b4..bf158a20a 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -183,9 +183,10 @@ private: } addwherep->addNext(newvarp); - sensp->replaceWith(new AstVarRef(sensp->fileline(), newvarp, false)); + sensp->replaceWith(new AstVarRef(sensp->fileline(), newvarp, VAccess::READ)); AstAssignW* assignp = new AstAssignW( - sensp->fileline(), new AstVarRef(sensp->fileline(), newvarp, true), sensp); + sensp->fileline(), new AstVarRef(sensp->fileline(), newvarp, VAccess::WRITE), + sensp); addwherep->addNext(assignp); } } else { // Old V1995 sensitivity list; we'll probably mostly ignore @@ -490,7 +491,8 @@ private: varoutp = varp; // Tie off m_modp->addStmtp(new AstAssignW( - varp->fileline(), new AstVarRef(varp->fileline(), varp, true), + varp->fileline(), + new AstVarRef(varp->fileline(), varp, VAccess::WRITE), new AstConst(varp->fileline(), AstConst::LogicFalse()))); } else { varp->v3error("Only inputs and outputs are allowed in udp modules"); diff --git a/src/V3Localize.cpp b/src/V3Localize.cpp index c9ee6b9f4..3192b074d 100644 --- a/src/V3Localize.cpp +++ b/src/V3Localize.cpp @@ -166,7 +166,7 @@ private: for (; nodep; nodep = nodep->nextp()) { if (VN_IS(nodep, NodeAssign)) { if (AstVarRef* varrefp = VN_CAST(VN_CAST(nodep, NodeAssign)->lhsp(), VarRef)) { - UASSERT_OBJ(varrefp->lvalue(), varrefp, "LHS assignment not lvalue"); + UASSERT_OBJ(varrefp->access().isWrite(), varrefp, "LHS assignment not lvalue"); if (!varrefp->varp()->user4p()) { UINFO(4, " FuncAsn " << varrefp << endl); varrefp->varp()->user4p(varrefp); diff --git a/src/V3MergeCond.cpp b/src/V3MergeCond.cpp index 114898b23..acdfe95b7 100644 --- a/src/V3MergeCond.cpp +++ b/src/V3MergeCond.cpp @@ -80,7 +80,7 @@ private: virtual void visit(AstVarRef* nodep) override { if (!m_mergeable) return; // Clear if it's an LValue referencing a marked variable - if (nodep->lvalue() && nodep->varp()->user1()) { + if (nodep->access().isWrite() && nodep->varp()->user1()) { clearMergeable(nodep, "might modify condition"); } } diff --git a/src/V3Number.cpp b/src/V3Number.cpp index 2b4e54494..cf6ef219b 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -1267,7 +1267,7 @@ V3Number& V3Number::opXor(const V3Number& lhs, const V3Number& rhs) { setBit(bit, 1); } else if (lhs.bitIs0(bit) && rhs.bitIs1(bit)) { setBit(bit, 1); - } else if (lhs.bitIsXZ(bit) && rhs.bitIsXZ(bit)) { + } else if (lhs.bitIsXZ(bit) || rhs.bitIsXZ(bit)) { setBit(bit, 'x'); } // else zero diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 17a63b000..9caff20c6 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -431,15 +431,6 @@ string V3Options::allArgsStringForHierBlock(bool forTop) const { //###################################################################### // File searching -bool V3Options::fileStatDir(const string& filename) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) - struct stat sstat; // Stat information - int err = stat(filename.c_str(), &sstat); - if (err != 0) return false; - if (!S_ISDIR(sstat.st_mode)) return false; - return true; -} - bool V3Options::fileStatNormal(const string& filename) { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) struct stat sstat; // Stat information @@ -513,7 +504,7 @@ string V3Options::filePathCheckOneDir(const string& modname, const string& dirna int V3Options::stripOptionsForChildRun(const string& opt, bool forTop) const { if (opt == "Mdir" || opt == "clk" || opt == "f" || opt == "j" || opt == "l2-name" || opt == "mod-prefix" || opt == "prefix" || opt == "protect-lib" || opt == "protect-key" - || opt == "top-module" || opt == "v") { + || opt == "threads" || opt == "top-module" || opt == "v") { return 2; } if (opt == "build" || (!forTop && (opt == "cc" || opt == "exe" || opt == "sc")) @@ -651,9 +642,9 @@ string V3Options::getenvSYSTEMC_ARCH() { struct utsname uts; uname(&uts); string sysname = VString::downcase(uts.sysname); // aka 'uname -s' - if (VString::wildmatch(sysname.c_str(), "*solaris*")) { + if (VL_UNCOVERABLE(VString::wildmatch(sysname.c_str(), "*solaris*"))) { var = "gccsparcOS5"; - } else if (VString::wildmatch(sysname.c_str(), "*cygwin*")) { + } else if (VL_UNCOVERABLE(VString::wildmatch(sysname.c_str(), "*cygwin*"))) { var = "cygwin"; } else { var = "linux"; @@ -1013,6 +1004,8 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char m_debugCheck = flag; } else if (onoff(sw, "-debug-collision", flag /*ref*/)) { // Undocumented m_debugCollision = flag; + } else if (onoff(sw, "-debug-emitv", flag /*ref*/)) { // Undocumented + m_debugEmitV = flag; } else if (onoff(sw, "-debug-exit-parse", flag /*ref*/)) { // Undocumented m_debugExitParse = flag; } else if (onoff(sw, "-debug-exit-uvm", flag /*ref*/)) { // Undocumented @@ -1594,6 +1587,7 @@ void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) { string oline; // cppcheck-suppress StlMissingComparison char lastch = ' '; + bool space_begin = true; // At beginning or leading spaces only for (string::const_iterator pos = line.begin(); pos != line.end(); lastch = *pos++) { if (inCmt) { if (*pos == '*' && *(pos + 1) == '/') { @@ -1603,11 +1597,15 @@ void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) { } else if (*pos == '/' && *(pos + 1) == '/' && (pos == line.begin() || isspace(lastch))) { // But allow /file//path break; // Ignore to EOL + } else if (*pos == '#' && space_begin) { // Only # at [spaced] begin of line + break; // Ignore to EOL } else if (*pos == '/' && *(pos + 1) == '*') { inCmt = true; + space_begin = false; // cppcheck-suppress StlMissingComparison ++pos; } else { + if (!isspace(*pos)) space_begin = false; oline += *pos; } } diff --git a/src/V3Options.h b/src/V3Options.h index d8a0f17b7..f5d21aac3 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -265,6 +265,7 @@ private: bool m_coverageUser = false; // main switch: --coverage-func bool m_debugCheck = false; // main switch: --debug-check bool m_debugCollision = false; // main switch: --debug-collision + bool m_debugEmitV = false; // main switch: --debug-emitv bool m_debugExitParse = false; // main switch: --debug-exit-parse bool m_debugExitUvm = false; // main switch: --debug-exit-uvm bool m_debugLeak = true; // main switch: --debug-leak @@ -469,6 +470,7 @@ public: bool coverageUser() const { return m_coverageUser; } bool debugCheck() const { return m_debugCheck; } bool debugCollision() const { return m_debugCollision; } + bool debugEmitV() const { return m_debugEmitV; } bool debugExitParse() const { return m_debugExitParse; } bool debugExitUvm() const { return m_debugExitUvm; } bool debugLeak() const { return m_debugLeak; } @@ -669,7 +671,6 @@ public: const string& errmsg); void filePathLookedMsg(FileLine* fl, const string& modname); V3LangCode fileLanguage(const string& filename); - static bool fileStatDir(const string& filename); static bool fileStatNormal(const string& filename); static void fileNfsFlush(const string& filename); diff --git a/src/V3Order.cpp b/src/V3Order.cpp index b641e48e5..915f88ee2 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -1026,7 +1026,8 @@ private: UASSERT_OBJ(varscp, nodep, "Var didn't get varscoped in V3Scope.cpp"); if (m_inSenTree) { // Add CLOCK dependency... This is a root of the tree we'll trace - UASSERT_OBJ(!nodep->lvalue(), nodep, "How can a sensitivity be setting a var?"); + UASSERT_OBJ(!nodep->access().isWrite(), nodep, + "How can a sensitivity be setting a var?"); OrderVarVertex* varVxp = newVarUserVertex(varscp, WV_STD); varVxp->isClock(true); new OrderEdge(&m_graph, varVxp, m_activeSenVxp, WEIGHT_MEDIUM); @@ -1036,7 +1037,7 @@ private: // We don't want to add extra edges if the logic block has many usages of same var bool gen = false; bool con = false; - if (nodep->lvalue()) { + if (nodep->access().isWrite()) { gen = !(varscp->user4() & VU_GEN); } else { con = !(varscp->user4() & VU_CON); diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 3e07a3de2..bc21b11f8 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -535,7 +535,7 @@ private: nodep->addNext(new AstInitial( nodep->fileline(), new AstAssign(nodep->fileline(), - new AstVarRef(nodep->fileline(), nodep, true), + new AstVarRef(nodep->fileline(), nodep, VAccess::WRITE), nodep->valuep()->cloneTree(true)))); if (m_ftaskp) { // We put the initial in wrong place under a function. We diff --git a/src/V3ParseGrammar.cpp b/src/V3ParseGrammar.cpp index ae478171d..329631792 100644 --- a/src/V3ParseGrammar.cpp +++ b/src/V3ParseGrammar.cpp @@ -83,7 +83,7 @@ AstNode* V3ParseGrammar::argWrapList(AstNode* nodep) { AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, const string& name, int value) { return new AstAssignW( - fileline, new AstVarRef(fileline, name, true), + fileline, new AstVarRef(fileline, name, VAccess::WRITE), new AstConst(fileline, AstConst::StringToParse(), (value ? "'1" : "'0"))); } diff --git a/src/V3PreLex.l b/src/V3PreLex.l index d706fc07c..aa331c629 100644 --- a/src/V3PreLex.l +++ b/src/V3PreLex.l @@ -595,11 +595,11 @@ string V3PreLex::cleanDbgStrg(const string& in) { } void V3PreLex::unused() { - if (0) { + if (VL_UNCOVERABLE(false)) { // LCOV_EXCL_START // Prevent unused warnings yy_top_state(); yyerror((char*)""); - } + } // LCOV_EXCL_STOP } /*################################################################### diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index ec9047731..022704efe 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -26,6 +26,7 @@ #include "V3PreShell.h" #include "V3String.h" +#include #include #include #include @@ -540,10 +541,7 @@ void V3PreProcImp::unputString(const string& strg) { } void V3PreProcImp::unputDefrefString(const string& strg) { - int multiline = 0; - for (size_t i = 0; i < strg.length(); i++) { - if (strg[i] == '\n') multiline++; - } + int multiline = std::count(strg.begin(), strg.end(), '\n'); unputString(strg); // A define that inserts multiple newlines are really attributed to one source line, // so temporarily don't increment lineno. @@ -1320,7 +1318,7 @@ int V3PreProcImp::getStateToken() { // multiline "..." without \ escapes. // The spec is silent about this either way; simulators vary string::size_type pos; - while ((pos = out.find('\n')) != string::npos) out.replace(pos, 1, " "); + std::replace(out.begin(), out.end(), '\n', ' '); unputString(string("\"") + out + "\""); statePop(); goto next_tok; @@ -1403,7 +1401,10 @@ int V3PreProcImp::getStateToken() { if (m_off) { goto next_tok; } else { - return VP_TEXT; + // We want final text of `name, but that would cause + // recursion, so use a special character to get it through + unputDefrefString(string("`\032") + name); + goto next_tok; } } else { string params = defParams(name); diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 154e517ee..8402cdb60 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -58,7 +58,7 @@ private: } virtual void visit(AstVarRef* nodep) override { // it's LHS var is used so need a deep temporary - if (nodep->lvalue()) { + if (nodep->access().isWrite()) { nodep->varp()->user4(true); } else { if (nodep->varp()->user4()) { @@ -173,11 +173,11 @@ private: AstVar* varp = getBlockTemp(nodep); if (noSubst) varp->noSubst(true); // Do not remove varrefs to this in V3Const // Replace node tree with reference to var - AstVarRef* newp = new AstVarRef(nodep->fileline(), varp, false); + AstVarRef* newp = new AstVarRef(nodep->fileline(), varp, VAccess::READ); linker.relink(newp); // Put assignment before the referencing statement - AstAssign* assp = new AstAssign(nodep->fileline(), - new AstVarRef(nodep->fileline(), varp, true), nodep); + AstAssign* assp = new AstAssign( + nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::WRITE), nodep); insertBeforeStmt(assp); if (debug() > 8) assp->dumpTree(cout, "deepou:"); nodep->user1(true); // Don't add another assignment diff --git a/src/V3ProtectLib.cpp b/src/V3ProtectLib.cpp index b889bd48a..88bf6ba8f 100644 --- a/src/V3ProtectLib.cpp +++ b/src/V3ProtectLib.cpp @@ -82,7 +82,7 @@ private: FileLine* fl = nodep->fileline(); // Need to know the existence of clk before createSvFile() m_hasClk = checkIfClockExists(nodep); - createSvFile(fl); + createSvFile(fl, nodep); createCppFile(fl); iterateChildren(nodep); @@ -124,7 +124,7 @@ private: addComment(txtp, fl, "Evaluates the secret module's final process"); } - void createSvFile(FileLine* fl) { + void createSvFile(FileLine* fl, AstNodeModule* modp) { // Comments AstTextBlock* txtp = new AstTextBlock(fl); addComment(txtp, fl, "Wrapper module for DPI protected library"); @@ -135,18 +135,28 @@ private: "See instructions in your simulator for how" " to use DPI libraries\n"); + bool timescaleShown = false; + if (v3Global.opt.hierChild() && !modp->timeunit().isNone()) { + // Emit timescale for hierarhical verilation + timescaleShown = true; + txtp->addText(fl, string("`timescale ") + modp->timeunit().ascii() + "/" + + v3Global.rootp()->timeprecision().ascii() + "\n\n"); + } // Module declaration m_modPortsp = new AstTextBlock(fl, "module " + m_libName + " (\n", false, true); txtp->addNodep(m_modPortsp); txtp->addText(fl, ");\n\n"); // Timescale - addComment(txtp, fl, - "Precision of submodule" - " (commented out to avoid requiring timescale on all modules)"); - addComment(txtp, fl, string("timeunit ") + v3Global.rootp()->timeunit().ascii() + ";"); - addComment(txtp, fl, - string("timeprecision ") + v3Global.rootp()->timeprecision().ascii() + ";\n"); + if (!timescaleShown) { + addComment(txtp, fl, + "Precision of submodule" + " (commented out to avoid requiring timescale on all modules)"); + addComment(txtp, fl, string("timeunit ") + v3Global.rootp()->timeunit().ascii() + ";"); + addComment(txtp, fl, + string("timeprecision ") + v3Global.rootp()->timeprecision().ascii() + + ";\n"); + } // DPI declarations hashComment(txtp, fl); diff --git a/src/V3Reloop.cpp b/src/V3Reloop.cpp index 7122b906c..f23423141 100644 --- a/src/V3Reloop.cpp +++ b/src/V3Reloop.cpp @@ -99,13 +99,13 @@ private: FileLine* fl = bodyp->fileline(); AstVar* itp = findCreateVarTemp(fl, m_mgCfuncp); - AstNode* initp = new AstAssign(fl, new AstVarRef(fl, itp, true), + AstNode* initp = new AstAssign(fl, new AstVarRef(fl, itp, VAccess::WRITE), new AstConst(fl, m_mgIndexLo)); - AstNode* condp - = new AstLte(fl, new AstVarRef(fl, itp, false), new AstConst(fl, m_mgIndexHi)); + AstNode* condp = new AstLte(fl, new AstVarRef(fl, itp, VAccess::READ), + new AstConst(fl, m_mgIndexHi)); AstNode* incp = new AstAssign( - fl, new AstVarRef(fl, itp, true), - new AstAdd(fl, new AstConst(fl, 1), new AstVarRef(fl, itp, false))); + fl, new AstVarRef(fl, itp, VAccess::WRITE), + new AstAdd(fl, new AstConst(fl, 1), new AstVarRef(fl, itp, VAccess::READ))); AstWhile* whilep = new AstWhile(fl, condp, nullptr, incp); initp->addNext(whilep); bodyp->replaceWith(initp); @@ -113,11 +113,11 @@ private: // Replace constant index with new loop index AstNode* lbitp = m_mgSelLp->bitp(); - lbitp->replaceWith(new AstVarRef(fl, itp, false)); + lbitp->replaceWith(new AstVarRef(fl, itp, VAccess::READ)); VL_DO_DANGLING(lbitp->deleteTree(), lbitp); if (m_mgSelRp) { // else constant and no replace AstNode* rbitp = m_mgSelRp->bitp(); - rbitp->replaceWith(new AstVarRef(fl, itp, false)); + rbitp->replaceWith(new AstVarRef(fl, itp, VAccess::READ)); VL_DO_DANGLING(rbitp->deleteTree(), lbitp); } if (debug() >= 9) initp->dumpTree(cout, "-new: "); diff --git a/src/V3Simulate.h b/src/V3Simulate.h index a2f1eb6f5..5d6b4ccf5 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -401,7 +401,7 @@ private: && !VN_IS(nodep->varp()->dtypeSkipRefp(), UnpackArrayDType) && !VN_IS(nodep->varp()->dtypeSkipRefp(), StructDType)) clearOptimizable(nodep, "Array references/not basic"); - if (nodep->lvalue()) { + if (nodep->access().isWrite()) { if (m_inDlyAssign) { if (!(vscp->user1() & VU_LVDLY)) { vscp->user1(vscp->user1() | VU_LVDLY); @@ -433,7 +433,7 @@ private: } } if (!m_checkOnly && optimizable()) { // simulating - UASSERT_OBJ(!nodep->lvalue(), nodep, + UASSERT_OBJ(!nodep->access().isWrite(), nodep, "LHS varref should be handled in AstAssign visitor."); { // Return simulation value - copy by reference instead of value for speed diff --git a/src/V3Split.cpp b/src/V3Split.cpp index 69773c2b5..5fc44131a 100644 --- a/src/V3Split.cpp +++ b/src/V3Split.cpp @@ -383,7 +383,7 @@ protected: SplitVarStdVertex* vstdp = reinterpret_cast(vscp->user1p()); // SPEEDUP: We add duplicate edges, that should be fixed - if (m_inDly && nodep->lvalue()) { + if (m_inDly && nodep->access().isWrite()) { UINFO(4, " VARREFDLY: " << nodep << endl); // Delayed variable is different from non-delayed variable if (!vscp->user2p()) { @@ -398,7 +398,7 @@ protected: new SplitLVEdge(&m_graph, vpostp, vxp); } } else { // Nondelayed assignment - if (nodep->lvalue()) { + if (nodep->access().isWrite()) { // Non-delay; need to maintain existing ordering // with all consumers of the signal UINFO(4, " VARREFLV: " << nodep << endl); diff --git a/src/V3SplitAs.cpp b/src/V3SplitAs.cpp index 793638187..eb1f1d2d1 100644 --- a/src/V3SplitAs.cpp +++ b/src/V3SplitAs.cpp @@ -49,7 +49,7 @@ private: // METHODS virtual void visit(AstVarRef* nodep) override { - if (nodep->lvalue() && !m_splitVscp && nodep->varp()->attrIsolateAssign()) { + if (nodep->access().isWrite() && !m_splitVscp && nodep->varp()->attrIsolateAssign()) { m_splitVscp = nodep->varScopep(); } } @@ -76,7 +76,7 @@ private: // METHODS virtual void visit(AstVarRef* nodep) override { - if (nodep->lvalue()) { + if (nodep->access().isWrite()) { if (nodep->varScopep() == m_splitVscp) { UINFO(6, " CL VAR " << nodep << endl); m_matches = true; @@ -183,10 +183,7 @@ private: public: // CONSTRUCTORS - explicit SplitAsVisitor(AstNetlist* nodep) { - AstNode::user1ClearTree(); // user1p() used on entire tree - iterate(nodep); - } + explicit SplitAsVisitor(AstNetlist* nodep) { iterate(nodep); } virtual ~SplitAsVisitor() override { V3Stats::addStat("Optimizations, isolate_assignments blocks", m_statSplits); } diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index b7f308d47..0612174e4 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -239,7 +239,7 @@ class UnpackRef { int m_index; // for ArraySel int m_msb; // for SliceSel int m_lsb; // for SliceSel - bool m_lvalue; + VAccess m_access; bool m_ftask; // true if the reference is in function/task. false if in module. public: UnpackRef(AstNode* stmtp, AstVarRef* nodep, bool ftask) @@ -248,23 +248,24 @@ public: , m_index{-1} , m_msb{0} , m_lsb{1} - , m_lvalue{nodep->lvalue()} + , m_access{nodep->access()} , m_ftask{ftask} {} - UnpackRef(AstNode* stmtp, AstArraySel* nodep, int idx, bool lvalue, bool ftask) + UnpackRef(AstNode* stmtp, AstArraySel* nodep, int idx, const VAccess& access, bool ftask) : m_contextp{stmtp} , m_nodep{nodep} , m_index{idx} , m_msb{0} , m_lsb{1} - , m_lvalue{lvalue} + , m_access{access} , m_ftask{ftask} {} - UnpackRef(AstNode* stmtp, AstSliceSel* nodep, int msb, int lsb, bool lvalue, bool ftask) + UnpackRef(AstNode* stmtp, AstSliceSel* nodep, int msb, int lsb, const VAccess& access, + bool ftask) : m_contextp{stmtp} , m_nodep{nodep} , m_index{msb == lsb ? msb : -1} // Equivalent to ArraySel , m_msb{msb} , m_lsb{lsb} - , m_lvalue{lvalue} + , m_access{access} , m_ftask{ftask} {} AstNode* nodep() const { return m_nodep; } bool isSingleRef() const { @@ -275,7 +276,7 @@ public: return m_index; } AstNode* context() const { return m_contextp; } - bool lvalue() const { return m_lvalue; } + VAccess access() const { return m_access; } bool ftask() const { return m_ftask; } bool operator<(const UnpackRef& other) const { return AstNodeComparator()(m_nodep, other.m_nodep); @@ -308,11 +309,11 @@ public: } // Register the location where a variable is used. bool tryAdd(AstNode* context, AstVarRef* refp, AstArraySel* selp, int idx, bool ftask) { - return addCore(refp, UnpackRef(context, selp, idx, refp->lvalue(), ftask)); + return addCore(refp, UnpackRef(context, selp, idx, refp->access(), ftask)); } bool tryAdd(AstNode* context, AstVarRef* refp, AstSliceSel* selp, int msb, int lsb, bool ftask) { - return addCore(refp, UnpackRef(context, selp, msb, lsb, refp->lvalue(), ftask)); + return addCore(refp, UnpackRef(context, selp, msb, lsb, refp->access(), ftask)); } bool tryAdd(AstNode* context, AstVarRef* refp, bool ftask) { return addCore(refp, UnpackRef(context, refp, ftask)); @@ -434,8 +435,8 @@ class SplitUnpackedVarVisitor : public AstNVisitor, public SplitVarImpl { m_refsForPackedSplit[m_modp].add(varp); return varp; } - AstVarRef* newVarRef(FileLine* fl, AstVar* varp, bool lvalue) { - AstVarRef* refp = new AstVarRef(fl, varp, lvalue); + AstVarRef* newVarRef(FileLine* fl, AstVar* varp, const VAccess& access) { + AstVarRef* refp = new AstVarRef(fl, varp, access); UASSERT_OBJ(m_modp, refp, "Must not nullptr"); m_refsForPackedSplit[m_modp].add(refp); return refp; @@ -617,9 +618,11 @@ class SplitUnpackedVarVisitor : public AstNVisitor, public SplitVarImpl { = (context && VN_IS(context, NodeFTaskRef)) || (assignp && VN_IS(assignp, Assign)); for (int i = 0; i <= dtypep->msb() - dtypep->lsb(); ++i) { - AstNode* lhsp = newVarRef(nodep->fileline(), vars.at(start_idx + i), lvalue); - AstNode* rhsp = new AstArraySel(nodep->fileline(), - newVarRef(nodep->fileline(), varp, !lvalue), i); + AstNode* lhsp = newVarRef(nodep->fileline(), vars.at(start_idx + i), + lvalue ? VAccess::WRITE : VAccess::READ); + AstNode* rhsp = new AstArraySel( + nodep->fileline(), + newVarRef(nodep->fileline(), varp, !lvalue ? VAccess::WRITE : VAccess::READ), i); AstNode* refp = lhsp; UINFO(9, "Creating assign idx:" << i << " + " << start_idx << "\n"); if (!lvalue) std::swap(lhsp, rhsp); @@ -643,16 +646,18 @@ class SplitUnpackedVarVisitor : public AstNVisitor, public SplitVarImpl { UASSERT_OBJ(!m_contextp, m_contextp, "must be null"); setContextAndIterate(newassignp, refp); } - return newVarRef(nodep->fileline(), varp, lvalue); + return newVarRef(nodep->fileline(), varp, lvalue ? VAccess::WRITE : VAccess::READ); } void connectPort(AstVar* varp, std::vector& vars, AstNode* insertp) { UASSERT_OBJ(varp->isIO(), varp, "must be port"); insertp = insertp ? toInsertPoint(insertp) : nullptr; const bool lvalue = varp->direction().isWritable(); for (size_t i = 0; i < vars.size(); ++i) { - AstNode* nodes[] - = {new AstArraySel(varp->fileline(), newVarRef(varp->fileline(), varp, lvalue), i), - newVarRef(varp->fileline(), vars.at(i), !lvalue)}; + AstNode* nodes[] = { + new AstArraySel( + varp->fileline(), + newVarRef(varp->fileline(), varp, lvalue ? VAccess::WRITE : VAccess::READ), i), + newVarRef(varp->fileline(), vars.at(i), !lvalue ? VAccess::WRITE : VAccess::READ)}; AstNode* lhsp = nodes[lvalue ? 0 : 1]; AstNode* rhsp = nodes[lvalue ? 1 : 0]; AstNodeAssign* assignp = newAssign(varp->fileline(), lhsp, rhsp, varp); @@ -702,7 +707,7 @@ class SplitUnpackedVarVisitor : public AstNVisitor, public SplitVarImpl { AstNode* newp = nullptr; if (sit->isSingleRef()) { newp = newVarRef(sit->nodep()->fileline(), vars.at(sit->index()), - sit->lvalue()); + sit->access()); } else { AstVarRef* refp = VN_CAST(sit->nodep(), VarRef); AstUnpackArrayDType* adtypep; @@ -718,7 +723,7 @@ class SplitUnpackedVarVisitor : public AstNVisitor, public SplitVarImpl { lsb = adtypep->lsb(); } AstVarRef* newrefp = createTempVar(sit->context(), refp, adtypep, varp->name(), - vars, lsb, refp->lvalue(), sit->ftask()); + vars, lsb, refp->access(), sit->ftask()); newp = newrefp; refp->varp()->addNextHere(newrefp->varp()); UINFO(3, @@ -891,9 +896,9 @@ public: } explicit PackedVarRef(AstVar* varp) : m_basicp{varp->dtypep()->basicp()} {} - void append(const PackedVarRefEntry& e, bool lvalue) { + void append(const PackedVarRefEntry& e, const VAccess& access) { UASSERT(!m_dedupDone, "cannot add after dedup()"); - if (lvalue) + if (access.isWrite()) m_lhs.push_back(e); else m_rhs.push_back(e); @@ -981,7 +986,7 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl { "variable in package must have been dropped beforehand."); const AstBasicDType* basicp = refit->second.basicp(); refit->second.append(PackedVarRefEntry(nodep, basicp->lsb(), varp->width()), - nodep->lvalue()); + nodep->access()); UINFO(5, varp->prettyName() << " Entire bit of [" << basicp->lsb() << ":+" << varp->width() << "] \n"); } @@ -1005,7 +1010,7 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl { refit->second.append( PackedVarRefEntry(nodep, consts[0]->toSInt() + refit->second.basicp()->lsb(), consts[1]->toUInt()), - vrefp->lvalue()); + vrefp->access()); UINFO(5, varp->prettyName() << " [" << consts[0]->toSInt() << ":+" << consts[1]->toSInt() << "] lsb:" << refit->second.basicp()->lsb() << "\n"); @@ -1028,8 +1033,8 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl { // Extract necessary bit range from a newly created variable to meet ref static AstNode* extractBits(const PackedVarRefEntry& ref, const SplitNewVar& var, - bool lvalue) { - AstVarRef* refp = new AstVarRef(ref.nodep()->fileline(), var.varp(), lvalue); + const VAccess access) { + AstVarRef* refp = new AstVarRef(ref.nodep()->fileline(), var.varp(), access); if (ref.lsb() <= var.lsb() && var.msb() <= ref.msb()) { // Use the entire bits return refp; } else { // Use slice @@ -1052,10 +1057,12 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl { } const bool in = portp->isReadOnly(); for (size_t i = 0; i < vars.size(); ++i) { - AstNode* rhsp - = new AstSel(portp->fileline(), new AstVarRef(portp->fileline(), portp, !in), - vars[i].lsb(), vars[i].bitwidth()); - AstNode* lhsp = new AstVarRef(portp->fileline(), vars[i].varp(), in); + AstNode* rhsp = new AstSel( + portp->fileline(), + new AstVarRef(portp->fileline(), portp, !in ? VAccess::WRITE : VAccess::READ), + vars[i].lsb(), vars[i].bitwidth()); + AstNode* lhsp = new AstVarRef(portp->fileline(), vars[i].varp(), + in ? VAccess::WRITE : VAccess::READ); if (!in) std::swap(lhsp, rhsp); AstNodeAssign* assignp = newAssign(portp->fileline(), lhsp, rhsp, portp); if (insertp) { @@ -1121,12 +1128,12 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl { if (AstSenItem* senitemp = refit->backSenItemp()) { AstNode* oldsenrefp = senitemp->sensp(); oldsenrefp->replaceWith( - new AstVarRef(senitemp->fileline(), varit->varp(), false)); + new AstVarRef(senitemp->fileline(), varit->varp(), VAccess::READ)); VL_DO_DANGLING(oldsenrefp->deleteTree(), oldsenrefp); prevp = senitemp; inSentitivityList = true; } else { - prevp = extractBits(*refit, *varit, lvalue); + prevp = extractBits(*refit, *varit, lvalue ? VAccess::WRITE : VAccess::READ); } for (int residue = refit->msb() - varit->msb(); residue > 0; residue -= varit->bitwidth()) { @@ -1135,10 +1142,11 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl { if (AstSenItem* senitemp = VN_CAST(prevp, SenItem)) { prevp = new AstSenItem( senitemp->fileline(), senitemp->edgeType(), - new AstVarRef(senitemp->fileline(), varit->varp(), false)); + new AstVarRef(senitemp->fileline(), varit->varp(), VAccess::READ)); senitemp->addNextHere(prevp); } else { - AstNode* bitsp = extractBits(*refit, *varit, lvalue); + AstNode* bitsp + = extractBits(*refit, *varit, lvalue ? VAccess::WRITE : VAccess::READ); prevp = new AstConcat(refit->nodep()->fileline(), bitsp, prevp); } } @@ -1177,15 +1185,16 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl { connectPortAndVar(vars, varp, nullptr); } else if (varp->isTrace()) { // Let's reuse the original variable for tracing - AstNode* rhsp - = new AstVarRef(vars.front().varp()->fileline(), vars.front().varp(), false); + AstNode* rhsp = new AstVarRef(vars.front().varp()->fileline(), vars.front().varp(), + VAccess::READ); for (size_t i = 1; i < vars.size(); ++i) { - rhsp = new AstConcat(varp->fileline(), - new AstVarRef(varp->fileline(), vars[i].varp(), false), - rhsp); + rhsp = new AstConcat( + varp->fileline(), + new AstVarRef(varp->fileline(), vars[i].varp(), VAccess::READ), rhsp); } - varp->addNextHere(newAssign( - varp->fileline(), new AstVarRef(varp->fileline(), varp, true), rhsp, varp)); + varp->addNextHere(newAssign(varp->fileline(), + new AstVarRef(varp->fileline(), varp, VAccess::WRITE), + rhsp, varp)); } else { // the original variable is not used anymore. VL_DO_DANGLING(varp->unlinkFrBack()->deleteTree(), varp); } diff --git a/src/V3Subst.cpp b/src/V3Subst.cpp index ac18e4d08..636d39986 100644 --- a/src/V3Subst.cpp +++ b/src/V3Subst.cpp @@ -306,7 +306,7 @@ private: iterate(nodep->rhsp()); AstVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef); AstConst* constp = VN_CAST(nodep->rhsp(), Const); - if (varrefp && isSubstVar(varrefp->varp()) && !varrefp->lvalue() && constp) { + if (varrefp && isSubstVar(varrefp->varp()) && !varrefp->access().isWrite() && constp) { // Nicely formed lvalues handled in NodeAssign // Other lvalues handled as unknown mess in AstVarRef int word = constp->toUInt(); @@ -329,14 +329,14 @@ private: } virtual void visit(AstVarRef* nodep) override { // Any variable - if (nodep->lvalue()) { + if (nodep->access().isWrite()) { m_assignStep++; nodep->varp()->user2(m_assignStep); UINFO(9, " ASSIGNstep u2=" << nodep->varp()->user2() << " " << nodep << endl); } if (isSubstVar(nodep->varp())) { SubstVarEntry* entryp = getEntryp(nodep); - if (nodep->lvalue()) { + if (nodep->access().isWrite()) { UINFO(8, " ASSIGNcpx " << nodep << endl); entryp->assignComplex(); } else if (AstNode* substp = entryp->substWhole(nodep)) { @@ -365,11 +365,7 @@ private: public: // CONSTRUCTORS - explicit SubstVisitor(AstNode* nodep) { - AstNode::user1ClearTree(); // user1p() used on entire tree - AstNode::user2ClearTree(); // user2p() used on entire tree - iterate(nodep); - } + explicit SubstVisitor(AstNode* nodep) { iterate(nodep); } virtual ~SubstVisitor() override { V3Stats::addStat("Optimizations, Substituted temps", m_statSubsts); for (SubstVarEntry* ip : m_entryps) { diff --git a/src/V3SymTable.h b/src/V3SymTable.h index d72925dbe..6fbdca71f 100644 --- a/src/V3SymTable.h +++ b/src/V3SymTable.h @@ -108,6 +108,7 @@ public: void operator delete(void* objp, size_t size) {} #endif void fallbackp(VSymEnt* entp) { m_fallbackp = entp; } + VSymEnt* fallbackp() const { return m_fallbackp; } void parentp(VSymEnt* entp) { m_parentp = entp; } VSymEnt* parentp() const { return m_parentp; } void packagep(AstNodeModule* entp) { m_packagep = entp; } diff --git a/src/V3Table.cpp b/src/V3Table.cpp index dc350a4d5..b91348489 100644 --- a/src/V3Table.cpp +++ b/src/V3Table.cpp @@ -154,7 +154,7 @@ public: // Called by TableSimulateVisitor on each unique varref encountered UINFO(9, " SimVARREF " << nodep << endl); AstVarScope* vscp = nodep->varScopep(); - if (nodep->lvalue()) { + if (nodep->access().isWrite()) { m_outWidth += nodep->varp()->dtypeSkipRefp()->widthTotalBytes(); m_outVarps.push_back(vscp); } else { @@ -255,7 +255,7 @@ private: // First var in inVars becomes the LSB of the concat AstNode* concatp = nullptr; for (AstVarScope* invscp : m_inVarps) { - AstVarRef* refp = new AstVarRef(nodep->fileline(), invscp, false); + AstVarRef* refp = new AstVarRef(nodep->fileline(), invscp, VAccess::READ); if (concatp) { concatp = new AstConcat(nodep->fileline(), refp, concatp); } else { @@ -263,8 +263,9 @@ private: } } - AstNode* stmtsp = new AstAssign( - nodep->fileline(), new AstVarRef(nodep->fileline(), indexVscp, true), concatp); + AstNode* stmtsp + = new AstAssign(nodep->fileline(), + new AstVarRef(nodep->fileline(), indexVscp, VAccess::WRITE), concatp); return stmtsp; } @@ -372,10 +373,11 @@ private: // Set each output from array ref into our table int outnum = 0; for (AstVarScope* outvscp : m_outVarps) { - AstNode* alhsp = new AstVarRef(nodep->fileline(), outvscp, true); + AstNode* alhsp = new AstVarRef(nodep->fileline(), outvscp, VAccess::WRITE); AstNode* arhsp = new AstArraySel( - nodep->fileline(), new AstVarRef(nodep->fileline(), m_tableVarps[outnum], false), - new AstVarRef(nodep->fileline(), indexVscp, false)); + nodep->fileline(), + new AstVarRef(nodep->fileline(), m_tableVarps[outnum], VAccess::READ), + new AstVarRef(nodep->fileline(), indexVscp, VAccess::READ)); AstNode* outasnp = (m_assignDly ? static_cast(new AstAssignDly(nodep->fileline(), alhsp, arhsp)) @@ -389,9 +391,10 @@ private: outsetp = new AstIf( nodep->fileline(), new AstAnd(nodep->fileline(), - new AstArraySel(nodep->fileline(), - new AstVarRef(nodep->fileline(), chgVscp, false), - new AstVarRef(nodep->fileline(), indexVscp, false)), + new AstArraySel( + nodep->fileline(), + new AstVarRef(nodep->fileline(), chgVscp, VAccess::READ), + new AstVarRef(nodep->fileline(), indexVscp, VAccess::READ)), new AstConst(nodep->fileline(), outputChgMask)), outsetp, nullptr); } diff --git a/src/V3Task.cpp b/src/V3Task.cpp index f21ba9488..c31598adb 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -448,9 +448,9 @@ private: AstVarScope* tempvscp = createVarScope(portp, namePrefix + "__" + portp->shortName()); portp->user2p(tempvscp); - AstAssign* assp - = new AstAssign(pinp->fileline(), pinp, - new AstVarRef(tempvscp->fileline(), tempvscp, false)); + AstAssign* assp = new AstAssign( + pinp->fileline(), pinp, + new AstVarRef(tempvscp->fileline(), tempvscp, VAccess::READ)); assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); // Ok if in <= block // Put assignment BEHIND of all other statements @@ -461,7 +461,8 @@ private: = createVarScope(portp, namePrefix + "__" + portp->shortName()); portp->user2p(inVscp); AstAssign* assp = new AstAssign( - pinp->fileline(), new AstVarRef(inVscp->fileline(), inVscp, true), pinp); + pinp->fileline(), + new AstVarRef(inVscp->fileline(), inVscp, VAccess::WRITE), pinp); assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); // Ok if in <= block // Put assignment in FRONT of all other statements @@ -571,10 +572,10 @@ private: AstVarScope* newvscp = createVarScope(portp, namePrefix + "__" + portp->shortName()); portp->user2p(newvscp); - pinp->replaceWith(new AstVarRef(newvscp->fileline(), newvscp, true)); - AstAssign* assp - = new AstAssign(pinp->fileline(), pinp, - new AstVarRef(newvscp->fileline(), newvscp, false)); + pinp->replaceWith(new AstVarRef(newvscp->fileline(), newvscp, VAccess::WRITE)); + AstAssign* assp = new AstAssign( + pinp->fileline(), pinp, + new AstVarRef(newvscp->fileline(), newvscp, VAccess::READ)); assp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); // Ok if in <= block // Put assignment BEHIND of all other statements @@ -608,7 +609,7 @@ private: ccallp->addArgsp(exprp); } - if (outvscp) ccallp->addArgsp(new AstVarRef(refp->fileline(), outvscp, true)); + if (outvscp) ccallp->addArgsp(new AstVarRef(refp->fileline(), outvscp, VAccess::WRITE)); if (debug() >= 9) beginp->dumpTreeAndNext(cout, "-nitask: "); return beginp; @@ -661,7 +662,7 @@ private: bool useSetWSvlv = V3Task::dpiToInternalFrStmt(portp, frName, frstmt); if (useSetWSvlv) { AstNode* linesp = new AstText(portp->fileline(), frstmt); - linesp->addNext(new AstVarRef(portp->fileline(), portvscp, true)); + linesp->addNext(new AstVarRef(portp->fileline(), portvscp, VAccess::WRITE)); linesp->addNext(new AstText(portp->fileline(), "," + frName + ");")); return new AstCStmt(portp->fileline(), linesp); } @@ -675,7 +676,7 @@ private: } } AstNode* newp = new AstAssign( - portp->fileline(), new AstVarRef(portp->fileline(), portvscp, true), + portp->fileline(), new AstVarRef(portp->fileline(), portvscp, VAccess::WRITE), new AstSel(portp->fileline(), new AstCMath(portp->fileline(), frstmt, cwidth, false), 0, portp->width())); return newp; @@ -741,7 +742,8 @@ private: outvscp->varp()->protect(false); portp->protect(false); AstVarRef* refp - = new AstVarRef(portp->fileline(), outvscp, portp->isWritable()); + = new AstVarRef(portp->fileline(), outvscp, + portp->isWritable() ? VAccess::WRITE : VAccess::READ); argnodesp = argnodesp->addNextNull(refp); if (portp->isNonOutput()) { @@ -765,7 +767,8 @@ private: AstVarScope* outvscp = createFuncVar(dpip, portp->name() + "__Vcvt", portp); // No information exposure; is already visible in import/export func template outvscp->varp()->protect(false); - AstVarRef* refp = new AstVarRef(portp->fileline(), outvscp, portp->isWritable()); + AstVarRef* refp = new AstVarRef(portp->fileline(), outvscp, + portp->isWritable() ? VAccess::WRITE : VAccess::READ); argnodesp = argnodesp->addNextNull(refp); } @@ -1134,8 +1137,8 @@ private: // Return statement if (rtnvscp && nodep->taskPublic()) { - cfuncp->addFinalsp(new AstCReturn(rtnvscp->fileline(), - new AstVarRef(rtnvscp->fileline(), rtnvscp, false))); + cfuncp->addFinalsp(new AstCReturn( + rtnvscp->fileline(), new AstVarRef(rtnvscp->fileline(), rtnvscp, VAccess::READ))); } // Replace variable refs // Iteration requires a back, so put under temporary node @@ -1245,7 +1248,7 @@ private: visitp = insertBeforeStmt(nodep, beginp); } else if (!nodep->isStatement()) { UASSERT_OBJ(nodep->taskp()->isFunction(), nodep, "func reference to non-function"); - AstVarRef* outrefp = new AstVarRef(nodep->fileline(), outvscp, false); + AstVarRef* outrefp = new AstVarRef(nodep->fileline(), outvscp, VAccess::READ); nodep->replaceWith(outrefp); // Insert new statements visitp = insertBeforeStmt(nodep, beginp); @@ -1371,7 +1374,6 @@ public: // CONSTRUCTORS TaskVisitor(AstNetlist* nodep, TaskStateVisitor* statep) : m_statep{statep} { - AstNode::user1ClearTree(); iterate(nodep); } virtual ~TaskVisitor() override {} diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index cb29a734e..3aeace7ab 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -419,13 +419,13 @@ private: graphSimplify(false); } - AstNode* selectActivity(FileLine* flp, uint32_t acode, bool lvalue) { - return new AstArraySel(flp, new AstVarRef(flp, m_activityVscp, lvalue), acode); + AstNode* selectActivity(FileLine* flp, uint32_t acode, const VAccess& access) { + return new AstArraySel(flp, new AstVarRef(flp, m_activityVscp, access), acode); } void addActivitySetter(AstNode* insertp, uint32_t code) { FileLine* const fl = insertp->fileline(); - AstAssign* const setterp = new AstAssign(fl, selectActivity(fl, code, true), + AstAssign* const setterp = new AstAssign(fl, selectActivity(fl, code, VAccess::WRITE), new AstConst(fl, AstConst::LogicTrue())); if (AstCCall* const callp = VN_CAST(insertp, CCall)) { callp->addNextHere(setterp); @@ -638,7 +638,7 @@ private: condp = new AstConst(flp, 1); // Always true, will be folded later } else { for (const uint32_t actCode : actSet) { - AstNode* const selp = selectActivity(flp, actCode, false); + AstNode* const selp = selectActivity(flp, actCode, VAccess::READ); condp = condp ? new AstOr(flp, condp, selp) : selp; } } @@ -651,7 +651,7 @@ private: // Add TraceInc node AstTraceDecl* const declp = vtxp->nodep(); - AstTraceInc* const incp = new AstTraceInc(declp->fileline(), declp, false); + AstTraceInc* const incp = new AstTraceInc(declp->fileline(), declp, VAccess::READ); ifp->addIfsp(incp); subStmts += EmitCBaseCounterVisitor(incp).count(); @@ -686,7 +686,7 @@ private: // Clear fine grained activity flags for (uint32_t i = 0; i < m_activityNumber; ++i) { - AstNode* const clrp = new AstAssign(fl, selectActivity(fl, i, true), + AstNode* const clrp = new AstAssign(fl, selectActivity(fl, i, VAccess::WRITE), new AstConst(fl, AstConst::LogicFalse())); cleanupFuncp->addStmtsp(clrp); } @@ -845,7 +845,7 @@ private: virtual void visit(AstVarRef* nodep) override { if (m_tracep) { UASSERT_OBJ(nodep->varScopep(), nodep, "No var scope?"); - UASSERT_OBJ(!nodep->lvalue(), nodep, "Lvalue in trace? Should be const."); + UASSERT_OBJ(!nodep->access().isWrite(), nodep, "Lvalue in trace? Should be const."); V3GraphVertex* varVtxp = nodep->varScopep()->user1u().toGraphVertex(); if (!varVtxp) { varVtxp = new TraceVarVertex(&m_graph, nodep->varScopep()); @@ -857,7 +857,7 @@ private: || nodep->varp()->isSigPublic()) { // Or ones user can change new V3GraphEdge(&m_graph, m_alwaysVtxp, traceVtxp, 1); } - } else if (m_funcp && m_finding && nodep->lvalue()) { + } else if (m_funcp && m_finding && nodep->access().isWrite()) { UASSERT_OBJ(nodep->varScopep(), nodep, "No var scope?"); V3GraphVertex* const funcVtxp = getCFuncVertexp(m_funcp); V3GraphVertex* const varVtxp = nodep->varScopep()->user1u().toGraphVertex(); diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index 4157347a5..f8669c6bd 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -201,7 +201,7 @@ private: if (nodep->valuep()) { m_traValuep = nodep->valuep()->cloneTree(true); } else { - m_traValuep = new AstVarRef(nodep->fileline(), nodep, false); + m_traValuep = new AstVarRef(nodep->fileline(), nodep, VAccess::READ); } // Recurse into data type of the signal; the visitors will call addTraceDecl() iterate(varp->dtypep()->skipRefToEnump()); diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index 7dda34b28..1bcf41c3f 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -168,7 +168,7 @@ private: for (V3GraphEdge* edgep = vtxp->inBeginp(); edgep; edgep = edgep->inNextp()) { TristateVertex* vvertexp = dynamic_cast(edgep->fromp()); if (const AstVarRef* refp = VN_CAST(vvertexp->nodep(), VarRef)) { - if (refp->lvalue() + if (refp->access().isWrite() // Doesn't hurt to not check if already set, but by doing so when we // print out the debug messages, we'll see this node at level 0 instead. && !vvertexp->isTristate()) { @@ -276,12 +276,12 @@ class TristatePinVisitor : public TristateBaseVisitor { bool m_lvalue; // Flip to be an LVALUE // VISITORS virtual void visit(AstVarRef* nodep) override { - if (m_lvalue && !nodep->lvalue()) { + if (m_lvalue && !nodep->access().isWrite()) { UINFO(9, " Flip-to-LValue " << nodep << endl); - nodep->lvalue(true); - } else if (!m_lvalue && nodep->lvalue()) { + nodep->access(VAccess::WRITE); + } else if (!m_lvalue && nodep->access().isWrite()) { UINFO(9, " Flip-to-RValue " << nodep << endl); - nodep->lvalue(false); + nodep->access(VAccess::READ); // Mark the ex-output as tristated UINFO(9, " setTristate-subpin " << nodep->varp() << endl); m_tgraph.setTristate(nodep->varp()); @@ -489,7 +489,7 @@ class TristateVisitor : public TristateBaseVisitor { UINFO(8, " Adding driver to var " << varp << endl); AstConst* constp = new AstConst(varp->fileline(), AstConst::WidthedValue(), varp->width(), 0); - AstVarRef* varrefp = new AstVarRef(varp->fileline(), varp, true); + AstVarRef* varrefp = new AstVarRef(varp->fileline(), varp, VAccess::WRITE); AstNode* newp = new AstAssignW(varp->fileline(), varrefp, constp); UINFO(9, " newoev " << newp << endl); varrefp->user1p(new AstConst(varp->fileline(), AstConst::WidthedValue(), @@ -577,24 +577,25 @@ class TristateVisitor : public TristateBaseVisitor { nodep->addStmtp(newenp); AstNode* enassp = new AstAssignW( - refp->fileline(), new AstVarRef(refp->fileline(), newenp, true), getEnp(refp)); + refp->fileline(), new AstVarRef(refp->fileline(), newenp, VAccess::WRITE), + getEnp(refp)); UINFO(9, " newass " << enassp << endl); nodep->addStmtp(enassp); // now append this driver to the driver logic. - AstNode* ref1p = new AstVarRef(refp->fileline(), newlhsp, false); - AstNode* ref2p = new AstVarRef(refp->fileline(), newenp, false); + AstNode* ref1p = new AstVarRef(refp->fileline(), newlhsp, VAccess::READ); + AstNode* ref2p = new AstVarRef(refp->fileline(), newenp, VAccess::READ); AstNode* andp = new AstAnd(refp->fileline(), ref1p, ref2p); // or this to the others orp = (!orp) ? andp : new AstOr(refp->fileline(), orp, andp); if (envarp) { - AstNode* ref3p = new AstVarRef(refp->fileline(), newenp, false); + AstNode* ref3p = new AstVarRef(refp->fileline(), newenp, VAccess::READ); enp = (!enp) ? ref3p : new AstOr(ref3p->fileline(), enp, ref3p); } - AstNode* tmp = new AstNot(newenp->fileline(), - new AstVarRef(newenp->fileline(), newenp, false)); + AstNode* tmp = new AstNot( + newenp->fileline(), new AstVarRef(newenp->fileline(), newenp, VAccess::READ)); undrivenp = ((!undrivenp) ? tmp : new AstAnd(refp->fileline(), tmp, undrivenp)); } if (!undrivenp) { // No drivers on the bus @@ -621,11 +622,12 @@ class TristateVisitor : public TristateBaseVisitor { } if (envarp) { nodep->addStmtp(new AstAssignW( - enp->fileline(), new AstVarRef(envarp->fileline(), envarp, true), enp)); + enp->fileline(), new AstVarRef(envarp->fileline(), envarp, VAccess::WRITE), + enp)); } // __out (child) or (parent) = drive-value expression - AstNode* assp = new AstAssignW(lhsp->fileline(), - new AstVarRef(lhsp->fileline(), lhsp, true), orp); + AstNode* assp = new AstAssignW( + lhsp->fileline(), new AstVarRef(lhsp->fileline(), lhsp, VAccess::WRITE), orp); assp->user2(U2_BOTH); // Don't process further; already resolved if (debug() >= 9) assp->dumpTree(cout, "-lhsp-eqn: "); nodep->addStmtp(assp); @@ -647,7 +649,7 @@ class TristateVisitor : public TristateBaseVisitor { // due to the pinReconnectSimple call in visit AstPin. // We can ignore the output override by making a temporary AstVar* varp = getCreateUnconnVarp(nodep, nodep->dtypep()); - AstNode* newp = new AstVarRef(nodep->fileline(), varp, true); + AstNode* newp = new AstVarRef(nodep->fileline(), varp, VAccess::WRITE); UINFO(9, " const->" << newp << endl); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); @@ -945,10 +947,12 @@ class TristateVisitor : public TristateBaseVisitor { ->num(); // visit(AstConst) already split into en/ones const V3Number& oneIfEnOne = constp->num(); AstVar* envarp = getCreateEnVarp(varrefp->varp()); - AstNode* newp = new AstLogAnd( - fl, new AstEq(fl, new AstConst(fl, oneIfEn), new AstVarRef(fl, envarp, false)), - // Keep the caseeq if there are X's present - new AstEqCase(fl, new AstConst(fl, oneIfEnOne), varrefp)); + AstNode* newp + = new AstLogAnd(fl, + new AstEq(fl, new AstConst(fl, oneIfEn), + new AstVarRef(fl, envarp, VAccess::READ)), + // Keep the caseeq if there are X's present + new AstEqCase(fl, new AstConst(fl, oneIfEnOne), varrefp)); if (neq) newp = new AstLogNot(fl, newp); UINFO(9, " newceq " << newp << endl); if (debug() >= 9) nodep->dumpTree(cout, "-caseeq-old: "); @@ -992,7 +996,7 @@ class TristateVisitor : public TristateBaseVisitor { nodep->v3warn(E_UNSUPPORTED, "Unsupported pullup/down (weak driver) construct."); } else { if (m_graphing) { - varrefp->lvalue(true); + varrefp->access(VAccess::WRITE); m_logicp = nodep; m_tgraph.setTristate(nodep); associateLogic(nodep, varrefp->varp()); @@ -1004,7 +1008,7 @@ class TristateVisitor : public TristateBaseVisitor { // current limitation of this implementation is that a pullup/down // gets applied to all bits of a bus and a bus cannot have drivers // in opposite directions on individual pins. - varrefp->lvalue(true); + varrefp->access(VAccess::WRITE); m_tgraph.didProcess(nodep); m_tgraph.didProcess(varrefp->varp()); setPullDirection(varrefp->varp(), nodep); @@ -1082,7 +1086,9 @@ class TristateVisitor : public TristateBaseVisitor { AstVar* ucVarp = getCreateUnconnVarp(nodep, nodep->modVarp()->dtypep()); nodep->exprp(new AstVarRef(nodep->fileline(), ucVarp, // We converted, so use declaration output state - nodep->modVarp()->declDirection().isWritable())); + nodep->modVarp()->declDirection().isWritable() + ? VAccess::WRITE + : VAccess::READ)); m_tgraph.setTristate(ucVarp); // We don't need a driver on the wire; the lack of one will default to tristate } else if (inDeclProcessing) { // Not an input that was a converted tristate @@ -1103,15 +1109,16 @@ class TristateVisitor : public TristateBaseVisitor { nodep->name() + "__en" + cvtToStr(m_unique++), VFlagBitPacked(), enModVarp->width()); UINFO(9, " newenv " << enVarp << endl); - AstPin* enpinp = new AstPin(nodep->fileline(), nodep->pinNum(), - enModVarp->name(), // should be {var}"__en" - new AstVarRef(nodep->fileline(), enVarp, true)); + AstPin* enpinp + = new AstPin(nodep->fileline(), nodep->pinNum(), + enModVarp->name(), // should be {var}"__en" + new AstVarRef(nodep->fileline(), enVarp, VAccess::WRITE)); enpinp->modVarp(enModVarp); UINFO(9, " newpin " << enpinp << endl); enpinp->user2(U2_BOTH); // don't iterate the pin later nodep->addNextHere(enpinp); m_modp->addStmtp(enVarp); - enrefp = new AstVarRef(nodep->fileline(), enVarp, false); + enrefp = new AstVarRef(nodep->fileline(), enVarp, VAccess::READ); UINFO(9, " newvrf " << enrefp << endl); if (debug() >= 9) enpinp->dumpTree(cout, "-pin-ena: "); } @@ -1215,7 +1222,7 @@ class TristateVisitor : public TristateBaseVisitor { virtual void visit(AstVarRef* nodep) override { UINFO(9, dbgState() << nodep << endl); if (m_graphing) { - if (nodep->lvalue()) { + if (nodep->access().isWrite()) { associateLogic(nodep, nodep->varp()); } else { associateLogic(nodep->varp(), nodep); @@ -1226,11 +1233,11 @@ class TristateVisitor : public TristateBaseVisitor { // Detect all var lhs drivers and adds them to the // VarMap so that after the walk through the module we can expand // any tristate logic on the driver. - if (nodep->lvalue() && m_tgraph.isTristate(nodep->varp())) { + if (nodep->access().isWrite() && m_tgraph.isTristate(nodep->varp())) { UINFO(9, " Ref-to-lvalue " << nodep << endl); m_tgraph.didProcess(nodep); mapInsertLhsVarRef(nodep); - } else if (!nodep->lvalue() + } else if (!nodep->access().isWrite() // Not already processed, nor varref from visit(AstPin) creation && !nodep->user1p() // Reference to another tristate variable @@ -1240,7 +1247,7 @@ class TristateVisitor : public TristateBaseVisitor { // Then propagate the enable from the original variable UINFO(9, " Ref-to-tri " << nodep << endl); AstVar* enVarp = getCreateEnVarp(nodep->varp()); - nodep->user1p(new AstVarRef(nodep->fileline(), enVarp, false)); + nodep->user1p(new AstVarRef(nodep->fileline(), enVarp, VAccess::READ)); } if (m_alhs) {} // NOP; user1() already passed down from assignment } @@ -1254,9 +1261,9 @@ class TristateVisitor : public TristateBaseVisitor { if (nodep->user2() & U2_GRAPHING) return; // Already processed nodep->user2(U2_GRAPHING); if (nodep->isPulldown() || nodep->isPullup()) { - AstNode* newp - = new AstPull(nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, true), - nodep->isPullup()); + AstNode* newp = new AstPull( + nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, VAccess::WRITE), + nodep->isPullup()); UINFO(9, " newpul " << newp << endl); nodep->addNextHere(newp); // We'll iterate on the new AstPull later diff --git a/src/V3Undriven.cpp b/src/V3Undriven.cpp index 01890983f..c09336dcd 100644 --- a/src/V3Undriven.cpp +++ b/src/V3Undriven.cpp @@ -318,7 +318,7 @@ private: for (int usr = 1; usr < (m_alwaysCombp ? 3 : 2); ++usr) { UndrivenVarEntry* entryp = getEntryp(varrefp->varp(), usr); int lsb = constp->toUInt(); - if (m_inBBox || varrefp->lvalue()) { + if (m_inBBox || varrefp->access().isWrite()) { // Don't warn if already driven earlier as "a=0; if(a) a=1;" is fine. if (usr == 2 && m_alwaysCombp && entryp->isUsedNotDrivenBit(lsb, nodep->width())) { @@ -327,7 +327,7 @@ private: } entryp->drivenBit(lsb, nodep->width()); } - if (m_inBBox || !varrefp->lvalue()) entryp->usedBit(lsb, nodep->width()); + if (m_inBBox || !varrefp->access().isWrite()) entryp->usedBit(lsb, nodep->width()); } } else { // else other varrefs handled as unknown mess in AstVarRef @@ -336,7 +336,7 @@ private: } virtual void visit(AstNodeVarRef* nodep) override { // Any variable - if (nodep->lvalue() + if (nodep->access().isWrite() && !VN_IS(nodep, VarXRef)) { // Ignore interface variables and similar ugly items if (m_inProcAssign && !nodep->varp()->varType().isProcAssignable() && !nodep->varp()->isDeclTyped() // @@ -355,16 +355,16 @@ private: } for (int usr = 1; usr < (m_alwaysCombp ? 3 : 2); ++usr) { UndrivenVarEntry* entryp = getEntryp(nodep->varp(), usr); - bool fdrv = nodep->lvalue() + bool fdrv = nodep->access().isWrite() && nodep->varp()->attrFileDescr(); // FD's are also being read from - if (m_inBBox || nodep->lvalue()) { + if (m_inBBox || nodep->access().isWrite()) { if (usr == 2 && m_alwaysCombp && entryp->isUsedNotDrivenAny()) { UINFO(9, " Full bus. Entryp=" << cvtToHex(entryp) << endl); warnAlwCombOrder(nodep); } entryp->drivenWhole(); } - if (m_inBBox || !nodep->lvalue() || fdrv) entryp->usedWhole(); + if (m_inBBox || !nodep->access().isWrite() || fdrv) entryp->usedWhole(); } } diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp index 15e9a199b..160c161c3 100644 --- a/src/V3Unknown.cpp +++ b/src/V3Unknown.cpp @@ -118,14 +118,14 @@ private: m_modp->addStmtp(varp); AstNode* abovep = prep->backp(); // Grab above point before lose it w/ next replace - prep->replaceWith(new AstVarRef(fl, varp, true)); - AstIf* newp - = new AstIf(fl, condp, - (needDly ? static_cast( - new AstAssignDly(fl, prep, new AstVarRef(fl, varp, false))) - : static_cast( - new AstAssign(fl, prep, new AstVarRef(fl, varp, false)))), - nullptr); + prep->replaceWith(new AstVarRef(fl, varp, VAccess::WRITE)); + AstIf* newp = new AstIf( + fl, condp, + (needDly ? static_cast( + new AstAssignDly(fl, prep, new AstVarRef(fl, varp, VAccess::READ))) + : static_cast( + new AstAssign(fl, prep, new AstVarRef(fl, varp, VAccess::READ)))), + nullptr); newp->branchPred(VBranchPred::BP_LIKELY); if (debug() >= 9) newp->dumpTree(cout, " _new: "); abovep->addNextStmt(newp, abovep); @@ -281,12 +281,13 @@ private: ++m_statUnkVars; AstNRelinker replaceHandle; nodep->unlinkFrBack(&replaceHandle); - AstNodeVarRef* newref1p = new AstVarRef(nodep->fileline(), newvarp, false); + AstNodeVarRef* newref1p = new AstVarRef(nodep->fileline(), newvarp, VAccess::READ); replaceHandle.relink(newref1p); // Replace const with varref AstInitial* newinitp = new AstInitial( nodep->fileline(), new AstAssign( - nodep->fileline(), new AstVarRef(nodep->fileline(), newvarp, true), + nodep->fileline(), + new AstVarRef(nodep->fileline(), newvarp, VAccess::WRITE), new AstOr( nodep->fileline(), new AstConst(nodep->fileline(), numb1), new AstAnd(nodep->fileline(), new AstConst(nodep->fileline(), numbx), @@ -312,7 +313,7 @@ private: AstNode* basefromp = AstArraySel::baseFromp(nodep); bool lvalue = false; if (const AstNodeVarRef* varrefp = VN_CAST(basefromp, NodeVarRef)) { - lvalue = varrefp->lvalue(); + lvalue = varrefp->access().isWrite(); } // Find range of dtype we are selecting from // Similar code in V3Const::warnSelect @@ -360,7 +361,7 @@ private: AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp()); bool lvalue = false; if (const AstNodeVarRef* varrefp = VN_CAST(basefromp, NodeVarRef)) { - lvalue = varrefp->lvalue(); + lvalue = varrefp->access().isWrite(); } else if (VN_IS(basefromp, Const)) { // If it's a PARAMETER[bit], then basefromp may be a constant instead of a varrefp } else { diff --git a/src/V3Unroll.cpp b/src/V3Unroll.cpp index 968a23c30..a94de57ac 100644 --- a/src/V3Unroll.cpp +++ b/src/V3Unroll.cpp @@ -445,13 +445,13 @@ private: virtual void visit(AstVarRef* nodep) override { if (m_varModeCheck && nodep->varp() == m_forVarp && nodep->varScopep() == m_forVscp - && nodep->lvalue()) { + && nodep->access().isWrite()) { UINFO(8, " Itervar assigned to: " << nodep << endl); m_varAssignHit = true; } if (m_varModeReplace && nodep->varp() == m_forVarp && nodep->varScopep() == m_forVscp - && !nodep->lvalue()) { + && !nodep->access().isWrite()) { AstNode* newconstp = m_varValuep->cloneTree(false); nodep->replaceWith(newconstp); pushDeletep(nodep); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 081dcbd10..1bcfaad59 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -128,6 +128,11 @@ public: return m_dtypep; } AstNodeDType* dtypeNullp() const { return m_dtypep; } + AstNodeDType* dtypeNullSkipRefp() const { + AstNodeDType* dtp = dtypeNullp(); + if (dtp) dtp = dtp->skipRefp(); + return dtp; + } AstNodeDType* dtypeOverridep(AstNodeDType* defaultp) const { if (m_stage == PRELIM) v3fatalSrc("Parent dtype should be a final-stage action"); return m_dtypep ? m_dtypep : defaultp; @@ -478,7 +483,7 @@ private: // signed: Unsigned (11.8.1) // width: LHS + RHS if (m_vup->prelim()) { - AstNodeDType* vdtypep = m_vup->dtypeNullp(); + AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp(); if (vdtypep && (VN_IS(vdtypep, AssocArrayDType) // || VN_IS(vdtypep, DynArrayDType) // @@ -602,7 +607,7 @@ private: // LHS, RHS is self-determined // width: value(LHS) * width(RHS) if (m_vup->prelim()) { - AstNodeDType* vdtypep = m_vup->dtypeNullp(); + AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp(); if (vdtypep && (VN_IS(vdtypep, AssocArrayDType) || VN_IS(vdtypep, DynArrayDType) || VN_IS(vdtypep, QueueDType) || VN_IS(vdtypep, UnpackArrayDType))) { @@ -1096,6 +1101,14 @@ private: } } + virtual void visit(AstImplication* nodep) override { + if (m_vup->prelim()) { + iterateCheckBool(nodep, "LHS", nodep->lhsp(), BOTH); + iterateCheckBool(nodep, "RHS", nodep->rhsp(), BOTH); + nodep->dtypeSetLogicBool(); + } + } + virtual void visit(AstRand* nodep) override { if (m_vup->prelim()) { nodep->dtypeSetSigned32(); // Says the spec @@ -1110,6 +1123,8 @@ private: if (m_vup->prelim()) { nodep->dtypeSetUInt32(); // Says the spec AstNodeDType* expDTypep = nodep->findUInt32DType(); + userIterateAndNext(nodep->lhsp(), WidthVP(CONTEXT, PRELIM).p()); + userIterateAndNext(nodep->rhsp(), WidthVP(CONTEXT, PRELIM).p()); iterateCheck(nodep, "LHS", nodep->lhsp(), SELF, FINAL, expDTypep, EXTEND_EXP); iterateCheck(nodep, "RHS", nodep->rhsp(), SELF, FINAL, expDTypep, EXTEND_EXP); } @@ -1356,7 +1371,7 @@ private: AstVar* varp = dimensionVarp(nodep->fromp()->dtypep(), nodep->attrType(), msbdim); AstNode* dimp = nodep->dimp()->unlinkFrBack(); - AstVarRef* varrefp = new AstVarRef(nodep->fileline(), varp, false); + AstVarRef* varrefp = new AstVarRef(nodep->fileline(), varp, VAccess::READ); varrefp->packagep(v3Global.rootp()->dollarUnitPkgAddp()); AstNode* newp = new AstArraySel(nodep->fileline(), varrefp, dimp); nodep->replaceWith(newp); @@ -1805,13 +1820,13 @@ private: // nodep->varp()->dumpTree(cout, " forvar "); } // Note genvar's are also entered as integers nodep->dtypeFrom(nodep->varp()); - if (VN_IS(nodep->backp(), NodeAssign) && nodep->lvalue()) { // On LHS + if (VN_IS(nodep->backp(), NodeAssign) && nodep->access().isWrite()) { // On LHS UASSERT_OBJ(nodep->dtypep(), nodep, "LHS var should be dtype completed"); } // if (debug() >= 9) nodep->dumpTree(cout, " VRout "); - if (nodep->lvalue() && nodep->varp()->direction() == VDirection::CONSTREF) { + if (nodep->access().isWrite() && nodep->varp()->direction() == VDirection::CONSTREF) { nodep->v3error("Assigning to const ref variable: " << nodep->prettyNameQ()); - } else if (nodep->lvalue() && nodep->varp()->isConst() && !m_paramsOnly + } else if (nodep->access().isWrite() && nodep->varp()->isConst() && !m_paramsOnly && (!m_ftaskp || !m_ftaskp->isConstructor()) && !VN_IS(m_procedurep, Initial)) { // Too loose, but need to allow our generated first assignment // Move this to a property of the AstInitial block @@ -2311,7 +2326,7 @@ private: } int selwidth = V3Number::log2b(msbdim) + 1; // Width to address a bit AstVar* varp = enumVarp(adtypep, attrType, (1ULL << selwidth) - 1); - AstVarRef* varrefp = new AstVarRef(nodep->fileline(), varp, false); + AstVarRef* varrefp = new AstVarRef(nodep->fileline(), varp, VAccess::READ); varrefp->packagep(v3Global.rootp()->dollarUnitPkgAddp()); AstNode* newp = new AstArraySel( nodep->fileline(), varrefp, @@ -2358,7 +2373,7 @@ private: newp->didWidth(true); } else if (nodep->name() == "delete") { // function void delete([input integer index]) methodOkArguments(nodep, 0, 1); - methodCallLValueRecurse(nodep, nodep->fromp(), true); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); if (!nodep->pinsp()) { newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "clear", nullptr); @@ -2387,13 +2402,13 @@ private: VL_DANGLING(index_exprp); // May have been edited return VN_CAST(nodep->pinsp(), Arg)->exprp(); } - void methodCallLValueRecurse(AstMethodCall* nodep, AstNode* childp, bool lvalue) { + void methodCallLValueRecurse(AstMethodCall* nodep, AstNode* childp, const VAccess& access) { if (AstNodeVarRef* varrefp = VN_CAST(childp, NodeVarRef)) { - if (lvalue) varrefp->lvalue(true); + varrefp->access(access); } else if (AstMemberSel* ichildp = VN_CAST(childp, MemberSel)) { - methodCallLValueRecurse(nodep, ichildp->fromp(), lvalue); + methodCallLValueRecurse(nodep, ichildp->fromp(), access); } else if (AstNodeSel* ichildp = VN_CAST(childp, NodeSel)) { - methodCallLValueRecurse(nodep, ichildp->fromp(), lvalue); + methodCallLValueRecurse(nodep, ichildp->fromp(), access); } else { UINFO(1, " Related node: " << childp << endl); nodep->v3warn(E_UNSUPPORTED, "Unsupported: Non-variable on LHS of built-in method '" @@ -2404,7 +2419,7 @@ private: AstCMethodHard* newp = nullptr; if (nodep->name() == "at") { // Created internally for [] methodOkArguments(nodep, 1, 1); - methodCallLValueRecurse(nodep, nodep->fromp(), true); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "at", nullptr); newp->dtypeFrom(adtypep->subDTypep()); @@ -2419,7 +2434,7 @@ private: newp->protect(false); } else if (nodep->name() == "delete") { // function void delete() methodOkArguments(nodep, 0, 0); - methodCallLValueRecurse(nodep, nodep->fromp(), true); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "clear", nullptr); newp->makeStatement(); @@ -2437,7 +2452,7 @@ private: AstCMethodHard* newp = nullptr; if (nodep->name() == "at") { // Created internally for [] methodOkArguments(nodep, 1, 1); - methodCallLValueRecurse(nodep, nodep->fromp(), true); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "at", nullptr); newp->dtypeFrom(adtypep->subDTypep()); @@ -2453,7 +2468,7 @@ private: newp->protect(false); } else if (nodep->name() == "delete") { // function void delete([input integer index]) methodOkArguments(nodep, 0, 1); - methodCallLValueRecurse(nodep, nodep->fromp(), true); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); if (!nodep->pinsp()) { newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), "clear", nullptr); @@ -2480,7 +2495,7 @@ private: } } else if (nodep->name() == "insert") { methodOkArguments(nodep, 2, 2); - methodCallLValueRecurse(nodep, nodep->fromp(), true); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); AstNode* index_exprp = methodCallQueueIndexExpr(nodep); AstArg* argp = VN_CAST(nodep->pinsp()->nextp(), Arg); iterateCheckTyped(nodep, "insert value", argp->exprp(), adtypep->subDTypep(), BOTH); @@ -2501,7 +2516,7 @@ private: } } else if (nodep->name() == "pop_front" || nodep->name() == "pop_back") { methodOkArguments(nodep, 0, 0); - methodCallLValueRecurse(nodep, nodep->fromp(), true); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), nullptr); newp->dtypeFrom(adtypep->subDTypep()); @@ -2510,7 +2525,7 @@ private: if (!nodep->firstAbovep()) { newp->makeStatement(); } } else if (nodep->name() == "push_back" || nodep->name() == "push_front") { methodOkArguments(nodep, 1, 1); - methodCallLValueRecurse(nodep, nodep->fromp(), true); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); AstArg* argp = VN_CAST(nodep->pinsp(), Arg); iterateCheckTyped(nodep, "push value", argp->exprp(), adtypep->subDTypep(), BOTH); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), @@ -2539,6 +2554,7 @@ private: UASSERT_OBJ(first_classp, nodep, "Unlinked"); for (AstClass* classp = first_classp; classp;) { if (AstNodeFTask* ftaskp = VN_CAST(classp->findMember(nodep->name()), NodeFTask)) { + userIterate(ftaskp, nullptr); nodep->taskp(ftaskp); nodep->dtypeFrom(ftaskp); if (VN_IS(ftaskp, Task)) nodep->makeStatement(); @@ -2672,10 +2688,10 @@ private: AstNodeVarRef* fromp = VN_CAST(nodep->fromp()->unlinkFrBack(), VarRef); AstNode* rhsp = arg0p->exprp()->unlinkFrBack(); AstNode* thsp = arg1p->exprp()->unlinkFrBack(); - AstVarRef* varrefp = new AstVarRef(nodep->fileline(), fromp->varp(), false); + AstVarRef* varrefp = new AstVarRef(nodep->fileline(), fromp->varp(), VAccess::READ); AstNode* newp = new AstAssign(nodep->fileline(), fromp, new AstPutcN(nodep->fileline(), varrefp, rhsp, thsp)); - fromp->lvalue(true); + fromp->access(VAccess::WRITE); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } else if (nodep->name() == "getc") { @@ -2725,7 +2741,7 @@ private: virtual void visit(AstNew* nodep) override { if (nodep->didWidthAndSet()) return; - AstClassRefDType* refp = VN_CAST(m_vup->dtypeNullp(), ClassRefDType); + AstClassRefDType* refp = VN_CAST(m_vup->dtypeNullSkipRefp(), ClassRefDType); if (!refp) { // e.g. int a = new; nodep->v3error("new() not expected in this context"); return; @@ -2751,7 +2767,7 @@ private: } virtual void visit(AstNewCopy* nodep) override { if (nodep->didWidthAndSet()) return; - AstClassRefDType* refp = VN_CAST(m_vup->dtypeNullp(), ClassRefDType); + AstClassRefDType* refp = VN_CAST(m_vup->dtypeNullSkipRefp(), ClassRefDType); if (!refp) { // e.g. int a = new; nodep->v3error("new() not expected in this context"); return; @@ -2766,7 +2782,7 @@ private: } virtual void visit(AstNewDynamic* nodep) override { if (nodep->didWidthAndSet()) return; - AstDynArrayDType* adtypep = VN_CAST(m_vup->dtypeNullp(), DynArrayDType); + AstDynArrayDType* adtypep = VN_CAST(m_vup->dtypeNullSkipRefp(), DynArrayDType); if (!adtypep) { // e.g. int a = new; nodep->v3error( "dynamic new() not expected in this context (data type must be dynamic array)"); @@ -5082,7 +5098,7 @@ private: AstNode* newp = new AstAssign( nodep->fileline(), fromp, new AstSFormatF(nodep->fileline(), format, false, argp->exprp()->unlinkFrBack())); - fromp->lvalue(true); + fromp->access(VAccess::WRITE); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp index b6b248810..ce6cdcee8 100644 --- a/src/V3WidthSel.cpp +++ b/src/V3WidthSel.cpp @@ -280,7 +280,7 @@ private: "Unsupported: String array operation on non-variable"); } AstNode* newp; - if (varrefp && varrefp->lvalue()) { + if (varrefp && varrefp->access().isWrite()) { newp = new AstGetcRefN(nodep->fileline(), fromp, rhsp); } else { newp = new AstGetcN(nodep->fileline(), fromp, rhsp); diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 7ffce2b63..16fd4c94e 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -106,6 +106,7 @@ static void reportStatsIfEnabled() { V3Stats::statsFinalAll(v3Global.rootp()); V3Stats::statsReport(); } + if (v3Global.opt.debugEmitV()) V3EmitV::debugEmitV("final"); } static void process() { @@ -363,6 +364,7 @@ static void process() { V3ActiveTop::activeTopAll(v3Global.rootp()); if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "PreOrder"); + if (v3Global.opt.debugEmitV()) V3EmitV::debugEmitV("preorder"); // Order the code; form SBLOCKs and BLOCKCALLs V3Order::orderAll(v3Global.rootp()); @@ -547,9 +549,9 @@ static void verilate(const string& argString) { } // Undocumented debugging - cannot be a switch as then command line // would mismatch forcing non-identicalness when we set it - if (!V3Os::getenvStr("VERILATOR_DEBUG_SKIP_IDENTICAL", "").empty()) { + if (!V3Os::getenvStr("VERILATOR_DEBUG_SKIP_IDENTICAL", "").empty()) { // LCOV_EXCL_START v3fatalSrc("VERILATOR_DEBUG_SKIP_IDENTICAL w/ --skip-identical: Changes found\n"); - } + } // LCOV_EXCL_STOP //--FRONTEND------------------ @@ -621,10 +623,8 @@ static void verilate(const string& argString) { // Final writing shouldn't throw warnings, but... V3Error::abortIfWarnings(); -#ifdef VL_LEAK_CHECKS // Cleanup memory for valgrind leak analysis v3Global.clear(); -#endif FileLine::deleteAllRemaining(); } diff --git a/src/verilog.y b/src/verilog.y index c9b2e8648..414043f6b 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -110,6 +110,20 @@ public: return new AstGatePin(rangep->fileline(), exprp, rangep->cloneTree(true)); } } + AstNode* createTypedef(FileLine* fl, const string& name, AstNode* attrsp, AstNodeDType* basep, + AstNodeRange* rangep) { + AstNode* nodep = new AstTypedef(fl, name, attrsp, VFlagChildDType(), + GRAMMARP->createArray(basep, rangep, false)); + SYMP->reinsert(nodep); + PARSEP->tagNodep(nodep); + return nodep; + } + AstNode* createTypedefFwd(FileLine* fl, const string& name) { + AstNode* nodep = new AstTypedefFwd(fl, name); + SYMP->reinsert(nodep); + PARSEP->tagNodep(nodep); + return nodep; + } void endLabel(FileLine* fl, AstNode* nodep, string* endnamep) { endLabel(fl, nodep->prettyName(), endnamep); } @@ -1932,7 +1946,7 @@ list_of_tf_variable_identifiers: // ==IEEE: list_of_tf_variable_identifie tf_variable_identifier: // IEEE: part of list_of_tf_variable_identifiers id variable_dimensionListE sigAttrListE exprEqE { $$ = VARDONEA($1,*$1, $2, $3); - if ($4) $$->addNext(new AstAssign($4->fileline(), new AstVarRef($1, *$1, true), $4)); } + if ($4) $$->addNext(new AstAssign($4->fileline(), new AstVarRef($1, *$1, VAccess::WRITE), $4)); } ; variable_declExpr: // IEEE: part of variable_decl_assignment - rhs of expr @@ -2151,21 +2165,45 @@ implicit_typeE: // IEEE: part of *data_type_or_implicit //UNSUP ; type_declaration: // ==IEEE: type_declaration - // // Use idAny, as we can redeclare a typedef on an existing typedef - yTYPEDEF data_type idAny variable_dimensionListE dtypeAttrListE ';' - /**/ { $$ = new AstTypedef($3, *$3, $5, VFlagChildDType(), GRAMMARP->createArray($2,$4,false)); - SYMP->reinsert($$); PARSEP->tagNodep($$); } - | yTYPEDEF id/*interface*/ '.' idAny/*type*/ idAny/*type*/ ';' { $$ = nullptr; BBUNSUP($1, "Unsupported: SystemVerilog 2005 typedef in this context"); } + // Data_type expanded + yTYPEDEF data_typeNoRef + /*cont*/ idAny variable_dimensionListE dtypeAttrListE ';' + { AstNodeDType* dtp = $2; + $$ = GRAMMARP->createTypedef($3, *$3, $5, dtp, $4); } + | yTYPEDEF packageClassScope idType packed_dimensionListE + /*cont*/ idAny variable_dimensionListE dtypeAttrListE ';' + { AstRefDType* refp = new AstRefDType($3, *$3, $2, nullptr); + AstNodeDType* dtp = GRAMMARP->createArray(refp, $4, true); + $$ = GRAMMARP->createTypedef($5, *$5, $7, dtp, $6); } + | yTYPEDEF packageClassScope idType parameter_value_assignmentClass packed_dimensionListE + /*cont*/ idAny variable_dimensionListE dtypeAttrListE ';' + { AstRefDType* refp = new AstRefDType($3, *$3, $2, $4); + AstNodeDType* dtp = GRAMMARP->createArray(refp, $5, true); + $$ = GRAMMARP->createTypedef($6, *$6, $8, dtp, $7); } + | yTYPEDEF idType packed_dimensionListE + /*cont*/ idAny variable_dimensionListE dtypeAttrListE ';' + { AstRefDType* refp = new AstRefDType($2, *$2, nullptr, nullptr); + AstNodeDType* dtp = GRAMMARP->createArray(refp, $3, true); + $$ = GRAMMARP->createTypedef($4, *$4, $6, dtp, $5); } + | yTYPEDEF idType parameter_value_assignmentClass packed_dimensionListE + /*cont*/ idAny variable_dimensionListE dtypeAttrListE ';' + { AstRefDType* refp = new AstRefDType($2, *$2, nullptr, $3); + AstNodeDType* dtp = GRAMMARP->createArray(refp, $4, true); + $$ = GRAMMARP->createTypedef($5, *$5, $7, dtp, $6); } + // // + | yTYPEDEF id/*interface*/ '.' idAny/*type*/ idAny/*type*/ ';' + { $$ = nullptr; BBUNSUP($1, "Unsupported: SystemVerilog 2005 typedef in this context"); } + // // Allow redeclaring same typedef again + // // Alternative is use of idAny below, but this will cause conflicts with ablve + | yTYPEDEF idType ';' { $$ = GRAMMARP->createTypedefFwd($2, *$2); } // // Combines into above "data_type id" rule // // Verilator: Not important what it is in the AST, just need to make sure the yaID__aTYPE gets returned - //UNSUP // Below should be idAny to allow duplicate forward defs; need to expand - // // data_type to exclude IDs, or add id__SEMI rule - | yTYPEDEF id ';' { $$ = nullptr; $$ = new AstTypedefFwd($2, *$2); SYMP->reinsert($$); PARSEP->tagNodep($$); } - | yTYPEDEF yENUM idAny ';' { $$ = nullptr; $$ = new AstTypedefFwd($3, *$3); SYMP->reinsert($$); PARSEP->tagNodep($$); } - | yTYPEDEF ySTRUCT idAny ';' { $$ = nullptr; $$ = new AstTypedefFwd($3, *$3); SYMP->reinsert($$); PARSEP->tagNodep($$); } - | yTYPEDEF yUNION idAny ';' { $$ = nullptr; $$ = new AstTypedefFwd($3, *$3); SYMP->reinsert($$); PARSEP->tagNodep($$); } - | yTYPEDEF yCLASS idAny ';' { $$ = nullptr; $$ = new AstTypedefFwd($3, *$3); SYMP->reinsert($$); PARSEP->tagNodep($$); } - | yTYPEDEF yINTERFACE yCLASS idAny ';' { $$ = nullptr; $$ = new AstTypedefFwd($4, *$4); SYMP->reinsert($$); PARSEP->tagNodep($$); } + | yTYPEDEF id ';' { $$ = GRAMMARP->createTypedefFwd($2, *$2); } + | yTYPEDEF yENUM idAny ';' { $$ = GRAMMARP->createTypedefFwd($3, *$3); } + | yTYPEDEF ySTRUCT idAny ';' { $$ = GRAMMARP->createTypedefFwd($3, *$3); } + | yTYPEDEF yUNION idAny ';' { $$ = GRAMMARP->createTypedefFwd($3, *$3); } + | yTYPEDEF yCLASS idAny ';' { $$ = GRAMMARP->createTypedefFwd($3, *$3); } + | yTYPEDEF yINTERFACE yCLASS idAny ';' { $$ = GRAMMARP->createTypedefFwd($4, *$4); } ; dtypeAttrListE: @@ -2432,7 +2470,8 @@ loop_generate_construct: // ==IEEE: loop_generate_construct genvar_initialization: // ==IEEE: genvar_initialization varRefBase '=' expr { $$ = new AstAssign($2,$1,$3); } - | yGENVAR genvar_identifierDecl '=' constExpr { $$ = $2; $2->addNext(new AstAssign($3,new AstVarRef($2->fileline(),$2,true), $4)); } + | yGENVAR genvar_identifierDecl '=' constExpr + { $$ = $2; $2->addNext(new AstAssign($3, new AstVarRef($2->fileline(), $2, VAccess::WRITE), $4)); } ; genvar_iteration: // ==IEEE: genvar_iteration @@ -2542,7 +2581,7 @@ netSigList: // IEEE: list_of_port_identifiers netSig: // IEEE: net_decl_assignment - one element from list_of_port_identifiers netId sigAttrListE { $$ = VARDONEA($1,*$1, nullptr, $2); } | netId sigAttrListE '=' expr { $$ = VARDONEA($1,*$1, nullptr, $2); - $$->addNext(new AstAssignW($3, new AstVarRef($1, *$1, true), $4)); } + $$->addNext(new AstAssignW($3, new AstVarRef($1, *$1, VAccess::WRITE), $4)); } | netId variable_dimensionList sigAttrListE { $$ = VARDONEA($1,*$1, $2, $3); } ; @@ -3386,12 +3425,12 @@ for_initializationItem: // IEEE: variable_assignment + for_variable_decl data_type idAny/*new*/ '=' expr { VARRESET_NONLIST(VAR); VARDTYPE($1); $$ = VARDONEA($2,*$2,nullptr,nullptr); - $$->addNext(new AstAssign($3, new AstVarRef($2, *$2, true), $4));} + $$->addNext(new AstAssign($3, new AstVarRef($2, *$2, VAccess::WRITE), $4)); } // // IEEE-2012: | yVAR data_type idAny/*new*/ '=' expr { VARRESET_NONLIST(VAR); VARDTYPE($2); $$ = VARDONEA($3,*$3,nullptr,nullptr); - $$->addNext(new AstAssign($4, new AstVarRef($3, *$3, true), $5));} + $$->addNext(new AstAssign($4, new AstVarRef($3, *$3, VAccess::WRITE), $5)); } // // IEEE: variable_assignment // // UNSUP variable_lvalue below | varRefBase '=' expr { $$ = new AstAssign($2, $1, $3); } @@ -4860,7 +4899,7 @@ idArrayedForeach: // IEEE: id + select (under foreach expression) // VarRef without any dots or vectorizaion varRefBase: - id { $$ = new AstVarRef($1,*$1,false);} + id { $$ = new AstVarRef($1, *$1, VAccess::READ); } ; // yaSTRING shouldn't be used directly, instead via an abstraction below @@ -5267,7 +5306,7 @@ pexpr: // IEEE: property_expr (The name pexpr is important as regexps j //UNSUP: This rule has been super-specialized to what is supported now //UNSUP remove below expr yP_ORMINUSGT pexpr { $$ = new AstLogOr($2, new AstLogNot($2, $1), $3); } - //UNSUP expr yP_OREQGT pexpr { $$ = new AstLogOr($2, new AstLogNot($2, new AstPast($2, $1, nullptr)), $3); } // This handles disable iff in the past time step incorrectly + | expr yP_OREQGT pexpr { $$ = new AstImplication($2, $1, $3); } | expr { $$ = $1; } //UNSUP remove above, use below: // @@ -6177,9 +6216,9 @@ dist_list: // ==IEEE: dist_list ; dist_item: // ==IEEE: dist_item + dist_weight - value_range { $$ = $1; } - | value_range yP_COLONEQ expr { $$ = $1; BBUNSUP($1, "Unsupported: dist :="); } - | value_range yP_COLONDIV expr { $$ = $1; BBUNSUP($1, "Unsupported: dist :/"); } + value_range { $$ = $1; /* Same as := 1 */ } + | value_range yP_COLONEQ expr { $$ = $1; nullptr; /*UNSUP-no-UVM*/ } + | value_range yP_COLONDIV expr { $$ = $1; nullptr; /*UNSUP-no-UVM*/ } ; //UNSUPextern_constraint_declaration: // ==IEEE: extern_constraint_declaration diff --git a/test_regress/driver.pl b/test_regress/driver.pl index eadd21b69..6367b69bd 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -2079,6 +2079,7 @@ sub files_identical { && !/^-node:/ && !/^dot [^\n]+\n/ && !/^In file: .*\/sc_.*:\d+/ + && !/^libgcov.*/ } @l1; @l1 = map { s/(Internal Error: [^\n]+\.cpp):[0-9]+:/$1:#:/; @@ -2318,6 +2319,21 @@ sub write_wholefile { my $fh = IO::File->new(">$filename") or die "%Error: $! writing $filename,"; print $fh $contents; $fh->close; + delete $_File_Contents_Cache{$filename}; +} + +sub file_sed { + my $self = (ref $_[0]? shift : $Self); + my $infilename = shift; + my $outfilename = shift; + my $editcb = shift; + my $contents = $self->file_contents($infilename); + { + $_ = $contents; + $editcb->($contents); + $contents = $_; + } + $self->write_wholefile($outfilename, $contents); } ####################################################################### diff --git a/test_regress/input.vc b/test_regress/input.vc index 77e6ce27e..b394985f6 100644 --- a/test_regress/input.vc +++ b/test_regress/input.vc @@ -1,5 +1,5 @@ -+librescan +libext+.v ++librescan +notimingchecks +libext+.v -y t +incdir+t +incdir+../include diff --git a/test_regress/t/t_assert_comp_bad.out b/test_regress/t/t_assert_comp_bad.out index 9906f8e57..13838eddd 100644 --- a/test_regress/t/t_assert_comp_bad.out +++ b/test_regress/t/t_assert_comp_bad.out @@ -1,18 +1,34 @@ --Info: t/t_assert_comp_bad.v:10:7: User compile-time info +-Info: t/t_assert_comp_bad.v:10:7: : ... In instance t - 10 | $info("User compile-time info"); + 10 | $info; | ^~~~~ -%Warning-USERWARN: t/t_assert_comp_bad.v:11:7: User compile-time warning +-Info: t/t_assert_comp_bad.v:11:7: User compile-time info + : ... In instance t + 11 | $info("User compile-time info"); + | ^~~~~ +%Warning-USERWARN: t/t_assert_comp_bad.v:12:7: : ... In instance t - 11 | $warning("User compile-time warning"); + 12 | $warning; | ^~~~~~~~ ... Use "/* verilator lint_off USERWARN */" and lint_on around source to disable this message. -%Warning-USERWARN: t/t_assert_comp_bad.v:12:7: 1 +%Warning-USERWARN: t/t_assert_comp_bad.v:13:7: User compile-time warning : ... In instance t - 12 | $warning(1); + 13 | $warning("User compile-time warning"); | ^~~~~~~~ -%Warning-USERERROR: t/t_assert_comp_bad.v:13:7: User compile-time error +%Warning-USERWARN: t/t_assert_comp_bad.v:14:7: 1 + : ... In instance t + 14 | $warning(1); + | ^~~~~~~~ +%Warning-USERERROR: t/t_assert_comp_bad.v:15:7: : ... In instance t - 13 | $error("User compile-time error"); + 15 | $error; + | ^~~~~~ +%Warning-USERERROR: t/t_assert_comp_bad.v:16:7: User compile-time error + : ... In instance t + 16 | $error("User compile-time error"); + | ^~~~~~ +%Warning-USERFATAL: t/t_assert_comp_bad.v:17:7: + : ... In instance t + 17 | $fatal; | ^~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_assert_comp_bad.v b/test_regress/t/t_assert_comp_bad.v index 6f4146fdc..22434a8ff 100644 --- a/test_regress/t/t_assert_comp_bad.v +++ b/test_regress/t/t_assert_comp_bad.v @@ -7,10 +7,14 @@ module t (/*AUTOARG*/); if (1) begin + $info; $info("User compile-time info"); + $warning; $warning("User compile-time warning"); $warning(1); // Check can convert arguments to format + $error; $error("User compile-time error"); + $fatal; end endmodule diff --git a/test_regress/t/t_assert_implication.v b/test_regress/t/t_assert_implication.v index 9f2f96f91..4a93b6d08 100644 --- a/test_regress/t/t_assert_implication.v +++ b/test_regress/t/t_assert_implication.v @@ -14,11 +14,15 @@ module t (/*AUTOARG*/ Test test (/*AUTOINST*/ // Inputs - .clk (clk)); + .clk(clk), + .cyc(cyc)); always @ (posedge clk) begin if (cyc!=0) begin cyc <= cyc + 1; +`ifdef TEST_VERBOSE + $display("cyc=%0d", cyc); +`endif if (cyc==10) begin $write("*-* All Finished *-*\n"); $finish; @@ -30,7 +34,8 @@ endmodule module Test ( - input clk + input clk, + input integer cyc ); `ifdef FAIL_ASSERT_1 @@ -38,8 +43,35 @@ module Test @(posedge clk) 1 |-> 0 ) else $display("[%0t] wrong implication", $time); + + assert property ( + @(posedge clk) + 1 |=> 0 + ) else $display("[%0t] wrong implication", $time); + + assert property ( + @(posedge clk) + cyc%3==1 |=> cyc%3==1 + ) else $display("[%0t] wrong implication (step)", $time); + + assert property ( + @(posedge clk) + cyc%3==1 |=> cyc%3==0 + ) else $display("[%0t] wrong implication (step)", $time); + + assert property ( + @(posedge clk) disable iff (cyc == 3) + (cyc == 4) |=> 0 + ) else $display("[%0t] wrong implication (disable)", $time); + + assert property ( + @(posedge clk) disable iff (cyc == 6) + (cyc == 4) |=> 0 + ) else $display("[%0t] wrong implication (disable)", $time); + `endif + // Test |-> assert property ( @(posedge clk) 1 |-> 1 @@ -55,4 +87,44 @@ module Test 0 |-> 1 ); + // Test |=> + assert property ( + @(posedge clk) + 1 |=> 1 + ); + + assert property ( + @(posedge clk) + 0 |=> 0 + ); + + assert property ( + @(posedge clk) + 0 |=> 1 + ); + + // Test correct handling of time step in |=> + assert property ( + @(posedge clk) + cyc%3==1 |=> cyc%3==2 + ); + + // Test correct handling of disable iff + assert property ( + @(posedge clk) disable iff (cyc < 3) + 1 |=> cyc > 3 + ); + + // Test correct handling of disable iff in current cycle + assert property ( + @(posedge clk) disable iff (cyc == 4) + (cyc == 4) |=> 0 + ); + + // Test correct handling of disable iff in previous cycle + assert property ( + @(posedge clk) disable iff (cyc == 5) + (cyc == 4) |=> 0 + ); + endmodule diff --git a/test_regress/t/t_class_extends_this.out b/test_regress/t/t_class_extends_this.out index 364b929f1..87bd383a9 100644 --- a/test_regress/t/t_class_extends_this.out +++ b/test_regress/t/t_class_extends_this.out @@ -1,15 +1,3 @@ -%Error-UNSUPPORTED: t/t_class_extends_this.v:13:11: Unsupported: this - 13 | if (this.value != 1) $stop; - | ^~~~ -%Error: t/t_class_extends_this.v:13:11: Can't find definition of scope/variable: 'this' - 13 | if (this.value != 1) $stop; - | ^~~~ -%Error-UNSUPPORTED: t/t_class_extends_this.v:21:11: Unsupported: this - 21 | if (this.value != 2) $stop; - | ^~~~ -%Error: t/t_class_extends_this.v:21:11: Can't find definition of scope/variable: 'this' - 21 | if (this.value != 2) $stop; - | ^~~~ %Error-UNSUPPORTED: t/t_class_extends_this.v:22:11: Unsupported: super 22 | if (super.value != 1) $stop; | ^~~~~ @@ -28,12 +16,6 @@ %Error: t/t_class_extends_this.v:24:7: Can't find definition of scope/variable: 'super' 24 | super.value = 10; | ^~~~~ -%Error-UNSUPPORTED: t/t_class_extends_this.v:25:7: Unsupported: this - 25 | this.value = 20; - | ^~~~ -%Error: t/t_class_extends_this.v:25:7: Can't find definition of scope/variable: 'this' - 25 | this.value = 20; - | ^~~~ %Error-UNSUPPORTED: t/t_class_extends_this.v:26:11: Unsupported: super 26 | if (super.value != 10) $stop; | ^~~~~ diff --git a/test_regress/t/t_class_local.v b/test_regress/t/t_class_local.v index 0df89e7a7..fb7ff5ae9 100644 --- a/test_regress/t/t_class_local.v +++ b/test_regress/t/t_class_local.v @@ -13,6 +13,8 @@ class Cls; protected int m_prot = B; endclass + const Cls mod_c = new; + initial begin Cls c; if (c.A != 10) $stop; @@ -21,6 +23,8 @@ endclass c.m_loc = 10; if (c.m_loc != 10) $stop; if (c.m_prot != 20) $stop; + // + if (mod_c.A != 10) $stop; $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_class_new.v b/test_regress/t/t_class_new.v index 88b6fc787..f8642e6cf 100644 --- a/test_regress/t/t_class_new.v +++ b/test_regress/t/t_class_new.v @@ -8,7 +8,7 @@ class ClsNoArg; const int imembera; // Ok for new() to assign to a const function new(); imembera = 5; - endfunction + endfunction : new endclass class ClsArg; diff --git a/test_regress/t/t_class_packed.pl b/test_regress/t/t_class_packed.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_class_packed.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_class_packed.v b/test_regress/t/t_class_packed.v new file mode 100644 index 000000000..676557e43 --- /dev/null +++ b/test_regress/t/t_class_packed.v @@ -0,0 +1,40 @@ +// 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*/ + // Inputs + clk + ); + input clk; + + //TODO sub #(.WIDTH(1)) w1; + //TODO sub #(.WIDTH(2)) w2; + //TODO sub #(.WIDTH(3)) w3; + //TODO sub #(.WIDTH(4)) w4; + sub #(.WIDTH(5)) w5; + + always @ (posedge clk) begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule + +module sub (); + parameter WIDTH=5; // WIDTH >= 5 fails. WIDTH <= 4 passes + + typedef struct packed { + logic [WIDTH-1:0] data; + } [15:0] w_t; + + class WrReqQ; + w_t w; + endclass + + initial begin + if ($bits(w_t) != WIDTH * 16) $stop; + end + +endmodule diff --git a/test_regress/t/t_class_uses_this.pl b/test_regress/t/t_class_uses_this.pl new file mode 100755 index 000000000..aabcde63e --- /dev/null +++ b/test_regress/t/t_class_uses_this.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 2020 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_class_uses_this.v b/test_regress/t/t_class_uses_this.v new file mode 100644 index 000000000..d1a30b01a --- /dev/null +++ b/test_regress/t/t_class_uses_this.v @@ -0,0 +1,34 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 Rafal Kapuscik +// SPDX-License-Identifier: CC0-1.0 +// +class foo; + bit [3:0] addr; + function void set (bit [3:0] addr); + begin : body + this.addr = addr; + end : body + endfunction +endclass + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + foo bar; + foo baz; + initial begin + bar = new(); + baz = new(); + bar.set(4); +`ifdef TEST_VERBOSE + $display(bar.addr); + $display(baz.addr); +`endif + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_uses_this_bad.out b/test_regress/t/t_class_uses_this_bad.out new file mode 100644 index 000000000..05075f46a --- /dev/null +++ b/test_regress/t/t_class_uses_this_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_class_uses_this_bad.v:15:12: 'this' used outside class + 15 | this.addr = 2; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_class_uses_this_bad.pl b/test_regress/t/t_class_uses_this_bad.pl new file mode 100755 index 000000000..953874c82 --- /dev/null +++ b/test_regress/t/t_class_uses_this_bad.pl @@ -0,0 +1,23 @@ +#!/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 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( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +#execute( +# check_finished => 1, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_class_uses_this_bad.v b/test_regress/t/t_class_uses_this_bad.v new file mode 100644 index 000000000..1db9fade6 --- /dev/null +++ b/test_regress/t/t_class_uses_this_bad.v @@ -0,0 +1,19 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 Rafal Kapuscik +// SPDX-License-Identifier: CC0-1.0 +// + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + bit [3:0] addr; + initial begin + this.addr = 2; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_convert2string.pl b/test_regress/t/t_convert2string.pl new file mode 100755 index 000000000..89a4e77d9 --- /dev/null +++ b/test_regress/t/t_convert2string.pl @@ -0,0 +1,20 @@ +#!/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( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_convert2string.v b/test_regress/t/t_convert2string.v new file mode 100644 index 000000000..990dfd2fc --- /dev/null +++ b/test_regress/t/t_convert2string.v @@ -0,0 +1,73 @@ +// 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])); + + + always @ (posedge clk) begin + if (cyc!=0) begin + cyc <= cyc + 1; + if (cyc==10) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + end + +endmodule + +package lpcm_pkg; + class lpcm_tr; + int latency; + int sample; + + function new(); + latency = 0; + sample = 0; + endfunction + + function string convert2string(); + return $sformatf("sample=0x%0h latency=%0d", sample, latency); + endfunction + endclass +endpackage + +//internal error happens when lpcm_pkg is not imported +//import lpcm_pkg::*; + +module Test (/*AUTOARG*/ + // Inputs + clk, in + ); + + input clk; + input [31:0] in; + + initial begin + string s; + lpcm_pkg::lpcm_tr tr; // internal error happens when lpcm_pkg is not imported + tr = new(); + tr.sample = 1; + tr.latency = 2; + s = tr.convert2string(); + $display("hello %s", tr.convert2string()); + if (s != "sample=0x1 latency=2") $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_cover_lib.pl b/test_regress/t/t_cover_lib.pl new file mode 100755 index 000000000..9d7305ac5 --- /dev/null +++ b/test_regress/t/t_cover_lib.pl @@ -0,0 +1,31 @@ +#!/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(vlt => 1); + +compile( + v_flags2 => ["--coverage t/t_cover_lib_c.cpp"], + verilator_flags2 => ["--exe -Wall -Wno-DECLFILENAME"], + make_flags => 'CPPFLAGS_ADD=-DTEST_OBJ_DIR="'.$Self->{obj_dir}.'"', + make_top_shell => 0, + make_main => 0, + ); + +execute( + check_finished => 1, + ); + +files_identical_sorted("$Self->{obj_dir}/coverage1.dat", "t/t_cover_lib_1.out"); +files_identical_sorted("$Self->{obj_dir}/coverage2.dat", "t/t_cover_lib_2.out"); +files_identical_sorted("$Self->{obj_dir}/coverage3.dat", "t/t_cover_lib_3.out"); +files_identical_sorted("$Self->{obj_dir}/coverage4.dat", "t/t_cover_lib_4.out"); + +ok(1); +1; diff --git a/test_regress/t/t_cover_lib.v b/test_regress/t/t_cover_lib.v new file mode 100644 index 000000000..1d95829b9 --- /dev/null +++ b/test_regress/t/t_cover_lib.v @@ -0,0 +1,10 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2017 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 + +module t (/*AUTOARG*/); +endmodule diff --git a/test_regress/t/t_cover_lib_1.out b/test_regress/t/t_cover_lib_1.out new file mode 100644 index 000000000..d757bf25a --- /dev/null +++ b/test_regress/t/t_cover_lib_1.out @@ -0,0 +1,4 @@ +# SystemC::Coverage-3 +C 'f../../t/t_cover_lib_c.cppl44pagesp_user/t_cover_lib_cokept_onehmain' 100 +C 'f../../t/t_cover_lib_c.cppl45pagesp_user/t_cover_lib_cokept_twohmain' 210 +C 'f../../t/t_cover_lib_c.cppl46pagesp_user/t_cover_lib_colost_threehmain' 220 diff --git a/test_regress/t/t_cover_lib_2.out b/test_regress/t/t_cover_lib_2.out new file mode 100644 index 000000000..42ec9a18e --- /dev/null +++ b/test_regress/t/t_cover_lib_2.out @@ -0,0 +1,3 @@ +# SystemC::Coverage-3 +C 'f../../t/t_cover_lib_c.cppl44pagesp_user/t_cover_lib_cokept_onehmain' 100 +C 'f../../t/t_cover_lib_c.cppl45pagesp_user/t_cover_lib_cokept_twohmain' 210 diff --git a/test_regress/t/t_cover_lib_3.out b/test_regress/t/t_cover_lib_3.out new file mode 100644 index 000000000..78bddf206 --- /dev/null +++ b/test_regress/t/t_cover_lib_3.out @@ -0,0 +1,3 @@ +# SystemC::Coverage-3 +C 'f../../t/t_cover_lib_c.cppl44pagesp_user/t_cover_lib_cokept_onehmain' 0 +C 'f../../t/t_cover_lib_c.cppl45pagesp_user/t_cover_lib_cokept_twohmain' 0 diff --git a/test_regress/t/t_cover_lib_4.out b/test_regress/t/t_cover_lib_4.out new file mode 100644 index 000000000..8b8f255e5 --- /dev/null +++ b/test_regress/t/t_cover_lib_4.out @@ -0,0 +1 @@ +# SystemC::Coverage-3 diff --git a/test_regress/t/t_cover_lib_c.cpp b/test_regress/t/t_cover_lib_c.cpp new file mode 100644 index 000000000..8b288fad9 --- /dev/null +++ b/test_regress/t/t_cover_lib_c.cpp @@ -0,0 +1,62 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2009-2017 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 +// +//************************************************************************* + +#include +#include +#include +#include "svdpi.h" + +#include "verilated_cov.h" + +#include VM_PREFIX_INCLUDE + +double sc_time_stamp() { return 0; } + +//====================================================================== + +int failure = 0; + +#define CHECK_RESULT_HEX(got, exp) \ + do { \ + if ((got) != (exp)) { \ + std::cout << std::dec << "%Error: " << __FILE__ << ":" << __LINE__ << std::hex \ + << ": GOT=" << (got) << " EXP=" << (exp) << std::endl; \ + failure = __LINE__; \ + } \ + } while (0) + +//====================================================================== + +const char* name() { return "main"; } + +int main() { + vluint32_t covers[1]; + vluint64_t coverw[2]; + + VL_COVER_INSERT(&covers[0], "comment", "kept_one"); + VL_COVER_INSERT(&coverw[0], "comment", "kept_two"); + VL_COVER_INSERT(&coverw[1], "comment", "lost_three"); + + covers[0] = 100; + coverw[0] = 210; + coverw[1] = 220; + + VerilatedCov::write(VL_STRINGIFY(TEST_OBJ_DIR) "/coverage1.dat"); + VerilatedCov::clearNonMatch("kept_"); + VerilatedCov::write(VL_STRINGIFY(TEST_OBJ_DIR) "/coverage2.dat"); + VerilatedCov::zero(); + VerilatedCov::write(VL_STRINGIFY(TEST_OBJ_DIR) "/coverage3.dat"); + VerilatedCov::clear(); + VerilatedCov::write(VL_STRINGIFY(TEST_OBJ_DIR) "/coverage4.dat"); + + printf("*-* All Finished *-*\n"); + exit(failure ? 10 : 0); +} diff --git a/test_regress/t/t_debug_emitv.out b/test_regress/t/t_debug_emitv.out new file mode 100644 index 000000000..72286aad6 --- /dev/null +++ b/test_regress/t/t_debug_emitv.out @@ -0,0 +1,206 @@ +module Vt_debug_emitv; + input logic clk; + input logic in; + signed int [31:0] [0:2] t.array; + logic logic [15:0] t.pubflat; + logic logic [15:0] t.pubflat_r; + int signed int [31:0] t.fd; + int signed int [31:0] t.i; + int signed int [31:0] t.cyc; + int signed int [31:0] t.fo; + int signed int [31:0] t.sum; + string string t.str; + int signed int [31:0] t._Vpast_0_0; + int signed int [31:0] t._Vpast_1_0; + int signed int [31:0] t.unnamedblk3.i; + @(*)@([settle])@([initial])@(posedge clk)@(negedge + clk)always @( + *)@( + [settle])@( + [initial])@( + posedge + clk)@( + negedge + clk) begin + $display("stmt"); + end + always @([settle])@([initial])@(posedge clk)@(negedge + clk) begin + $display("stmt"); + end + initial begin + // Function: f + $write("stmt\nstmt 0 99\n"); + // Function: t + $display("stmt"); + // Function: f + $write("stmt\nstmt 1 -1\n"); + // Function: t + $display("stmt"); + // Function: f + $display("stmt"); + $display("stmt 2 -2"); + // Function: t + $display("stmt"); + $display("stmt"); + end + + ???? // CFUNC '_final_TOP' + $_CSTMT(Vt_debug_emitv* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp; + ); + // FINAL + $display("stmt"); + always @(posedge clk)@(negedge clk) begin + $display("posedge clk"); + end + always @(posedge clk)@(negedge clk) begin + __Vdly__t.pubflat_r <= t.pubflat; + end + always @(posedge clk)@(negedge clk) begin + __Vdly__t.cyc <= (32'sh1 + t.cyc); + t.fo = t.cyc; + // Function: inc + __Vtask_t.sub.inc__2__i = t.fo; + __Vtask_t.sub.inc__2__o = (32'h1 + __Vtask_t.sub.inc__2__i[31:1]); + t.sum = __Vtask_t.sub.inc__2__o; + // Function: f + __Vfunc_t.sub.f__3__v = t.sum; + begin : label0 + begin : label0 + if ((32'sh0 == __Vfunc_t.sub.f__3__v)) begin + __Vfunc_t.sub.f__3__Vfuncout = 32'sh21; + disable label0; + end + __Vfunc_t.sub.f__3__Vfuncout = (32'h1 + + __Vfunc_t.sub.f__3__v[2]); + disable label0; + end + end + t.sum = __Vfunc_t.sub.f__3__Vfuncout; + $display("[%0t] sum = %~", $timet.sum, t.sum); + $display("a?= $d%d", ($c(32'sh1) ? $c(32'sh14) + : $c(32'sh1e))); + $c(;); + $display("%d", $c(0)); + $fopen(72'h2f6465762f6e756c6c); + $fclose(t.fd); + $fopen(72'h2f6465762f6e756c6c, 8'h72); + $fgetc(t.fd); + $fflush(t.fd); + $fscanf(t.fd, "%d", t.sum); + ; + $fdisplay(32'h69203d20, "%d", t.sum); + $fwrite(t.fd, "hello"); + $readmemh(t.fd, t.array); + $readmemh(t.fd, t.array, 32'sh0); + $readmemh(t.fd, t.array, 32'sh0, 32'sh0); + t.sum = 32'sh0; + t.unnamedblk3.i = 32'sh0; + begin : label0 + while ((t.unnamedblk3.i < t.cyc)) begin + t.sum = (t.sum + t.unnamedblk3.i); + if ((32'sha < t.sum)) begin + disable label0; + end + else begin + t.sum = (32'sh1 + t.sum); + end + t.unnamedblk3.i = (32'h1 + t.unnamedblk3.i); + end + end + if ((32'sh63 == t.cyc)) begin + $finish; + end + if ((32'sh64 == t.cyc)) begin + $stop; + end + if (in) begin + $display("1"); + end + else begin + $display("default"); + end + if (in) begin + $display("1"); + end + else begin + $display("default"); + end + if (in) begin + $display("1"); + end + else begin + $display("default"); + end + if (in) begin + $display("1"); + end + else begin + $display("default"); + end + if (in) begin + $display("1"); + end + else begin + $display("0"); + end + priority if (in) begin + $display("1"); + end + else begin + $display("0"); + end + unique if (in) begin + $display("1"); + end + else begin + $display("0"); + end + unique0 if (in) begin + $display("1"); + end + else begin + $display("0"); + end + $display("%d%d", t._Vpast_0_0t._Vpast_1_0, + t._Vpast_1_0); + t.str = $sformatf("cyc=%~", t.cyc); + ; + $display("str = %@", t.str); + $display("%% [%t] [%^] to=%o td=%d", $time$realtime + $time$time, $realtime$time$time, $time + $time, $time); + $sscanf(40'h666f6f3d35, "foo=%d", t.i); + ; + if ((32'sh5 != t.i)) begin + $stop; + end + end + /*verilator public_flat_rw @(posedge clk)@(negedge + clk) t.pubflat*/ + always @(posedge clk)@(negedge clk) begin + __Vdly__t._Vpast_0_0 <= t.cyc; + end + always @(posedge clk)@(negedge clk) begin + __Vdly__t._Vpast_1_0 <= t.cyc; + end + __Vdly__t._Vpast_1_0 = t._Vpast_1_0; + t._Vpast_1_0 = __Vdly__t._Vpast_1_0; + __Vdly__t._Vpast_0_0 = t._Vpast_0_0; + t._Vpast_0_0 = __Vdly__t._Vpast_0_0; + __Vdly__t.cyc = t.cyc; + t.cyc = __Vdly__t.cyc; + __Vdly__t.pubflat_r = t.pubflat_r; + t.pubflat_r = __Vdly__t.pubflat_r; + always @(negedge clk) begin + $display("negedge clk, pfr = %x", t.pubflat_r); + end + int signed int [31:0] __Vtask_t.sub.inc__2__i; + int signed int [31:0] __Vtask_t.sub.inc__2__o; + int signed int [31:0] __Vfunc_t.sub.f__3__Vfuncout; + int signed int [31:0] __Vfunc_t.sub.f__3__v; + logic logic [15:0] __Vdly__t.pubflat_r; + int signed int [31:0] __Vdly__t.cyc; + int signed int [31:0] __Vdly__t._Vpast_0_0; + int signed int [31:0] __Vdly__t._Vpast_1_0; +endmodule diff --git a/test_regress/t/t_debug_emitv.pl b/test_regress/t/t_debug_emitv.pl new file mode 100755 index 000000000..3532795bc --- /dev/null +++ b/test_regress/t/t_debug_emitv.pl @@ -0,0 +1,22 @@ +#!/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(vlt => 1); + +lint( + # We also have dump-tree turned on, so hit a lot of AstNode*::dump() functions + # Likewise XML + v_flags => ["--lint-only --dump-treei 9 --debug-emitv"], + ); + +files_identical("$Self->{obj_dir}/$Self->{VM_PREFIX}__preorder.v", $Self->{golden_filename}); + +ok(1); +1; diff --git a/test_regress/t/t_debug_emitv.v b/test_regress/t/t_debug_emitv.v new file mode 100644 index 000000000..d1ae29ee0 --- /dev/null +++ b/test_regress/t/t_debug_emitv.v @@ -0,0 +1,154 @@ +// DESCRIPTION: Verilator: Dotted reference that uses another dotted reference +// as the select expression +// +// 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 (/*AUTOARG*/ + // Inputs + clk, in + ); + input clk; + input in; + + // verilator lint_off UNPACKED + + typedef enum { + ZERO, + ONE = 1 + } e_t; + + typedef struct packed { + e_t a; + } ps_t; + typedef struct { + logic signed [2:0] a; + } us_t; + + const ps_t ps[3]; + us_t us; + + int array[3]; + initial array = '{1,2,3}; + + reg [15:0] pubflat /*verilator public_flat_rw @(posedge clk) */; + + reg [15:0] pubflat_r; + wire [15:0] pubflat_w = pubflat; + int fd; + int i; + + task t; + $display("stmt"); + endtask + function int f(input int v); + $display("stmt"); + return v == 0 ? 99 : ~v + 1; + endfunction + + sub sub(); + + initial begin + int other; + begin //unnamed + for (int i = 0; i < 3; ++i) begin + other = f(i); + $display("stmt %d %d", i, other); + t(); + end + end + begin : named + $display("stmt"); + end : named + end + final begin + $display("stmt"); + end + + always @ (in) begin + $display("stmt"); + end + always @ (posedge clk) begin + $display("posedge clk"); + pubflat_r <= pubflat_w; + end + always @ (negedge clk) begin + $display("negedge clk, pfr = %x", pubflat_r); + end + + int cyc; + int fo; + int sum; + string str; + always_ff @ (posedge clk) begin + cyc <= cyc + 1; + fo = cyc; + sub.inc(fo, sum); + sum = sub.f(sum); + $display("[%0t] sum = %d", $time, sum); + $display("a?= $d", $c(1) ? $c32(20) : $c32(30)); + + $c(";"); + $display("%d", $c("0")); + fd = $fopen("/dev/null"); + $fclose(fd); + fd = $fopen("/dev/null", "r"); + $fgetc(fd); // stmt + $fflush(fd); + $fscanf(fd, "%d", sum); + $fdisplay("i = ", sum); + $fwrite(fd, "hello"); + $readmemh(fd, array); + $readmemh(fd, array, 0); + $readmemh(fd, array, 0, 0); + + sum = 0; + for (int i = 0; i < cyc; ++i) begin + sum += i; + if (sum > 10) break; + else sum += 1; + end + if (cyc == 99) $finish; + if (cyc == 100) $stop; + + case (in) // synopsys full_case parallel_case + 1: $display("1"); + default: $display("default"); + endcase + priority case (in) + 1: $display("1"); + default: $display("default"); + endcase + unique case (in) + 1: $display("1"); + default: $display("default"); + endcase + unique0 case (in) + 1: $display("1"); + default: $display("default"); + endcase + if (in) $display("1"); else $display("0"); + priority if (in) $display("1"); else $display("0"); + unique if (in) $display("1"); else $display("0"); + unique0 if (in) $display("1"); else $display("0"); + + $display($past(cyc), $past(cyc, 1)); + + str = $sformatf("cyc=%d", cyc); + $display("str = %s", str); + $display("%% [%t] [%t] to=%o td=%d", $time, $realtime, $time, $time); + $sscanf("foo=5", "foo=%d", i); + if (i != 5) $stop; + end +endmodule + +module sub(); + task inc(input int i, output int o); + o = {1'b0, i[31:1]} + 32'd1; + endtask + function int f(input int v); + if (v == 0) return 33; + return {31'd0, v[2]} + 32'd1; + endfunction +endmodule diff --git a/test_regress/t/t_debug_emitv_addrids.pl b/test_regress/t/t_debug_emitv_addrids.pl new file mode 100755 index 000000000..40070d6e5 --- /dev/null +++ b/test_regress/t/t_debug_emitv_addrids.pl @@ -0,0 +1,22 @@ +#!/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(vlt => 1); + +top_filename("t/t_debug_emitv.v"); + +lint( + # We also have dump-tree turned on, so hit a lot of AstNode*::dump() functions + # Likewise XML + v_flags => ["--lint-only --dump-treei 9 --dump-tree-addrids"], + ); + +ok(1); +1; diff --git a/test_regress/t/t_display.out b/test_regress/t/t_display.out index 3825f5ad7..9b2b995ce 100644 --- a/test_regress/t/t_display.out +++ b/test_regress/t/t_display.out @@ -44,9 +44,13 @@ [0] %6s=: !: %6s=: what!: %6s=: hmmm!1234: [0] %8s=: sv-str: d: 12 12 + h: 00c 00c + o: 014 014 + b: 000001100 000001100 + [0] hello, from a very long string. Percent %s are literally substituted in. hello, from a concatenated string. hello, from a concatenated format string [0]. diff --git a/test_regress/t/t_display.v b/test_regress/t/t_display.v index c13999c87..073268617 100644 --- a/test_regress/t/t_display.v +++ b/test_regress/t/t_display.v @@ -135,9 +135,13 @@ module t; // Displays without format, must use default $write("d: "); $write(nine); $write(" "); $display(nine); + $write; $display; $writeh("h: "); $writeh(nine); $writeh(" "); $displayh(nine); + $writeh; $displayh; $writeo("o: "); $writeo(nine); $writeo(" "); $displayo(nine); + $writeb; $displayb; $writeb("b: "); $writeb(nine); $writeb(" "); $displayb(nine); + $writeo; $displayo; $display("[%0t] %s%s%s", $time, "hel", "lo, fr", "om a very long string. Percent %s are literally substituted in."); diff --git a/test_regress/t/t_dist_error_format.pl b/test_regress/t/t_dist_error_format.pl index 546883f47..329ab3096 100755 --- a/test_regress/t/t_dist_error_format.pl +++ b/test_regress/t/t_dist_error_format.pl @@ -38,6 +38,7 @@ sub formats { my $lineno = 0; foreach my $line (split /\n/, $wholefile) { ++$lineno; + $line =~ s/(\$display|\$write).*\".*%(Error|Warning)//; if ($line =~ /(Error|Warning)/) { # These formats are documented in bin/verilator # Error with fileline diff --git a/test_regress/t/t_dpi_context_c.cpp b/test_regress/t/t_dpi_context_c.cpp index 3204c9bea..1447ab083 100644 --- a/test_regress/t/t_dpi_context_c.cpp +++ b/test_regress/t/t_dpi_context_c.cpp @@ -74,6 +74,7 @@ int dpic_line() { printf("%%Warning: svGetCallerInfo failed\n"); return 0; } + if (svGetCallerInfo(nullptr, nullptr)) {} // Check doesn't segflt return lineno; } diff --git a/test_regress/t/t_dpi_export_context2_bad.cpp b/test_regress/t/t_dpi_export_context2_bad.cpp new file mode 100644 index 000000000..77ce4668c --- /dev/null +++ b/test_regress/t/t_dpi_export_context2_bad.cpp @@ -0,0 +1,44 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +// +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2010 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +#include +#include VM_PREFIX_INCLUDE + +//====================================================================== + +#include "Vt_dpi_export_context2_bad__Dpi.h" + +//====================================================================== + +unsigned int main_time = 0; + +double sc_time_stamp() { return main_time; } + +VM_PREFIX* topp = nullptr; + +int main(int argc, char* argv[]) { + topp = new VM_PREFIX; + + Verilated::debug(0); + + topp->eval(); + return 1; +} +int dpii_task() { + + // Check DPI warnings + svScope scope = svGetScope(); // Will warn + if (scope) {} // Unused + const char* filenamep = ""; + int lineno = 0; + svGetCallerInfo(&filenamep, &lineno); // Will warn + if (filenamep && lineno) {} // Unused + + dpix_task(); + return 0; +} diff --git a/test_regress/t/t_dpi_export_context2_bad.out b/test_regress/t/t_dpi_export_context2_bad.out new file mode 100644 index 000000000..c01b0dec6 --- /dev/null +++ b/test_regress/t/t_dpi_export_context2_bad.out @@ -0,0 +1,4 @@ +%Warning: DPI C Function called by Verilog DPI import with missing 'context' keyword. +%Warning: DPI C Function called by Verilog DPI import with missing 'context' keyword. +%Error: unknown:0: Testbench C called 'dpix_task' but scope wasn't set, perhaps due to dpi import call without 'context', or missing svSetScope. See IEEE 1800-2017 35.5.3. +Aborting... diff --git a/test_regress/t/t_dpi_export_context2_bad.pl b/test_regress/t/t_dpi_export_context2_bad.pl new file mode 100755 index 000000000..93b856ef1 --- /dev/null +++ b/test_regress/t/t_dpi_export_context2_bad.pl @@ -0,0 +1,24 @@ +#!/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( + v_flags2 => ["--exe $Self->{t_dir}/t_dpi_export_context2_bad.cpp"], + make_main => 0, + ); + +execute( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_dpi_export_context2_bad.v b/test_regress/t/t_dpi_export_context2_bad.v new file mode 100644 index 000000000..5002b95e2 --- /dev/null +++ b/test_regress/t/t_dpi_export_context2_bad.v @@ -0,0 +1,19 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2020 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 + +module t; + export "DPI-C" task dpix_task; + sub sub (); + task dpix_task(); + $write("Hello in %m\n"); + endtask +endmodule +module sub; + import "DPI-C" task dpii_task; + initial dpii_task; +endmodule diff --git a/test_regress/t/t_dpi_import_c.cpp b/test_regress/t/t_dpi_import_c.cpp index ebcbedef1..5a174cd67 100644 --- a/test_regress/t/t_dpi_import_c.cpp +++ b/test_regress/t/t_dpi_import_c.cpp @@ -189,7 +189,9 @@ int dpii_t_void() { return svIsDisabledState(); } int dpii_t_void_context() { return svIsDisabledState(); } int dpii_t_int(int i, int* o) { *o = i; - return svIsDisabledState(); // Tasks generally need this + bool disabled = svIsDisabledState(); // Tasks generally need this + svAckDisabledState(); + return disabled; } #endif diff --git a/test_regress/t/t_dpi_lib_c.cpp b/test_regress/t/t_dpi_lib_c.cpp index bb214c594..b800b17fc 100644 --- a/test_regress/t/t_dpi_lib_c.cpp +++ b/test_regress/t/t_dpi_lib_c.cpp @@ -74,14 +74,32 @@ void dpii_lib_bit_check() { CHECK_RESULT_HEX(bv[1], 0xa7a6a5ad); CHECK_RESULT_HEX(bv[2], 0xabaaa9a8); - svBitVecVal btmp[1]; + svBitVecVal btmp[2]; svGetPartselBit(btmp, bv, 40, 8); CHECK_RESULT_HEX(btmp[0], 0xa5); + svGetPartselBit(btmp, bv, 32, 32); + CHECK_RESULT_HEX(btmp[0], 0xa7a6a5ad); + svGetPartselBit(btmp, bv, 48, 40); + CHECK_RESULT_HEX(btmp[0], 0xa9a8a7a6); + CHECK_RESULT_HEX(btmp[1], 0xaa); + btmp[0] = 0xa5; svPutPartselBit(bv, btmp[0], 48, 8); CHECK_RESULT_HEX(bv[0], 0xa3a2a1a0); CHECK_RESULT_HEX(bv[1], 0xa7a5a5ad); CHECK_RESULT_HEX(bv[2], 0xabaaa9a8); + + btmp[0] = 0x11223344; + svPutPartselBit(bv, btmp[0], 32, 32); + CHECK_RESULT_HEX(bv[0], 0xa3a2a1a0); + CHECK_RESULT_HEX(bv[1], 0x11223344); + CHECK_RESULT_HEX(bv[2], 0xabaaa9a8); + + btmp[0] = 0x99887766; + svPutPartselBit(bv, btmp[0], 24, 24); + CHECK_RESULT_HEX(bv[0], 0x66a2a1a0); + CHECK_RESULT_HEX(bv[1], 0x11228877); + CHECK_RESULT_HEX(bv[2], 0xabaaa9a8); } void dpii_lib_logic_check() { @@ -112,11 +130,21 @@ void dpii_lib_logic_check() { CHECK_RESULT_HEX(lv[1].bval, 0xc7c6c5c8); CHECK_RESULT_HEX(lv[2].bval, 0xcbcac9c8); - svLogicVecVal ltmp[1]; + svLogicVecVal ltmp[2]; svGetPartselLogic(ltmp, lv, 40, 8); CHECK_RESULT_HEX(ltmp[0].aval, 0xb5); CHECK_RESULT_HEX(ltmp[0].bval, 0xc5); + svGetPartselLogic(ltmp, lv, 32, 32); + CHECK_RESULT_HEX(ltmp[0].aval, 0xb7b6b5bd); + CHECK_RESULT_HEX(ltmp[0].bval, 0xc7c6c5c8); + svGetPartselLogic(ltmp, lv, 48, 40); + CHECK_RESULT_HEX(ltmp[0].aval, 0xb9b8b7b6); + CHECK_RESULT_HEX(ltmp[0].bval, 0xc9c8c7c6); + CHECK_RESULT_HEX(ltmp[1].aval, 0xba); + CHECK_RESULT_HEX(ltmp[1].bval, 0xca); + ltmp[0].aval = 0xb5; + ltmp[0].bval = 0xc5; svPutPartselLogic(lv, ltmp[0], 48, 8); CHECK_RESULT_HEX(lv[0].aval, 0xb3b2b1b0); CHECK_RESULT_HEX(lv[1].aval, 0xb7b5b5bd); @@ -124,6 +152,26 @@ void dpii_lib_logic_check() { CHECK_RESULT_HEX(lv[0].bval, 0xc3c2c1c0); CHECK_RESULT_HEX(lv[1].bval, 0xc7c5c5c8); CHECK_RESULT_HEX(lv[2].bval, 0xcbcac9c8); + + ltmp[0].aval = 0x11223344; + ltmp[0].bval = 0x81828384; + svPutPartselLogic(lv, ltmp[0], 32, 32); + CHECK_RESULT_HEX(lv[0].aval, 0xb3b2b1b0); + CHECK_RESULT_HEX(lv[1].aval, 0x11223344); + CHECK_RESULT_HEX(lv[2].aval, 0xbbbab9b8); + CHECK_RESULT_HEX(lv[0].bval, 0xc3c2c1c0); + CHECK_RESULT_HEX(lv[1].bval, 0x81828384); + CHECK_RESULT_HEX(lv[2].bval, 0xcbcac9c8); + + ltmp[0].aval = 0x99887766; + ltmp[0].bval = 0x89888786; + svPutPartselLogic(lv, ltmp[0], 24, 24); + CHECK_RESULT_HEX(lv[0].aval, 0x66b2b1b0); + CHECK_RESULT_HEX(lv[1].aval, 0x11228877); + CHECK_RESULT_HEX(lv[2].aval, 0xbbbab9b8); + CHECK_RESULT_HEX(lv[0].bval, 0x86c2c1c0); + CHECK_RESULT_HEX(lv[1].bval, 0x81828887); + CHECK_RESULT_HEX(lv[2].bval, 0xcbcac9c8); } //====================================================================== diff --git a/test_regress/t/t_flag_f.vc b/test_regress/t/t_flag_f.vc index 44e4076c8..88883245c 100644 --- a/test_regress/t/t_flag_f.vc +++ b/test_regress/t/t_flag_f.vc @@ -1,4 +1,5 @@ // Test that environment substitutions work +# This is also a comment (in several simulators) -f $VERILATOR_ROOT/test_regress/t/t_flag_f__2.vc // Env var with .v file, and parens // Double slash below is intentional, as allowed in other tools diff --git a/test_regress/t/t_hier_block.v b/test_regress/t/t_hier_block.v index d4701b2ac..26c722cb6 100644 --- a/test_regress/t/t_hier_block.v +++ b/test_regress/t/t_hier_block.v @@ -9,6 +9,10 @@ `define HIER_BLOCK /*verilator hier_block*/ `endif +`ifndef PROTLIB_TOP +`timescale 1ns/1ps +`endif + interface byte_ifs(input clk); logic [7:0] data; modport sender(input clk, output data); diff --git a/test_regress/t/t_hier_block_cmake.pl b/test_regress/t/t_hier_block_cmake.pl index 24760fe3c..7f7c28cba 100755 --- a/test_regress/t/t_hier_block_cmake.pl +++ b/test_regress/t/t_hier_block_cmake.pl @@ -13,38 +13,28 @@ clean_objs(); scenarios(simulator => 1); top_filename("t/t_hier_block.v"); -# Travis environment offers 2 VCPUs, 2 thread setting causes the following warning. -# %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads. -# So use 6 threads here though it's not optimal in performace wise, but ok. -compile( - verilator_make_gmake => 0, - verilator_make_cmake => 1, - v_flags2 => ['t/t_hier_block.cpp'], - verilator_flags2 => ['--stats', - '--hierarchical', - '--CFLAGS', "'-pipe -DCPP_MACRO=cplusplus '", - '--make cmake', - ($Self->{vltmt} ? ' --threads 6' : '')], +if (!$Self->have_cmake) { + $Self->skip("Test requires CMake; ignore error since not available or version too old\n"); +} else { + run(logfile => "$Self->{obj_dir}/cmake.log", + cmd => ['cd "' . $Self->{obj_dir} . '" && cmake ' . $Self->{t_dir} . '/t_hier_block_cmake', + "-DCMAKE_PREFIX_PATH=$ENV{VERILATOR_ROOT}", + ($Self->{vltmt} ? '-DTEST_THREADS=6' : '') + ]); + + run(logfile => "$Self->{obj_dir}/build.log", + cmd => ['cd "' . $Self->{obj_dir} . '" && cmake --build', '.'] ); -if (!$Self->have_cmake) { - skip("cmake is not installed"); -} else { - my $cmakecache = $Self->{obj_dir}."/CMakeCache.txt"; - if (! -e $cmakecache) { - error("$cmakecache does not exist.") - } - - execute( - check_finished => 1, - ); - -file_grep($Self->{obj_dir} . "/Vsub0/sub0.sv", /^module\s+(\S+)\s+/, "sub0"); -file_grep($Self->{obj_dir} . "/Vsub1/sub1.sv", /^module\s+(\S+)\s+/, "sub1"); -file_grep($Self->{obj_dir} . "/Vsub2/sub2.sv", /^module\s+(\S+)\s+/, "sub2"); -file_grep($Self->{obj_dir} . '/Vt_hier_block_cmake__stats.txt', qr/HierBlock,\s+Hierarchical blocks\s+(\d+)/i, 10); -file_grep($Self->{run_log_filename}, qr/MACRO:(\S+) is defined/i, "cplusplus"); - + run(logfile => "$Self->{obj_dir}/run.log", + cmd => ['cd "' . $Self->{obj_dir} . '" && ./t_hier_block_cmake', '.'] + ); + my $target_dir = $Self->{obj_dir} .'/CMakeFiles/t_hier_block_cmake.dir/Vt_hier_block.dir/'; + file_grep($target_dir . 'Vsub0/sub0.sv', /^module\s+(\S+)\s+/, "sub0"); + file_grep($target_dir . 'Vsub1/sub1.sv', /^module\s+(\S+)\s+/, "sub1"); + file_grep($target_dir . 'Vsub2/sub2.sv', /^module\s+(\S+)\s+/, "sub2"); + file_grep($target_dir . 'Vt_hier_block__stats.txt', qr/HierBlock,\s+Hierarchical blocks\s+(\d+)/i, 10); + file_grep($Self->{obj_dir} . '/run.log', qr/MACRO:(\S+) is defined/i, "cplusplus"); } ok(1); diff --git a/test_regress/t/t_hier_block_cmake/CMakeLists.txt b/test_regress/t/t_hier_block_cmake/CMakeLists.txt new file mode 100644 index 000000000..6e7c91bbe --- /dev/null +++ b/test_regress/t/t_hier_block_cmake/CMakeLists.txt @@ -0,0 +1,27 @@ +###################################################################### +# +# DESCRIPTION: CMake script for t_hier_block_cmake +# +# Copyright 2003-2020 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 +# +###################################################################### + +cmake_minimum_required (VERSION 3.8) +project (t_hier_block_cmake) + +find_package(verilator REQUIRED) + +add_executable(t_hier_block_cmake main.cpp ../t_hier_block.cpp) + +if(TEST_THREADS) + set(VERILATOR_OPTIONS "${VERILATOR_OPTIONS}" --threads ${TEST_THREADS}) +endif() +set(VERILATOR_OPTIONS "${VERILATOR_OPTIONS}" --hierarchical --stats --CFLAGS "-pipe -DCPP_MACRO=cplusplus") + +verilate(t_hier_block_cmake VERILATOR_ARGS ${VERILATOR_OPTIONS} SOURCES + ../t_hier_block.v ) + diff --git a/test_regress/t/t_hier_block_cmake/main.cpp b/test_regress/t/t_hier_block_cmake/main.cpp new file mode 100644 index 000000000..b26551f4d --- /dev/null +++ b/test_regress/t/t_hier_block_cmake/main.cpp @@ -0,0 +1,27 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2020 by Yutetsu TAKATSUKASA. 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 +// +//************************************************************************* + +#include +#include "Vt_hier_block.h" + +int main(int argc, char *argv[]) { + std::unique_ptr top{new Vt_hier_block("top")}; + Verilated::commandArgs(argc, argv); + for (int i = 0; i < 100 && !Verilated::gotFinish(); ++i) { + top->eval(); + top->clk ^= 1; + } + if (!Verilated::gotFinish()) { + vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish"); + } + top->final(); + return 0; +} diff --git a/test_regress/t/t_hier_block_libmod.pl b/test_regress/t/t_hier_block_libmod.pl new file mode 100755 index 000000000..6fcdd000e --- /dev/null +++ b/test_regress/t/t_hier_block_libmod.pl @@ -0,0 +1,23 @@ +#!/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(vlt_all => 1); + +compile( + verilator_flags2 => ['--hierarchical', + '-y', $Self->{t_dir} . '/t_flag_relinc_dir/chip', + '+incdir+'. $Self->{t_dir} . '/t_flag_relinc_dir/include'], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_hier_block_libmod.v b/test_regress/t/t_hier_block_libmod.v new file mode 100644 index 000000000..deaeb9fe2 --- /dev/null +++ b/test_regress/t/t_hier_block_libmod.v @@ -0,0 +1,14 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2020 by Yutetsu TAKATSUKASA + +module t; + t_flag_relinc_sub i_t_flag_relinc_sub(); +endmodule + +`ifdef VERILATOR +`verilator_config +hier_block -module "t_flag_relinc_sub" +`verilog +`endif diff --git a/test_regress/t/t_hier_task.pl b/test_regress/t/t_hier_task.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_hier_task.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_hier_task.v b/test_regress/t/t_hier_task.v new file mode 100644 index 000000000..dfd3f7948 --- /dev/null +++ b/test_regress/t/t_hier_task.v @@ -0,0 +1,48 @@ +// DESCRIPTION: Verilator: Test for issue #2267 +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2020 by James Pallister. +// SPDX-License-Identifier: CC0-1.0 + +module mod_a; + mod_inner u_inner; + mod_a_mon u_a_mon; + + initial begin + bit x; + + u_inner.x = 1; + u_a_mon.y = 0; + u_a_mon.accessor; + + if (u_a_mon.y != 1) begin + $write("%%Error: Incorrect value placed in submodule\n"); + $stop; + end + + u_inner.x = 0; + u_a_mon.accessor; + + if (u_a_mon.y != 0) begin + $write("%%Error: Incorrect value placed in submodule\n"); + $stop; + end + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule : mod_a + +module mod_inner; + logic x; +endmodule : mod_inner + +module mod_a_mon; + bit y; + function void accessor; + begin : accessor_block + bit read_x = mod_a.u_inner.x; + y = read_x; + end + endfunction +endmodule diff --git a/test_regress/t/t_lint_unused_bad.pl b/test_regress/t/t_lint_unused_bad.pl index ca7a27539..feee5f9e4 100755 --- a/test_regress/t/t_lint_unused_bad.pl +++ b/test_regress/t/t_lint_unused_bad.pl @@ -11,7 +11,8 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(linter => 1); lint( - verilator_flags2 => ["--lint-only --bbox-sys --bbox-unsup -Wall -Wno-DECLFILENAME"], + verilator_flags2 => ["--lint-only --bbox-sys --bbox-unsup -Wall -Wno-DECLFILENAME", + "--unused-regexp 'cmdln*'"], fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_lint_unused_bad.v b/test_regress/t/t_lint_unused_bad.v index 9ee42b607..839527590 100644 --- a/test_regress/t/t_lint_unused_bad.v +++ b/test_regress/t/t_lint_unused_bad.v @@ -29,6 +29,9 @@ module sub; assign mixed[2] = 0; assign mixed[0] = 0; + wire [2:0] cmdln_off; // Suppressed by command line + assign cmdln_off = 0; + localparam THREE = 3; initial begin diff --git a/test_regress/t/t_math_arith.v b/test_regress/t/t_math_arith.v index 44945b297..6679ca665 100644 --- a/test_regress/t/t_math_arith.v +++ b/test_regress/t/t_math_arith.v @@ -9,7 +9,7 @@ module t (/*AUTOARG*/ clk ); input clk; - reg _ranit; + reg _ranit; reg [2:0] xor3; reg [1:0] xor2; @@ -29,8 +29,8 @@ module t (/*AUTOARG*/ wire [4:0] cond_check = (( xor2 == 2'b11) ? 5'h1 : (xor2 == 2'b00) ? 5'h2 - : (xor2 == 2'b01) ? 5'h3 - : 5'h4); + : (xor2 == 2'b01) ? 5'h3 + : 5'h4); wire ctrue = 1'b1 ? cond_check[1] : cond_check[0]; wire cfalse = 1'b0 ? cond_check[1] : cond_check[0]; @@ -49,91 +49,120 @@ module t (/*AUTOARG*/ always @ (posedge clk) begin if (!_ranit) begin - _ranit <= 1; + _ranit <= 1; - if (rep6 != 6'b111111) $stop; - if (!one) $stop; - if (~one) $stop; + if (rep6 != 6'b111111) $stop; + if (!one) $stop; + if (~one) $stop; - if (( 1'b0 ? 3'h3 : 1'b0 ? 3'h2 : 1'b1 ? 3'h1 : 3'h0) !== 3'h1) $stop; - // verilator lint_off WIDTH - if (( 8'h10 + 1'b0 ? 8'he : 8'hf) !== 8'he) $stop; // + is higher than ? - // verilator lint_on WIDTH + if (( 1'b0 ? 3'h3 : 1'b0 ? 3'h2 : 1'b1 ? 3'h1 : 3'h0) !== 3'h1) $stop; + // verilator lint_off WIDTH + if (( 8'h10 + 1'b0 ? 8'he : 8'hf) !== 8'he) $stop; // + is higher than ? + // verilator lint_on WIDTH - // surefire lint_off SEQASS - xor1 = 1'b1; - xor2 = 2'b11; - xor3 = 3'b111; - // verilator lint_off WIDTH - if (1'b1 & | (!xor3)) $stop; - // verilator lint_on WIDTH - if ({1{xor1}} != 1'b1) $stop; - if ({4{xor1}} != 4'b1111) $stop; - if (!(~xor1) !== ~(!xor1)) $stop; - if ((^xor1) !== 1'b1) $stop; - if ((^xor2) !== 1'b0) $stop; - if ((^xor3) !== 1'b1) $stop; - if (~(^xor2) !== 1'b1) $stop; - if (~(^xor3) !== 1'b0) $stop; - if ((^~xor1) !== 1'b0) $stop; - if ((^~xor2) !== 1'b1) $stop; - if ((^~xor3) !== 1'b0) $stop; - if ((~^xor1) !== 1'b0) $stop; - if ((~^xor2) !== 1'b1) $stop; - if ((~^xor3) !== 1'b0) $stop; - xor1 = 1'b0; - xor2 = 2'b10; - xor3 = 3'b101; - if ((^xor1) !== 1'b0) $stop; - if ((^xor2) !== 1'b1) $stop; - if ((^xor3) !== 1'b0) $stop; - if (~(^xor2) !== 1'b0) $stop; - if (~(^xor3) !== 1'b1) $stop; - if ((^~xor1) !== 1'b1) $stop; - if ((^~xor2) !== 1'b0) $stop; - if ((^~xor3) !== 1'b1) $stop; - if ((~^xor1) !== 1'b1) $stop; - if ((~^xor2) !== 1'b0) $stop; - if ((~^xor3) !== 1'b1) $stop; + // surefire lint_off SEQASS + xor1 = 1'b1; + xor2 = 2'b11; + xor3 = 3'b111; + // verilator lint_off WIDTH + if (1'b1 & | (!xor3)) $stop; + // verilator lint_on WIDTH + if ({1{xor1}} != 1'b1) $stop; + if ({4{xor1}} != 4'b1111) $stop; + if (!(~xor1) !== ~(!xor1)) $stop; + if ((^xor1) !== 1'b1) $stop; + if ((^xor2) !== 1'b0) $stop; + if ((^xor3) !== 1'b1) $stop; + if (~(^xor2) !== 1'b1) $stop; + if (~(^xor3) !== 1'b0) $stop; + if ((^~xor1) !== 1'b0) $stop; + if ((^~xor2) !== 1'b1) $stop; + if ((^~xor3) !== 1'b0) $stop; + if ((~^xor1) !== 1'b0) $stop; + if ((~^xor2) !== 1'b1) $stop; + if ((~^xor3) !== 1'b0) $stop; + xor1 = 1'b0; + xor2 = 2'b10; + xor3 = 3'b101; + if ((^xor1) !== 1'b0) $stop; + if ((^xor2) !== 1'b1) $stop; + if ((^xor3) !== 1'b0) $stop; + if (~(^xor2) !== 1'b0) $stop; + if (~(^xor3) !== 1'b1) $stop; + if ((^~xor1) !== 1'b1) $stop; + if ((^~xor2) !== 1'b0) $stop; + if ((^~xor3) !== 1'b1) $stop; + if ((~^xor1) !== 1'b1) $stop; + if ((~^xor2) !== 1'b0) $stop; + if ((~^xor3) !== 1'b1) $stop; - ma = 3'h3; + // X propagation + if (!1'bx !== 1'bx) $stop; + if (~2'bx !== 2'bx) $stop; + if (-2'bx !== 2'bx) $stop; + if ((2'bxx + 2'b1) !== 2'bxx) $stop; + if ((2'bxx - 2'b1) !== 2'bxx) $stop; + if ((2'bxx * 2'b1) !== 2'bxx) $stop; + if ((2'bxx / 2'b1) !== 2'bxx) $stop; + if ((2'bxx % 2'b1) !== 2'bxx) $stop; + if ((2'sbxx * 2'sb1) !== 2'bxx) $stop; + if ((2'sbxx / 2'sb1) !== 2'bxx) $stop; + if ((2'sbxx % 2'sb1) !== 2'bxx) $stop; + if ((1'bx & 1'b1) !== 1'bx) $stop; + if ((1'bx & 1'b0) !== 1'b0) $stop; + if ((1'bx | 1'b0) !== 1'bx) $stop; + if ((1'bx | 1'b1) !== 1'b1) $stop; + if ((1'bx && 1'b1) !== 1'bx) $stop; + if ((1'bx && 1'b0) !== 1'b0) $stop; + if ((1'bx || 1'b0) !== 1'bx) $stop; + if ((1'bx || 1'b1) !== 1'b1) $stop; + if ((2'bxx ^ 2'b1) !== 2'bxx) $stop; + if ((2'bxx > 2'b1) !== 1'bx) $stop; + if ((2'bxx < 2'b1) !== 1'bx) $stop; + if ((2'bxx == 2'b1) !== 1'bx) $stop; + if ((2'bxx <= 2'b1) !== 1'bx) $stop; + if ((2'bxx >= 2'b1) !== 1'bx) $stop; + if ((2'sbxx <= 2'sb1) !== 1'bx) $stop; + if ((2'sbxx >= 2'sb1) !== 1'bx) $stop; + + ma = 3'h3; mb = 3'h4; - mc = 10'h5; + mc = 10'h5; - mr1 = ma * mb; // Lint ASWESB: Assignment width mismatch - mr2 = 30'h5 * mc; // Lint ASWESB: Assignment width mismatch - if (mr1 !== 5'd12) $stop; - if (mr2 !== 31'd25) $stop; // Lint CWECBB: Comparison width mismatch + mr1 = ma * mb; // Lint ASWESB: Assignment width mismatch + mr2 = 30'h5 * mc; // Lint ASWESB: Assignment width mismatch + if (mr1 !== 5'd12) $stop; + if (mr2 !== 31'd25) $stop; // Lint CWECBB: Comparison width mismatch - sh1 = 68'hf_def1_9abc_5678_1234; - shq = sh1 >> 16; - if (shq !== 68'hf_def1_9abc_5678) $stop; - shq = sh1 << 16; // Lint ASWESB: Assignment width mismatch - if (shq !== 68'h1_9abc_5678_1234_0000) $stop; + sh1 = 68'hf_def1_9abc_5678_1234; + shq = sh1 >> 16; + if (shq !== 68'hf_def1_9abc_5678) $stop; + shq = sh1 << 16; // Lint ASWESB: Assignment width mismatch + if (shq !== 68'h1_9abc_5678_1234_0000) $stop; - // surefire lint_on SEQASS + // surefire lint_on SEQASS - // Test display extraction widthing - $display("[%0t] %x %x %x(%d)", $time, shq[2:0], shq[2:0]<<2, xor3[2:0], xor3[2:0]); + // Test display extraction widthing + $display("[%0t] %x %x %x(%d)", $time, shq[2:0], shq[2:0]<<2, xor3[2:0], xor3[2:0]); - // bug736 - //verilator lint_off WIDTH - if ((~| 4'b0000) != 4'b0001) $stop; - if ((~| 4'b0010) != 4'b0000) $stop; - if ((~& 4'b1111) != 4'b0000) $stop; - if ((~& 4'b1101) != 4'b0001) $stop; - //verilator lint_on WIDTH + // bug736 + //verilator lint_off WIDTH + if ((~| 4'b0000) != 4'b0001) $stop; + if ((~| 4'b0010) != 4'b0000) $stop; + if ((~& 4'b1111) != 4'b0000) $stop; + if ((~& 4'b1101) != 4'b0001) $stop; + //verilator lint_on WIDTH - // bug764 - //verilator lint_off WIDTH - // X does not sign extend - if (bug764_p11 !== 4'b000x) $stop; - if (~& bug764_p11 !== 1'b1) $stop; - //verilator lint_on WIDTH - // However IEEE 2017 5.7.1 says for constants that smaller-sizes do extend - if (4'bx !== 4'bxxxx) $stop; - if (4'bz !== 4'bzzzz) $stop; - if (4'b1 !== 4'b0001) $stop; + // bug764 + //verilator lint_off WIDTH + // X does not sign extend + if (bug764_p11 !== 4'b000x) $stop; + if (~& bug764_p11 !== 1'b1) $stop; + //verilator lint_on WIDTH + // However IEEE 2017 5.7.1 says for constants that smaller-sizes do extend + if (4'bx !== 4'bxxxx) $stop; + if (4'bz !== 4'bzzzz) $stop; + if (4'b1 !== 4'b0001) $stop; if ((0 -> 0) != 1'b1) $stop; if ((0 -> 1) != 1'b1) $stop; @@ -156,13 +185,13 @@ module t (/*AUTOARG*/ reg [7:0] m_corr_data_b8; initial begin m_data_pipe2_r = 64'h1234_5678_9abc_def0; - {m_corr_data_b8, m_corr_data_w1, m_corr_data_w0} = { m_data_pipe2_r[63:57], 1'b0, //m_corr_data_b8 [7:0] - m_data_pipe2_r[56:26], 1'b0, //m_corr_data_w1 [31:0] - m_data_pipe2_r[25:11], 1'b0, //m_corr_data_w0 [31:16] - m_data_pipe2_r[10:04], 1'b0, //m_corr_data_w0 [15:8] - m_data_pipe2_r[03:01], 1'b0, //m_corr_data_w0 [7:4] - m_data_pipe2_r[0], 3'b000 //m_corr_data_w0 [3:0] - }; + {m_corr_data_b8, m_corr_data_w1, m_corr_data_w0} = { m_data_pipe2_r[63:57], 1'b0, //m_corr_data_b8 [7:0] + m_data_pipe2_r[56:26], 1'b0, //m_corr_data_w1 [31:0] + m_data_pipe2_r[25:11], 1'b0, //m_corr_data_w0 [31:16] + m_data_pipe2_r[10:04], 1'b0, //m_corr_data_w0 [15:8] + m_data_pipe2_r[03:01], 1'b0, //m_corr_data_w0 [7:4] + m_data_pipe2_r[0], 3'b000 //m_corr_data_w0 [3:0] + }; if (m_corr_data_w0 != 32'haf36de00) $stop; if (m_corr_data_w1 != 32'h1a2b3c4c) $stop; if (m_corr_data_b8 != 8'h12) $stop; diff --git a/test_regress/t/t_param_public.cpp b/test_regress/t/t_param_public.cpp index b167dbf31..1620fb2d4 100644 --- a/test_regress/t/t_param_public.cpp +++ b/test_regress/t/t_param_public.cpp @@ -10,6 +10,7 @@ #include "Vt_param_public.h" #include "Vt_param_public_p.h" +#include "Vt_param_public_t.h" int main(int argc, char* argv[]) { Vt_param_public* topp = new Vt_param_public; @@ -17,6 +18,9 @@ int main(int argc, char* argv[]) { Verilated::debug(0); // Make sure public tag worked + if (static_cast(Vt_param_public_t::TOP_PARAM) != 30) { + vl_fatal(__FILE__, __LINE__, "dut", "bad value"); + } if (static_cast(Vt_param_public_p::INPACK) != 0) {} for (int i = 0; i < 10; i++) { diff --git a/test_regress/t/t_param_public.pl b/test_regress/t/t_param_public.pl index 345560283..6cec8bc56 100755 --- a/test_regress/t/t_param_public.pl +++ b/test_regress/t/t_param_public.pl @@ -12,7 +12,7 @@ scenarios(simulator => 1); if ($Self->{vlt_all}) { compile( - verilator_flags2 => ["--exe $Self->{t_dir}/$Self->{name}.cpp"], + verilator_flags2 => ["-GTOP_PARAM=30 --exe $Self->{t_dir}/$Self->{name}.cpp"], make_top_shell => 0, make_main => 0, ); diff --git a/test_regress/t/t_param_public.v b/test_regress/t/t_param_public.v index 36851a343..b896a596a 100644 --- a/test_regress/t/t_param_public.v +++ b/test_regress/t/t_param_public.v @@ -12,6 +12,8 @@ module t (/*AUTOARG*/ ); input clk; + parameter TOP_PARAM /*verilator public*/ = 20; + a #(1) a1 (); b #(2) b2 (); diff --git a/test_regress/t/t_preproc.out b/test_regress/t/t_preproc.out index d7dbfb30c..db7c40637 100644 --- a/test_regress/t/t_preproc.out +++ b/test_regress/t/t_preproc.out @@ -936,6 +936,12 @@ endmodule `line 635 "t/t_preproc.v" 0 + +"`NOT_DEFINED_STR" + +`line 640 "t/t_preproc.v" 0 + + predef 0 0 predef 1 1 @@ -956,4 +962,4 @@ predef 2 2 -`line 657 "t/t_preproc.v" 2 +`line 662 "t/t_preproc.v" 2 diff --git a/test_regress/t/t_preproc.v b/test_regress/t/t_preproc.v index 580998ce9..31d7ab17f 100644 --- a/test_regress/t/t_preproc.v +++ b/test_regress/t/t_preproc.v @@ -632,6 +632,11 @@ module pcc2_cfg; endgenerate endmodule +//====================================================================== +// Verilog-Perl bug1668 +`define stringify(text) `"text`" +`stringify(`NOT_DEFINED_STR) + //====================================================================== // IEEE mandated predefines `undefineall // undefineall should have no effect on these diff --git a/test_regress/t/t_preproc_comments.out b/test_regress/t/t_preproc_comments.out index 2397ac8f9..158faa511 100644 --- a/test_regress/t/t_preproc_comments.out +++ b/test_regress/t/t_preproc_comments.out @@ -940,6 +940,12 @@ endmodule `line 635 "t/t_preproc.v" 0 //====================================================================== +// Verilog-Perl bug1668 + +"`NOT_DEFINED_STR" + +`line 640 "t/t_preproc.v" 0 +//====================================================================== // IEEE mandated predefines // undefineall should have no effect on these predef 0 0 @@ -961,4 +967,4 @@ predef 2 2 // After `undefineall above, for testing --dump-defines -`line 657 "t/t_preproc.v" 2 +`line 662 "t/t_preproc.v" 2 diff --git a/test_regress/t/t_preproc_defarg_bad.out b/test_regress/t/t_preproc_defarg_bad.out new file mode 100644 index 000000000..1dac9e679 --- /dev/null +++ b/test_regress/t/t_preproc_defarg_bad.out @@ -0,0 +1,7 @@ +%Error: t/t_preproc_defarg_bad.v:13:4: Illegal text before '(' that starts define arguments +%Error: t/t_preproc_defarg_bad.v:13:8: Define passed too many arguments: A1 +%Error: t/t_preproc_defarg_bad.v:15:4: Illegal text before '(' that starts define arguments +%Error: t/t_preproc_defarg_bad.v:16:10: Define passed too many arguments: A2 +%Error: t/t_preproc_defarg_bad.v:21:1: EOF in define argument list +%Error: t/t_preproc_defarg_bad.v:21:1: Expecting ( to begin argument list for define reference `A2 +%Error: Exiting due to diff --git a/test_regress/t/t_preproc_defarg_bad.pl b/test_regress/t/t_preproc_defarg_bad.pl new file mode 100755 index 000000000..aa47819e1 --- /dev/null +++ b/test_regress/t/t_preproc_defarg_bad.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(vlt => 1); + +lint( + fails => 1, + verilator_flags2 => ["-Wno-context"], + # The .vh file has the error, not the .v file + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_preproc_defarg_bad.v b/test_regress/t/t_preproc_defarg_bad.v new file mode 100644 index 000000000..967c3b44b --- /dev/null +++ b/test_regress/t/t_preproc_defarg_bad.v @@ -0,0 +1,19 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2010 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +//See bug289 + +`define A1(x) +`define A2(x,y) + +`A1 +`A1(1,2) +`A2 +`A2(1) +`A2(1,2,3) + +module t; +endmodule diff --git a/test_regress/t/t_preproc_elsif_bad.out b/test_regress/t/t_preproc_elsif_bad.out new file mode 100644 index 000000000..979b24b69 --- /dev/null +++ b/test_regress/t/t_preproc_elsif_bad.out @@ -0,0 +1,16 @@ +%Error: t/t_preproc_elsif_bad.v:9:8: `elsif with no matching `if + 9 | `elsif A + | ^ +%Error: t/t_preproc_elsif_bad.v:10:1: `endif with no matching `if + 10 | `endif + | ^~~~~~ +%Error: t/t_preproc_elsif_bad.v:12:1: `else with no matching `if + 12 | `else + | ^~~~~ +%Error: t/t_preproc_elsif_bad.v:13:1: `endif with no matching `if + 13 | `endif + | ^~~~~~ +%Error: t/t_preproc_elsif_bad.v:15:8: Expecting `error string. Found: INCLUDE + 15 | `error `include + | ^~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_queue_unsup_bad.pl b/test_regress/t/t_preproc_elsif_bad.pl similarity index 90% rename from test_regress/t/t_queue_unsup_bad.pl rename to test_regress/t/t_preproc_elsif_bad.pl index b9057722c..cdeb5a8e1 100755 --- a/test_regress/t/t_queue_unsup_bad.pl +++ b/test_regress/t/t_preproc_elsif_bad.pl @@ -10,8 +10,9 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -compile( +lint( fails => 1, + # The .vh file has the error, not the .v file expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_preproc_elsif_bad.v b/test_regress/t/t_preproc_elsif_bad.v new file mode 100644 index 000000000..967b9f241 --- /dev/null +++ b/test_regress/t/t_preproc_elsif_bad.v @@ -0,0 +1,18 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2010 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +//See bug289 + +`elsif A +`endif + +`else +`endif + +`error `include + +module t; +endmodule diff --git a/test_regress/t/t_preproc_str_undef.out b/test_regress/t/t_preproc_str_undef.out new file mode 100644 index 000000000..dbfd686eb --- /dev/null +++ b/test_regress/t/t_preproc_str_undef.out @@ -0,0 +1,4 @@ +`PREFIX_my_suffix +`PREFIX_my_suffix +my_prefix_suffix +*-* All Finished *-* diff --git a/test_regress/t/t_preproc_str_undef.pl b/test_regress/t/t_preproc_str_undef.pl new file mode 100755 index 000000000..c6a015747 --- /dev/null +++ b/test_regress/t/t_preproc_str_undef.pl @@ -0,0 +1,22 @@ +#!/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, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_preproc_str_undef.v b/test_regress/t/t_preproc_str_undef.v new file mode 100644 index 000000000..f02544542 --- /dev/null +++ b/test_regress/t/t_preproc_str_undef.v @@ -0,0 +1,21 @@ +`define PREFIX_ my_prefix_ +`define SUFFIX my_suffix +`define PREFIX_SUFFIX my_prefix_suffix +`define name1 `PREFIX``_```SUFFIX +`define name2(p,s) p``_``s +`define name3(p) ```p``_SUFFIX +`define stringify(text) `"text`" + +module t(); + initial begin + // Another simulator gives: + // `PREFIX_my_suffix + // `name2(`PREFIX, my_suffix) + // `name3(PREFIX) + $display(`stringify(`name1)); + $display(`stringify(`name2(`PREFIX, `SUFFIX))); + $display(`stringify(`name3(PREFIX))); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_preproc_ttempty.out b/test_regress/t/t_preproc_ttempty.out index c1b85709c..e69de29bb 100644 --- a/test_regress/t/t_preproc_ttempty.out +++ b/test_regress/t/t_preproc_ttempty.out @@ -1 +0,0 @@ - `TARGET_PACKAGE diff --git a/test_regress/t/t_queue_method.out b/test_regress/t/t_queue_method.out new file mode 100644 index 000000000..078c10478 --- /dev/null +++ b/test_regress/t/t_queue_method.out @@ -0,0 +1,70 @@ +%Error-UNSUPPORTED: t/t_queue_method.v:28:14: Unsupported: with statements + 28 | q.sort with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:30:17: Unsupported: with statements + 30 | q.sort(x) with (x == 3); + | ^~~~ +%Error: t/t_queue_method.v:30:14: Can't find definition of variable: 'x' + 30 | q.sort(x) with (x == 3); + | ^ +%Error-UNSUPPORTED: t/t_queue_method.v:32:18: Unsupported: with statements + 32 | qe.sort(x) with (x == 3); + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:37:15: Unsupported: with statements + 37 | q.rsort with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:39:19: Unsupported: with statements + 39 | qe.rsort(x) with (x == 3); + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:59:19: Unsupported: with statements + 59 | qv = q.find with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:61:25: Unsupported: with statements + 61 | qv = q.find_index with (item == 2); qv.sort; + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:63:25: Unsupported: with statements + 63 | qv = q.find_first with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:65:31: Unsupported: with statements + 65 | qv = q.find_first_index with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:67:24: Unsupported: with statements + 67 | qv = q.find_last with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:69:30: Unsupported: with statements + 69 | qv = q.find_last_index with (item == 2); + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:72:19: Unsupported: with statements + 72 | qv = q.find with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:74:25: Unsupported: with statements + 74 | qv = q.find_index with (item == 20); qv.sort; + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:76:25: Unsupported: with statements + 76 | qv = q.find_first with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:78:31: Unsupported: with statements + 78 | qv = q.find_first_index with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:80:24: Unsupported: with statements + 80 | qv = q.find_last with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:82:30: Unsupported: with statements + 82 | qv = q.find_last_index with (item == 20); + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:98:17: Unsupported: with statements + 98 | i = q.sum with (item + 1); do if ((i) !== (32'h11)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_queue_method.v",98, (i), (32'h11)); $stop; end while(0);; + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:100:21: Unsupported: with statements + 100 | i = q.product with (item + 1); do if ((i) !== (32'h168)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_queue_method.v",100, (i), (32'h168)); $stop; end while(0);; + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:107:17: Unsupported: with statements + 107 | i = q.and with (item + 1); do if ((i) !== (32'b1001)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_queue_method.v",107, (i), (32'b1001)); $stop; end while(0);; + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:109:16: Unsupported: with statements + 109 | i = q.or with (item + 1); do if ((i) !== (32'b1111)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_queue_method.v",109, (i), (32'b1111)); $stop; end while(0);; + | ^~~~ +%Error-UNSUPPORTED: t/t_queue_method.v:111:17: Unsupported: with statements + 111 | i = q.xor with (item + 1); do if ((i) !== (32'b0110)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_queue_method.v",111, (i), (32'b0110)); $stop; end while(0);; + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_queue_method.pl b/test_regress/t/t_queue_method.pl new file mode 100755 index 000000000..f4321c541 --- /dev/null +++ b/test_regress/t/t_queue_method.pl @@ -0,0 +1,23 @@ +#!/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( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +#execute( +# check_finished => 1, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_queue_method.v b/test_regress/t/t_queue_method.v new file mode 100644 index 000000000..e3d6d6f27 --- /dev/null +++ b/test_regress/t/t_queue_method.v @@ -0,0 +1,120 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2019 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`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); + +`define checkg(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%g' exp='%g'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); + +module t (/*AUTOARG*/); + initial begin + int q[$]; + int qe[$]; + int qv[$]; + int i; + string v; + + q = '{1, 2, 2, 4, 3}; + v = $sformatf("%p", q); `checks(v, "'{1, 2, 2, 4, 3} "); + + // NOT tested: with ... selectors + + q.sort; + v = $sformatf("%p", q); `checks(v, "'{1, 2, 2, 3, 4} "); + q.sort with (item == 2); + v = $sformatf("%p", q); `checks(v, "'{4, 3, 1, 2, 2} "); + q.sort(x) with (x == 3); + v = $sformatf("%p", q); `checks(v, "'{2, 1, 2, 4, 3} "); + qe.sort(x) with (x == 3); + v = $sformatf("%p", qe); `checks(v, "'{}"); + + q.rsort; + v = $sformatf("%p", q); `checks(v, "'{4, 3, 2, 2, 1} "); + q.rsort with (item == 2); + v = $sformatf("%p", q); `checks(v, "'{2, 2, 4, 1, 3} "); + qe.rsort(x) with (x == 3); + v = $sformatf("%p", qe); `checks(v, "'{}"); + + qv = q.unique; + v = $sformatf("%p", qv); `checks(v, "'{2, 4, 1, 3} "); + qv = qe.unique; + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.unique_index; qv.sort; + v = $sformatf("%p", qv); `checks(v, "'{0, 2, 3, 4} "); + q.reverse; + v = $sformatf("%p", q); `checks(v, "'{3, 1, 4, 2, 2} "); + qe.reverse; + v = $sformatf("%p", qe); `checks(v, "'{}"); + q.shuffle(); q.sort; + v = $sformatf("%p", q); `checks(v, "'{1, 2, 2, 3, 4} "); + qe.shuffle(); qe.sort; + v = $sformatf("%p", qe); `checks(v, "'{}"); + + // These require an with clause or are illegal + // TODO add a lint check that with clause is provided + qv = q.find with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{2, 2} "); + qv = q.find_index with (item == 2); qv.sort; + v = $sformatf("%p", qv); `checks(v, "'{1, 2} "); + qv = q.find_first with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{2} "); + qv = q.find_first_index with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{1} "); + qv = q.find_last with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{2} "); + qv = q.find_last_index with (item == 2); + v = $sformatf("%p", qv); `checks(v, "'{2} "); + + qv = q.find with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_index with (item == 20); qv.sort; + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_first with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_first_index with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_last with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = q.find_last_index with (item == 20); + v = $sformatf("%p", qv); `checks(v, "'{}"); + + qv = q.min; + v = $sformatf("%p", qv); `checks(v, "'{1} "); + qv = q.max; + v = $sformatf("%p", qv); `checks(v, "'{4} "); + + qv = qe.min; + v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = qe.max; + v = $sformatf("%p", qv); `checks(v, "'{}"); + + // Reduction methods + + i = q.sum; `checkh(i, 32'hc); + i = q.sum with (item + 1); `checkh(i, 32'h11); + i = q.product; `checkh(i, 32'h30); + i = q.product with (item + 1); `checkh(i, 32'h168); + + i = qe.sum; `checkh(i, 32'h0); + i = qe.product; `checkh(i, 32'h0); + + q = '{32'b1100, 32'b1010}; + i = q.and; `checkh(i, 32'b1000); + i = q.and with (item + 1); `checkh(i, 32'b1001); + i = q.or; `checkh(i, 32'b1110); + i = q.or with (item + 1); `checkh(i, 32'b1111); + i = q.xor; `checkh(i, 32'b0110); + i = q.xor with (item + 1); `checkh(i, 32'b0110); + + i = qe.and; `checkh(i, 32'b0); + i = qe.or; `checkh(i, 32'b0); + i = qe.xor; `checkh(i, 32'b0); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_queue_slice.out b/test_regress/t/t_queue_slice.out new file mode 100644 index 000000000..2df592095 --- /dev/null +++ b/test_regress/t/t_queue_slice.out @@ -0,0 +1,85 @@ +%Error-UNSUPPORTED: t/t_queue_slice.v:22:11: Unsupported: Assignment pattern applies against non struct/union data type: 'string[$]' + : ... In instance t + 22 | q = '{"q", "b", "c", "d", "e", "f"}; + | ^~ +%Error-UNSUPPORTED: t/t_queue_slice.v:25:11: Unsupported: Replication to form 'string[$]' data type + : ... In instance t + 25 | q = {"q", "b", "c", "d", "e", "f"}; + | ^ +%Error-UNSUPPORTED: t/t_queue_slice.v:28:9: Unsupported: Queue .delete(index) method, as is O(n) complexity and slow. + : ... In instance t + 28 | q.delete(1); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_queue_slice.v:32:9: Unsupported: Queue .insert method, as is O(n) complexity and slow. + : ... In instance t + 32 | q.insert(2, "ins2"); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_queue_slice.v:38:11: Unsupported: Replication to form 'string[$]' data type + : ... In instance t + 38 | q = {"q", "b", "c", "d", "e", "f"}; + | ^ +%Error: t/t_queue_slice.v:39:12: Illegal range select; type already selected, or bad dimension: data type is 'string[$]' + : ... In instance t + 39 | q = q[2:3]; + | ^ +%Error-UNSUPPORTED: t/t_queue_slice.v:41:11: Unsupported: Replication to form 'string[$]' data type + : ... In instance t + 41 | q = {"q", "b", "c", "d", "e", "f"}; + | ^ +%Error-UNSUPPORTED: t/t_queue_slice.v:42:15: Unsupported/illegal unbounded ('$') in this context. + : ... In instance t + 42 | q = q[3:$]; + | ^ +%Error: t/t_queue_slice.v:42:15: First value of [a:b] isn't a constant, maybe you want +: or -: + : ... In instance t + 42 | q = q[3:$]; + | ^ +%Error: t/t_queue_slice.v:42:12: Illegal range select; type already selected, or bad dimension: data type is 'string[$]' + : ... In instance t + 42 | q = q[3:$]; + | ^ +%Error-UNSUPPORTED: t/t_queue_slice.v:46:11: Unsupported: Replication to form 'string[$]' data type + : ... In instance t + 46 | q = {q, "f1"}; + | ^ +%Error-UNSUPPORTED: t/t_queue_slice.v:47:11: Unsupported: Replication to form 'string[$]' data type + : ... In instance t + 47 | q = {q, "f2"}; + | ^ +%Error-UNSUPPORTED: t/t_queue_slice.v:48:11: Unsupported: Replication to form 'string[$]' data type + : ... In instance t + 48 | q = {"b1", q}; + | ^ +%Error-UNSUPPORTED: t/t_queue_slice.v:49:11: Unsupported: Replication to form 'string[$]' data type + : ... In instance t + 49 | q = {"b2", q}; + | ^ +%Error-UNSUPPORTED: t/t_queue_slice.v:50:11: Unsupported: Replication to form 'string[$]' data type + : ... In instance t + 50 | q = {q[0], q[2:$]}; + | ^ +%Error-UNSUPPORTED: t/t_queue_slice.v:50:22: Unsupported/illegal unbounded ('$') in this context. + : ... In instance t + 50 | q = {q[0], q[2:$]}; + | ^ +%Error: t/t_queue_slice.v:50:22: First value of [a:b] isn't a constant, maybe you want +: or -: + : ... In instance t + 50 | q = {q[0], q[2:$]}; + | ^ +%Error: t/t_queue_slice.v:50:19: Illegal range select; type already selected, or bad dimension: data type is 'string[$]' + : ... In instance t + 50 | q = {q[0], q[2:$]}; + | ^ +%Error-UNSUPPORTED: t/t_queue_slice.v:54:25: Unsupported: Replication to form 'string[$]' data type + : ... In instance t + 54 | string ai[$] = { "Foo", "Bar" }; + | ^ +%Error-UNSUPPORTED: t/t_queue_slice.v:59:14: Unsupported: Assignment pattern applies against non struct/union data type: 'string[$]' + : ... In instance t + 59 | q = '{ "BB", "CC" }; + | ^~ +%Error-UNSUPPORTED: t/t_queue_slice.v:62:14: Unsupported: Replication to form 'string[$]' data type + : ... In instance t + 62 | q = { "BB", "CC" }; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_queue_slice.pl b/test_regress/t/t_queue_slice.pl new file mode 100755 index 000000000..f4321c541 --- /dev/null +++ b/test_regress/t/t_queue_slice.pl @@ -0,0 +1,23 @@ +#!/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( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +#execute( +# check_finished => 1, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_queue_unsup_bad.v b/test_regress/t/t_queue_slice.v similarity index 71% rename from test_regress/t/t_queue_unsup_bad.v rename to test_regress/t/t_queue_slice.v index e58e21113..e60539f4a 100644 --- a/test_regress/t/t_queue_unsup_bad.v +++ b/test_regress/t/t_queue_slice.v @@ -16,7 +16,11 @@ module t (/*AUTOARG*/); int i; q.push_front("non-empty"); - i = q.size(); `checkh(i, 0); + i = q.size(); `checkh(i, 1); + v = $sformatf("%p", q); `checks(v, "'{\"non-empty\"} "); + + q = '{"q", "b", "c", "d", "e", "f"}; + v = $sformatf("%p", q); `checks(v, "'{\"q\", \"b\", \"c\", \"d\", \"e\", \"f\"} "); q = {"q", "b", "c", "d", "e", "f"}; v = $sformatf("%p", q); `checks(v, "'{\"q\", \"b\", \"c\", \"d\", \"e\", \"f\"} "); @@ -28,7 +32,15 @@ module t (/*AUTOARG*/); q.insert(2, "ins2"); v = q[0]; `checks(v, "ins0"); v = q[2]; `checks(v, "ins2"); - v = $sformatf("%p", q); `checks(v, "'{need_update, \"q\", \"b\", \"c\", \"d\", \"e\", \"f\"} "); + v = $sformatf("%p", q); `checks(v, "'{\"ins0\", \"q\", \"ins2\", \"c\", \"d\", \"e\", \"f\"} "); + + // Slicing + q = {"q", "b", "c", "d", "e", "f"}; + q = q[2:3]; + v = $sformatf("%p", q); `checks(v, "'{\"c\", \"d\"} "); + q = {"q", "b", "c", "d", "e", "f"}; + q = q[3:$]; + v = $sformatf("%p", q); `checks(v, "'{\"d\", \"e\", \"f\"} "); // Similar using implied notation q = {q, "f1"}; // push_front @@ -36,7 +48,7 @@ module t (/*AUTOARG*/); q = {"b1", q}; // push_back q = {"b2", q}; // push_back q = {q[0], q[2:$]}; // delete element 1 - v = $sformatf("%p", q); `checks(v, "'{need_update, \"q\", \"b\", \"c\", \"d\", \"e\", \"f\"} "); + v = $sformatf("%p", q); `checks(v, "'{\"b2\", \"d\", \"e\", \"f\", \"f1\", \"f2\"} "); begin string ai[$] = { "Foo", "Bar" }; @@ -52,25 +64,7 @@ module t (/*AUTOARG*/); v = q.pop_front(); `checks(v, "CC"); end - // Unpacked methods also allowed. Not supported yet. - // find() - // find_index() - // find_first() - // find_first_index() - // find_last() - // find_last_index() - // min() - // max() - // unique() - // unique_index() - // reverse() - // sort() - // rsort() - // shuffle() - // sum() - // product() - // and() - // or() - // xor() + $write("*-* All Finished *-*\n"); + $finish; end endmodule diff --git a/test_regress/t/t_queue_unsup_bad.out b/test_regress/t/t_queue_unsup_bad.out deleted file mode 100644 index 91430c035..000000000 --- a/test_regress/t/t_queue_unsup_bad.out +++ /dev/null @@ -1,57 +0,0 @@ -%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:21:11: Unsupported: Replication to form 'string[$]' data type - : ... In instance t - 21 | q = {"q", "b", "c", "d", "e", "f"}; - | ^ -%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:24:9: Unsupported: Queue .delete(index) method, as is O(n) complexity and slow. - : ... In instance t - 24 | q.delete(1); - | ^~~~~~ -%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:28:9: Unsupported: Queue .insert method, as is O(n) complexity and slow. - : ... In instance t - 28 | q.insert(2, "ins2"); - | ^~~~~~ -%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:34:11: Unsupported: Replication to form 'string[$]' data type - : ... In instance t - 34 | q = {q, "f1"}; - | ^ -%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:35:11: Unsupported: Replication to form 'string[$]' data type - : ... In instance t - 35 | q = {q, "f2"}; - | ^ -%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:36:11: Unsupported: Replication to form 'string[$]' data type - : ... In instance t - 36 | q = {"b1", q}; - | ^ -%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:37:11: Unsupported: Replication to form 'string[$]' data type - : ... In instance t - 37 | q = {"b2", q}; - | ^ -%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:38:11: Unsupported: Replication to form 'string[$]' data type - : ... In instance t - 38 | q = {q[0], q[2:$]}; - | ^ -%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:38:22: Unsupported/illegal unbounded ('$') in this context. - : ... In instance t - 38 | q = {q[0], q[2:$]}; - | ^ -%Error: t/t_queue_unsup_bad.v:38:22: First value of [a:b] isn't a constant, maybe you want +: or -: - : ... In instance t - 38 | q = {q[0], q[2:$]}; - | ^ -%Error: t/t_queue_unsup_bad.v:38:19: Illegal range select; type already selected, or bad dimension: data type is 'string[$]' - : ... In instance t - 38 | q = {q[0], q[2:$]}; - | ^ -%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:42:25: Unsupported: Replication to form 'string[$]' data type - : ... In instance t - 42 | string ai[$] = { "Foo", "Bar" }; - | ^ -%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:47:14: Unsupported: Assignment pattern applies against non struct/union data type: 'string[$]' - : ... In instance t - 47 | q = '{ "BB", "CC" }; - | ^~ -%Error-UNSUPPORTED: t/t_queue_unsup_bad.v:50:14: Unsupported: Replication to form 'string[$]' data type - : ... In instance t - 50 | q = { "BB", "CC" }; - | ^ -%Error: Exiting due to diff --git a/test_regress/t/t_randomize.out b/test_regress/t/t_randomize.out index ae473f217..7f05355de 100644 --- a/test_regress/t/t_randomize.out +++ b/test_regress/t/t_randomize.out @@ -4,16 +4,7 @@ %Error-UNSUPPORTED: t/t_randomize.v:29:29: Unsupported: solve before 29 | constraint order { solve length before header; } | ^~~~~~ -%Error-UNSUPPORTED: t/t_randomize.v:32:16: Unsupported: dist :/ - 32 | x dist { [100:102] :/ 1, 200 := 2, 300 := 5}; - | ^ -%Error-UNSUPPORTED: t/t_randomize.v:32:32: Unsupported: dist := - 32 | x dist { [100:102] :/ 1, 200 := 2, 300 := 5}; - | ^~~ -%Error-UNSUPPORTED: t/t_randomize.v:32:42: Unsupported: dist := - 32 | x dist { [100:102] :/ 1, 200 := 2, 300 := 5}; - | ^~~ %Error-UNSUPPORTED: t/t_randomize.v:32:9: Unsupported: dist - 32 | x dist { [100:102] :/ 1, 200 := 2, 300 := 5}; + 32 | x dist { [100:102] :/ 1, 200 := 2, 300 := 5, 400}; | ^~~~ %Error: Exiting due to diff --git a/test_regress/t/t_randomize.v b/test_regress/t/t_randomize.v index adc5bfcca..9c3d9bf5e 100644 --- a/test_regress/t/t_randomize.v +++ b/test_regress/t/t_randomize.v @@ -29,7 +29,7 @@ class Packet; constraint order { solve length before header; } constraint dis { disable soft x; - x dist { [100:102] :/ 1, 200 := 2, 300 := 5}; + x dist { [100:102] :/ 1, 200 := 2, 300 := 5, 400}; } endclass diff --git a/test_regress/t/t_runflag_bad.out b/test_regress/t/t_runflag_bad.out new file mode 100644 index 000000000..32330deaf --- /dev/null +++ b/test_regress/t/t_runflag_bad.out @@ -0,0 +1,2 @@ +%Warning: Unknown +verilator runtime argument: '+verilator+bad+flag+testing' +*-* All Finished *-* diff --git a/test_regress/t/t_runflag_bad.pl b/test_regress/t/t_runflag_bad.pl new file mode 100755 index 000000000..7f6ecf79f --- /dev/null +++ b/test_regress/t/t_runflag_bad.pl @@ -0,0 +1,24 @@ +#!/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(vlt_all => 1); + +compile( + ); + +execute( + all_run_flags => ["+verilator+bad+flag+testing"], + #fails => 1, # doesn't fail just prints + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_runflag_bad.v b/test_regress/t/t_runflag_bad.v new file mode 100644 index 000000000..cfcf3ba54 --- /dev/null +++ b/test_regress/t/t_runflag_bad.v @@ -0,0 +1,12 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2019 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_savable.v b/test_regress/t/t_savable.v index 76b18144f..c5e010a4e 100644 --- a/test_regress/t/t_savable.v +++ b/test_regress/t/t_savable.v @@ -6,11 +6,17 @@ module t (/*AUTOARG*/ // Inputs - clk + clk, model ); /*verilator no_inline_module*/ // So we'll get hiearachy we can test input clk; + // Parameter so we can test for different model error + parameter MODEL_WIDTH = 10; + input [MODEL_WIDTH-1:0] model; + + initial $write("Model width = %d\n", MODEL_WIDTH); + sub sub (/*AUTOINST*/ // Inputs .clk (clk)); diff --git a/test_regress/t/t_savable_format1_bad.out b/test_regress/t/t_savable_format1_bad.out new file mode 100644 index 000000000..72f5bde4d --- /dev/null +++ b/test_regress/t/t_savable_format1_bad.out @@ -0,0 +1,4 @@ +Model width = 40 +Restoring model from 'obj_vlt/t_savable_format1_bad/saved.vltsv' +%Error: obj_vlt/t_savable_format1_bad/saved.vltsv:0: Can't deserialize save-restore file as was made from different model: obj_vlt/t_savable_format1_bad/saved.vltsv +Aborting... diff --git a/test_regress/t/t_savable_format1_bad.pl b/test_regress/t/t_savable_format1_bad.pl new file mode 100755 index 000000000..f6ac72e4e --- /dev/null +++ b/test_regress/t/t_savable_format1_bad.pl @@ -0,0 +1,39 @@ +#!/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(vlt => 1); + +top_filename("t/t_savable.v"); + +compile( + v_flags2 => ["--savable"], + save_time => 500, + ); + +execute( + check_finished => 0, + all_run_flags => ['+save_time=500'], + ); + +-r "$Self->{obj_dir}/saved.vltsv" or error("Saved.vltsv not created\n"); + +compile( + v_flags2 => ["--savable -GMODEL_WIDTH=40"], + save_time => 500, + ); + +execute( + all_run_flags => ['+save_restore=1'], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_savable_format2_bad.out b/test_regress/t/t_savable_format2_bad.out new file mode 100644 index 000000000..69680ca5b --- /dev/null +++ b/test_regress/t/t_savable_format2_bad.out @@ -0,0 +1,4 @@ +Model width = 10 +Restoring model from 'obj_vlt/t_savable_format2_bad/saved.vltsv' +%Error: obj_vlt/t_savable_format2_bad/saved.vltsv:0: Can't deserialize; file has wrong header signature, or file not found: obj_vlt/t_savable_format2_bad/saved.vltsv +Aborting... diff --git a/test_regress/t/t_savable_format2_bad.pl b/test_regress/t/t_savable_format2_bad.pl new file mode 100755 index 000000000..8a6e75248 --- /dev/null +++ b/test_regress/t/t_savable_format2_bad.pl @@ -0,0 +1,39 @@ +#!/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(vlt => 1); + +top_filename("t/t_savable.v"); + +compile( + v_flags2 => ["--savable"], + save_time => 500, + ); + +execute( + check_finished => 0, + all_run_flags => ['+save_time=500'], + ); + +-r "$Self->{obj_dir}/saved.vltsv" or error("Saved.vltsv not created\n"); + +# Break the header +file_sed("$Self->{obj_dir}/saved.vltsv", + "$Self->{obj_dir}/saved.vltsv", + sub { s/verilatorsave01/verilatorsavBAD/g; }); + +execute( + all_run_flags => ['+save_restore=1'], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_savable_format3_bad.out b/test_regress/t/t_savable_format3_bad.out new file mode 100644 index 000000000..3389dee4b --- /dev/null +++ b/test_regress/t/t_savable_format3_bad.out @@ -0,0 +1,4 @@ +Model width = 10 +Restoring model from 'obj_vlt/t_savable_format3_bad/saved.vltsv' +%Error: obj_vlt/t_savable_format3_bad/saved.vltsv:0: Can't deserialize; file has wrong end-of-file signature: obj_vlt/t_savable_format3_bad/saved.vltsv +Aborting... diff --git a/test_regress/t/t_savable_format3_bad.pl b/test_regress/t/t_savable_format3_bad.pl new file mode 100755 index 000000000..ce78e55f1 --- /dev/null +++ b/test_regress/t/t_savable_format3_bad.pl @@ -0,0 +1,39 @@ +#!/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(vlt => 1); + +top_filename("t/t_savable.v"); + +compile( + v_flags2 => ["--savable"], + save_time => 500, + ); + +execute( + check_finished => 0, + all_run_flags => ['+save_time=500'], + ); + +-r "$Self->{obj_dir}/saved.vltsv" or error("Saved.vltsv not created\n"); + +# Break the header +file_sed("$Self->{obj_dir}/saved.vltsv", + "$Self->{obj_dir}/saved.vltsv", + sub { s/vltsaved/vltNOTed/g; }); + +execute( + all_run_flags => ['+save_restore=1'], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_savable_open_bad.out b/test_regress/t/t_savable_open_bad.out new file mode 100644 index 000000000..ca2151f02 --- /dev/null +++ b/test_regress/t/t_savable_open_bad.out @@ -0,0 +1,4 @@ +Model width = 10 +Restoring model from 'obj_vlt/t_savable_open_bad/saved.vltsv' +%Error: obj_vlt/t_savable_open_bad/saved.vltsv:0: Can't deserialize; file has wrong header signature, or file not found: obj_vlt/t_savable_open_bad/saved.vltsv +Aborting... diff --git a/test_regress/t/t_savable_open_bad.pl b/test_regress/t/t_savable_open_bad.pl new file mode 100755 index 000000000..a2160366f --- /dev/null +++ b/test_regress/t/t_savable_open_bad.pl @@ -0,0 +1,27 @@ +#!/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(vlt => 1); + +top_filename("t/t_savable.v"); + +compile( + v_flags2 => ["--savable"], + save_time => 500, + ); + +execute( + all_run_flags => ['+save_restore=1'], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_scope_map.cpp b/test_regress/t/t_scope_map.cpp index 90fd2c63f..39d28c3d0 100644 --- a/test_regress/t/t_scope_map.cpp +++ b/test_regress/t/t_scope_map.cpp @@ -115,6 +115,9 @@ int main(int argc, char** argv, char** env) { tfp->dump((unsigned int)(main_time)); ++main_time; + // Code coverage of historical flush function + Verilated::flushCall(); + for (VerilatedScopeNameMap::const_iterator it = scopeMapp->begin(); it != scopeMapp->end(); ++it) { VerilatedVarNameMap* varNameMap = it->second->varsp(); @@ -159,5 +162,6 @@ int main(int argc, char** argv, char** env) { tfp->close(); top->final(); VL_PRINTF("*-* All Finished *-*\n"); + return 0; } diff --git a/test_regress/t/t_stream_integer_type.pl b/test_regress/t/t_stream_integer_type.pl new file mode 100755 index 000000000..d48fba66c --- /dev/null +++ b/test_regress/t/t_stream_integer_type.pl @@ -0,0 +1,22 @@ +#!/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( + fails => $Self->{vlt_all}, + ); + +#execute( +# check_finished => 1, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_stream_integer_type.v b/test_regress/t/t_stream_integer_type.v new file mode 100644 index 000000000..2b606829f --- /dev/null +++ b/test_regress/t/t_stream_integer_type.v @@ -0,0 +1,332 @@ +// DESCRIPTION: Verilator: Verilog Test module +// Ref. to IEEE Std 1800-2017 11.4.14 & A.8.1 +// +// stream pack/unpack for integer_type only +// slice_size ::= simple_type | constant_expression +// simple_type ::= +// integer_type | non_integer_type | ps_type_identifier | ps_parameter_identifier +// non_integer_type ::= shortreal | real | realtime +// integer_type ::= +// integer_vector_type | integer_atom_type +// integer_atom_type ::= byte | shortint | int | longint | integer | time +// integer_vector_type ::= bit | logic | reg +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Victor Besyakov. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + logic [31:0] packed_data_32; + logic [31:0] packed_data_32_ref; + + logic [31:0] v_packed_data_32; + logic [31:0] v_packed_data_32_ref; + + logic [63:0] packed_data_64; + logic [63:0] packed_data_64_ref; + + logic [63:0] v_packed_data_64; + logic [63:0] v_packed_data_64_ref; + + logic [127:0] packed_data_128; + logic [127:0] packed_data_128_ref; + + logic [127:0] v_packed_data_128; + logic [127:0] v_packed_data_128_ref; + + logic [127:0] packed_data_128_i; + logic [127:0] packed_data_128_i_ref; + + logic [255:0] packed_data_256; + logic [255:0] packed_data_256_ref; + + logic [255:0] packed_time_256; + logic [255:0] packed_time_256_ref; + // + //integer_atom_type + // + byte byte_in[4]; + byte byte_out[4]; + // + int int_in[4]; + int int_out[4]; + // + // + shortint shortint_in[4]; + shortint shortint_out[4]; + // + longint longint_in[4]; + longint longint_out[4]; + // + integer integer_in[4]; + integer integer_out[4]; + // + time time_in[4]; + time time_out[4]; + + //integer_vector_type + typedef bit [7:0] test_byte; + typedef bit [15:0] test_short; + typedef bit [31:0] test_word; + typedef bit [63:0] test_long; + // + test_byte bit_in[4]; + test_byte bit_out[4]; + // + test_short logic_in[4]; + test_short logic_out[4]; + // + test_word reg_in[4]; + test_word reg_out[4]; + // + string error = ""; + + initial begin + //init + $write("*-* START t_stream_pack_unpack *-*\n"); + error = test_integer_type_1(error); +`ifdef TEST_VERBOSE + print_all_data("test_integer_type_1"); +`endif + error = test_integer_type_2(error); +`ifdef TEST_VERBOSE + print_all_data("test_integer_type_2"); +`endif + // + if (error == "") $write("*-* All Finished *-*\n"); + else begin + $write("*-* TEST failed error %s *-*:\n", error); + print_data_error(error); + end + $finish; + end // initial begin + + function string test_integer_type_1(string error); + automatic string error_; + automatic string function_name_ = "test_integer_type_1"; + + error_ = error; + if (error_ == "") begin + clean_packed_data (); + init_data(); + //pack + packed_data_32 = {<<8{byte_in}}; + packed_data_64 = {<<16{shortint_in}}; + packed_data_128 = {<<32{int_in}}; + packed_data_128_i = {<<32{integer_in}}; + packed_data_256 = {<<64{longint_in}}; + packed_time_256 = {<<64{time_in}}; + v_packed_data_32 = {<<8{bit_in}}; + v_packed_data_64 = {<<16{logic_in}}; + v_packed_data_128 = {<<32{reg_in}}; + //unpack + {<<8{byte_out}} = packed_data_32; + {<<16{shortint_out}} = packed_data_64; + {<<32{int_out}} = packed_data_128; + {<<32{integer_out}} = packed_data_128_i; + {<<64{longint_out}} = packed_data_256; + {<<64{time_out}} = packed_time_256; + {<<8{bit_out}} = v_packed_data_32; + {<<16{logic_out}} = v_packed_data_64; + {<<32{reg_out}} = v_packed_data_128; + error_ = comp_in_out(); + end // if (error == "") + return error_; + endfunction : test_integer_type_1 + + function string test_integer_type_2(string error); + automatic string error_; + automatic string function_name_ = "test_integer_type_2"; + error_ = error; + if (error_ == "") begin + clean_packed_data (); + init_data(); + //pack + packed_data_32 = {< ["../bin/verilator_coverage", "t/${basename}", + "--debug", "--debugi 9", ], tee => $Self->{verbose}, diff --git a/test_regress/t/t_vlcov_merge.pl b/test_regress/t/t_vlcov_merge.pl index cfac15b48..bf62addf8 100755 --- a/test_regress/t/t_vlcov_merge.pl +++ b/test_regress/t/t_vlcov_merge.pl @@ -11,6 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(dist => 1); run(cmd => ["../bin/verilator_coverage", + "--no-unlink", "--nounlink", "--write", "$Self->{obj_dir}/coverage.dat", "t/t_vlcov_data_a.dat", "t/t_vlcov_data_b.dat", @@ -20,6 +21,10 @@ run(cmd => ["../bin/verilator_coverage", verilator_run => 1, ); +# Not deleted e.g. parsed --no-unlink properly +files_identical("$Self->{t_dir}/t_vlcov_data_a.dat", + "$Self->{t_dir}/t_vlcov_data_a.dat"); + # Older clib's didn't properly sort maps, but the coverage data doesn't # really care about ordering. So avoid false failures by sorting. files_identical_sorted("$Self->{obj_dir}/coverage.dat", $Self->{golden_filename}); diff --git a/test_regress/t/t_vlcov_unlink.pl b/test_regress/t/t_vlcov_unlink.pl new file mode 100755 index 000000000..51b2e7d0c --- /dev/null +++ b/test_regress/t/t_vlcov_unlink.pl @@ -0,0 +1,32 @@ +#!/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-2009 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 + +use File::Copy; + +scenarios(dist => 1); + +my $tmp = "$Self->{obj_dir}/copied.dat"; +File::Copy::copy("$Self->{t_dir}/t_vlcov_data_a.dat", $tmp); + +run(cmd => ["../bin/verilator_coverage", + "--unlink", + $tmp, + "--write", "$Self->{obj_dir}/output.dat"], + verilator_run => 1, + ); + +files_identical("$Self->{obj_dir}/output.dat", "t/t_vlcov_data_a.dat"); + +# --unlink should have removed it +!-r $tmp or error("Not unlinked"); + +ok(1); + +1; diff --git a/test_regress/t/t_vpi_var.cpp b/test_regress/t/t_vpi_var.cpp index 0b067dab6..8de2707f9 100644 --- a/test_regress/t/t_vpi_var.cpp +++ b/test_regress/t/t_vpi_var.cpp @@ -106,9 +106,15 @@ int _mon_check_mcd() { status = vpi_mcd_printf(mcd, (PLI_BYTE8*)"hello %s", "vpi_mcd_printf"); CHECK_RESULT(status, strlen("hello vpi_mcd_printf")); + status = vpi_mcd_printf(0, (PLI_BYTE8*)"empty"); + CHECK_RESULT(status, 0); + status = vpi_mcd_flush(mcd); CHECK_RESULT(status, 0); + status = vpi_mcd_flush(0); + CHECK_RESULT(status, 1); + status = vpi_mcd_close(mcd); // Icarus says 'error' on ones we're not using, so check only used ones return 0. CHECK_RESULT(status & mcd, 0); @@ -421,6 +427,8 @@ int _mon_check_string() { vpi_get_value(vh1, &v); if (vpi_chk_error(&e)) { printf("%%vpi_chk_error : %s\n", e.message); } + (void)vpi_chk_error(NULL); + CHECK_RESULT_CSTR_STRIP(v.value.str, text_test_obs[i].initial); v.value.str = (PLI_BYTE8*)text_test_obs[i].value; diff --git a/test_regress/t/t_waiveroutput.pl b/test_regress/t/t_waiveroutput.pl index 08f77ed08..9559ffed7 100755 --- a/test_regress/t/t_waiveroutput.pl +++ b/test_regress/t/t_waiveroutput.pl @@ -20,7 +20,8 @@ compile( files_identical("$out_filename", $Self->{golden_filename}); -run(cmd=>["sed 's/\\/\\/ lint_off/lint_off/g' $out_filename > $waiver_filename"]); +file_sed($out_filename, $waiver_filename, + sub { s/\/\/ lint_off/lint_off/g; }); compile( v_flags2 => [$waiver_filename], diff --git a/verilator-config.cmake.in b/verilator-config.cmake.in index 68c187e41..0b972874b 100644 --- a/verilator-config.cmake.in +++ b/verilator-config.cmake.in @@ -221,14 +221,8 @@ function(verilate TARGET) ${${VERILATE_PREFIX}_CLASSES_SLOW} ${${VERILATE_PREFIX}_SUPPORT_FAST} ${${VERILATE_PREFIX}_SUPPORT_SLOW}) - foreach(GENERATED_C_SOURCE ${GENERATED_C_SOURCES}) - get_filename_component(C_OUTPUT_NAME_WE "${GENERATED_C_SOURCE}" NAME_WE) - if(C_OUTPUT_NAME_WE MATCHES ".*Trace.*") - continue() - endif() - list(APPEND GENERATED_H_SOURCES "${VDIR}/${C_OUTPUT_NAME_WE}.h") - endforeach() - set(GENERATED_SOURCES ${GENERATED_C_SOURCES} ${GENERATED_H_SOURCES}) + # No need for .h's as the .cpp will get written same time + set(GENERATED_SOURCES ${GENERATED_C_SOURCES}) add_custom_command(OUTPUT ${GENERATED_SOURCES} "${VCMAKE}" COMMAND ${VERILATOR_COMMAND}