diff --git a/.github/workflows/contributor.yml b/.github/workflows/contributor.yml index 627d00ab3..bbc00ce97 100644 --- a/.github/workflows/contributor.yml +++ b/.github/workflows/contributor.yml @@ -11,7 +11,7 @@ on: jobs: Test: name: "'docs/CONTRIBUTORS' was signed" - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 - run: test_regress/t/t_dist_contributors.pl diff --git a/Changes b/Changes index ba4c752ba..bd1720f09 100644 --- a/Changes +++ b/Changes @@ -24,9 +24,21 @@ Verilator 5.001 devel Verilator 4.227 devel ========================== +**Announcement:** + +* The next release is anticipated primere Verilator Version 5. Please + consider beta-testing the github 'develop-v5' branch, which will soon + merge into the github 'master' branch (#3383). + **Minor:** -Fix crash in gate optimization of circular logic (#3543). [Bill Flynn] +* Support IEEE constant signal strengths (#3601). [Ryszard Rozak/Antmicro] +* Add --main to generate main() C++ (previously was experimental only). +* Fix thread saftey in SystemC VL_ASSIGN_SBW/WSB (#3494) (#3513). [Mladen Slijepcevic] +* Fix crash in gate optimization of circular logic (#3543). [Bill Flynn] +* Fix arguments in non-static method call (#3547) (#3582). [Gustav Svensk] +* Fix default --mod-prefix when --prefix is repeated (#3603). [Geza Lore] +* Fix typedef'ed class conversion to boolean (#3616). [Aleksander Kiryk] Verilator 4.226 2022-08-31 @@ -46,7 +58,7 @@ Verilator 4.226 2022-08-31 * Fix incorrect tristate logic (#3399) [shareefj, Vighnesh Iyer] * Fix incorrect bit op tree optimization (#3470). [algrobman] * Fix bisonpre for MSYS2 (#3471). -* Fix max memory usage (#3483). [Kamil Rakoczy] +* Fix max memory usage (#3483). [Kamil Rakoczy/Antmicro] * Fix empty string arguments to display (#3484). [Grulfen] * Fix table misoptimizing away display (#3488). [Stefan Post] * Fix unique_ptr memory header for MinGW64 (#3493). @@ -57,7 +69,7 @@ Verilator 4.226 2022-08-31 * Fix segfault exporting non-existant package (#3535). * Fix void-cast queue pop_front or pop_back (#3542) (#3364). [Drew Ranck] * Fix case statement comparing string literal (#3544). [Gustav Svensk] -* Fix === with some tristate constants (#3551). [Ryszard Rozak] +* Fix === with some tristate constants (#3551). [Ryszard Rozak/Antmicro] * Fix converting subclasses to string (#3552). [Arkadiusz Kozdra/Antmicro] * Fix --hierarchical with order-based pin connections (#3583) (#3585). [Kelin9298] diff --git a/Makefile.in b/Makefile.in index fc9b6b1a9..08271b047 100644 --- a/Makefile.in +++ b/Makefile.in @@ -391,10 +391,10 @@ yapf: FLAKE8 = flake8 FLAKE8_FLAGS = \ --extend-exclude=fastcov.py \ - --ignore=E123,E129,E251,E501,W503,W504,E701 + --ignore=E123,E129,E251,E402,E501,W503,W504,E701 PYLINT = pylint -PYLINT_FLAGS = --disable=R0801 +PYLINT_FLAGS = --score=n --disable=R0801 lint-py: -$(FLAKE8) $(FLAKE8_FLAGS) $(PY_PROGRAMS) diff --git a/README.rst b/README.rst index 8dd636245..d46296d02 100644 --- a/README.rst +++ b/README.rst @@ -28,7 +28,7 @@ Welcome to Verilator - |Logo| * - |verilator multithreaded performance| - **Fast** - * Outperforms many commercial simulators + * Outperforms many closed-source commercial simulators * Single- and multi-threaded output models * - **Widely Used** * Wide industry and academic deployment @@ -55,20 +55,19 @@ performing lint checks, and optionally inserting assertion checks and coverage-analysis points. It outputs single- or multi-threaded .cpp and .h files, the "Verilated" code. -The user writes a little C++/SystemC wrapper file, which instantiates the -"Verilated" model of the user's top level module. These C++/SystemC files -are then compiled by a C++ compiler (gcc/clang/MSVC++). Executing the -resulting executable performs the design simulation. Verilator also -supports linking Verilated generated libraries, optionally encrypted, into -other simulators. +These Verilated C++/SystemC files are then compiled by a C++ compiler +(gcc/clang/MSVC++), optionally along with a user's own C++/SystemC wrapper +file to instantiate the Verilated model. Executing the resulting executable +performs the design simulation. Verilator also supports linking Verilated +generated libraries, optionally encrypted, into other simulators. Verilator may not be the best choice if you are expecting a full featured -replacement for Incisive, ModelSim/Questa, VCS or another commercial -Verilog simulator, or if you are looking for a behavioral Verilog simulator -e.g. for a quick class project (we recommend `Icarus Verilog`_ for this.) -However, if you are looking for a path to migrate SystemVerilog to C++ or -SystemC, or your team is comfortable writing just a touch of C++ code, -Verilator is the tool for you. +replacement for a closed-source Verilog simulator, need SDF annotation, +mixed-signal simulation, or are doing a quick class project (we recommend +`Icarus Verilog`_ for classwork.) However, if you are looking for a path +to migrate SystemVerilog to C++/SystemC, or want high speed simulation of +synthesizable designs containing limited verification constructs, Verilator +is the tool for you. Performance @@ -85,9 +84,11 @@ multithreading (yielding 200-1000x total over interpreted simulators). Verilator has typically similar or better performance versus the closed-source Verilog simulators (Carbon Design Systems Carbonator, -Modelsim, Cadence Incisive/NC-Verilog, Synopsys VCS, VTOC, and Pragmatic -CVer/CVC). But, Verilator is open-sourced, so you can spend on computes -rather than licenses. Thus Verilator gives you the best cycles/dollar. +Modelsim/Questa, Cadence Incisive/NC-Verilog, Synopsys VCS, VTOC, and +Pragmatic CVer/CVC). But, Verilator is open-sourced, so you can spend on +computes rather than licenses. Thus Verilator gives you the best +cycles/dollar. + Installation & Documentation ============================ diff --git a/bin/verilator b/bin/verilator index 703a09ed4..b68812d61 100755 --- a/bin/verilator +++ b/bin/verilator @@ -344,6 +344,7 @@ detailed descriptions of these arguments. --main Generate a main C++ file --make Generate scripts for specified build tool -MAKEFLAGS Arguments to pass to make during --build + --main Generate C++ main() --max-num-width Maximum number width (default: 64K) --Mdir Name of output object directory --MMD Create .d dependency files diff --git a/bin/verilator_difftree b/bin/verilator_difftree index 3e8315691..d7c65a28e 100755 --- a/bin/verilator_difftree +++ b/bin/verilator_difftree @@ -38,7 +38,7 @@ def diff_dir(a, b): anyfile = False for base in sorted(files.keys()): - if (not 'a' in files[base]) or (not 'b' in files[base]): + if ('a' not in files[base]) or ('b' not in files[base]): continue a = files[base]['a'] b = files[base]['b'] diff --git a/bin/verilator_gantt b/bin/verilator_gantt index 616af30dc..03a7a16af 100755 --- a/bin/verilator_gantt +++ b/bin/verilator_gantt @@ -149,7 +149,8 @@ def report(): for thread in Threads: # Make potentially multiple characters per column for start in Threads[thread]: - if not Threads[thread][start]: continue + if not Threads[thread][start]: + continue cpu = Threads[thread][start]['cpu'] elapsed = Threads[thread][start]['end'] - start if cpu not in Global['cpus']: diff --git a/ci/ci-install.bash b/ci/ci-install.bash index 4f61f06c4..2e7325cea 100755 --- a/ci/ci-install.bash +++ b/ci/ci-install.bash @@ -19,6 +19,10 @@ set -x cd $(dirname "$0")/.. +# Avoid occasional cpan failures "Issued certificate has expired." +export PERL_LWP_SSL_VERIFY_HOSTNAME=0 +echo "check_certificate = off" >> ~/.wgetrc + fatal() { echo "ERROR: $(basename "$0"): $1" >&2; exit 1; } diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index aa66209c5..7a800bab7 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -82,6 +82,7 @@ Michael Killough Michaël Lefebvre Mike Popoloski Miodrag Milanović +Mladen Slijepcevic Morten Borup Petersen Mostafa Gamal Nandu Raj diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index 25891aa32..ce2140c7a 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -716,6 +716,15 @@ Summary: (e.g. ``-MAKEFLAGS -l -MAKEFLAGS -k``). Use of this option should not be required for simple builds using the host toolchain. +.. option:: --main + + Generates a top-level C++ main() file that supports parsing arguments, + but does not drive any inputs. This is sufficient to use for top-level + SystemVerilog designs that has no inputs, and does not need the C++ to + do any time advancement. + + Implies :vlopt:`--cc` if no other output mode was provided. + .. option:: --max-num-width Set the maximum number literal width (e.g. in 1024'd22 this it the diff --git a/docs/guide/simulating.rst b/docs/guide/simulating.rst index 01dd7f844..7209a0a19 100644 --- a/docs/guide/simulating.rst +++ b/docs/guide/simulating.rst @@ -7,9 +7,9 @@ Simulating (Verilated-Model Runtime) ************************************ -This section describes items related to simulating, that using a Verilated -model's executable. For the runtime arguments to a simulated model, see -:ref:`Simulation Runtime Arguments`. +This section describes items related to simulating, that is, the use of a +Verilated model's executable. For the runtime arguments to a simulated +model, see :ref:`Simulation Runtime Arguments`. .. _Benchmarking & Optimization: diff --git a/examples/make_protect_lib/sim_main.cpp b/examples/make_protect_lib/sim_main.cpp index b3096b4c5..fefcb0c5a 100644 --- a/examples/make_protect_lib/sim_main.cpp +++ b/examples/make_protect_lib/sim_main.cpp @@ -32,7 +32,7 @@ int main(int argc, char** argv, char** env) { // When tracing, the contents of the secret module will not be seen VerilatedVcdC* tfp = nullptr; const char* flag = contextp->commandArgsPlusMatch("trace"); - if (flag && 0 == strcmp(flag, "+trace")) { + if (flag && 0 == std::strcmp(flag, "+trace")) { contextp->traceEverOn(true); VL_PRINTF("Enabling waves into logs/vlt_dump.vcd...\n"); tfp = new VerilatedVcdC; diff --git a/examples/make_tracing_sc/sc_main.cpp b/examples/make_tracing_sc/sc_main.cpp index 93861ceea..3d3cb1392 100644 --- a/examples/make_tracing_sc/sc_main.cpp +++ b/examples/make_tracing_sc/sc_main.cpp @@ -89,7 +89,7 @@ int sc_main(int argc, char* argv[]) { // and if at run time passed the +trace argument, turn on tracing VerilatedVcdSc* tfp = nullptr; const char* flag = Verilated::commandArgsPlusMatch("trace"); - if (flag && 0 == strcmp(flag, "+trace")) { + if (flag && 0 == std::strcmp(flag, "+trace")) { cout << "Enabling waves into logs/vlt_dump.vcd...\n"; tfp = new VerilatedVcdSc; top->trace(tfp, 99); // Trace 99 levels of hierarchy diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index a7c3fcc73..8bcef8019 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -448,10 +448,17 @@ static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE { { \ const int words = VL_WORDS_I(obits); \ sc_biguint<(obits)> _butemp = (svar).read(); \ - for (int i = 0; i < words; ++i) { \ - int msb = ((i + 1) * VL_IDATASIZE) - 1; \ - msb = (msb >= (obits)) ? ((obits)-1) : msb; \ - (owp)[i] = _butemp.range(msb, i * VL_IDATASIZE).to_uint(); \ + uint32_t* chunk = _butemp.get_raw(); \ + int32_t lsb = 0; \ + while (lsb < obits - BITS_PER_DIGIT) { \ + const uint32_t data = *chunk; \ + ++chunk; \ + _vl_insert_WI(owp.data(), data, lsb + BITS_PER_DIGIT - 1, lsb); \ + lsb += BITS_PER_DIGIT; \ + } \ + if (lsb < obits) { \ + const uint32_t msb_data = *chunk; \ + _vl_insert_WI(owp.data(), msb_data, obits - 1, lsb); \ } \ (owp)[words - 1] &= VL_MASK_E(obits); \ } @@ -492,13 +499,23 @@ static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE { { (svar).write(rd); } #define VL_ASSIGN_SBQ(obits, svar, rd) \ { (svar).write(rd); } +#define VL_SC_BITS_PER_DIGIT 30 // This comes from sc_nbdefs.h BITS_PER_DIGIT #define VL_ASSIGN_SBW(obits, svar, rwp) \ { \ sc_biguint<(obits)> _butemp; \ - for (int i = 0; i < VL_WORDS_I(obits); ++i) { \ - int msb = ((i + 1) * VL_IDATASIZE) - 1; \ - msb = (msb >= (obits)) ? ((obits)-1) : msb; \ - _butemp.range(msb, i* VL_IDATASIZE) = (rwp)[i]; \ + int32_t lsb = 0; \ + uint32_t* chunk = _butemp.get_raw(); \ + while (lsb + VL_SC_BITS_PER_DIGIT < (obits)) { \ + static_assert(std::is_same::value, "IData and EData missmatch"); \ + const uint32_t data = VL_SEL_IWII(lsb + VL_SC_BITS_PER_DIGIT + 1, (rwp).data(), lsb, \ + VL_SC_BITS_PER_DIGIT); \ + *chunk = data & VL_MASK_E(VL_SC_BITS_PER_DIGIT); \ + ++chunk; \ + lsb += VL_SC_BITS_PER_DIGIT; \ + } \ + if (lsb < (obits)) { \ + const uint32_t msb_data = VL_SEL_IWII((obits) + 1, (rwp).data(), lsb, (obits)-lsb); \ + *chunk = msb_data & VL_MASK_E((obits)-lsb); \ } \ (svar).write(_butemp); \ } diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 2f1467f03..7694e1e69 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -165,22 +165,22 @@ string AstNode::prettyName(const string& namein) { continue; } if (pos[0] == '_' && pos[1] == '_') { // Short-circuit - if (0 == strncmp(pos, "__BRA__", 7)) { + if (0 == std::strncmp(pos, "__BRA__", 7)) { pretty += "["; pos += 7; continue; } - if (0 == strncmp(pos, "__KET__", 7)) { + if (0 == std::strncmp(pos, "__KET__", 7)) { pretty += "]"; pos += 7; continue; } - if (0 == strncmp(pos, "__DOT__", 7)) { + if (0 == std::strncmp(pos, "__DOT__", 7)) { pretty += "."; pos += 7; continue; } - if (0 == strncmp(pos, "__PVT__", 7)) { + if (0 == std::strncmp(pos, "__PVT__", 7)) { pretty += ""; pos += 7; continue; diff --git a/src/V3Ast.h b/src/V3Ast.h index 4be593993..11f320f70 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -517,8 +517,9 @@ public: return names[m_e]; } static void selfTest() { - UASSERT(0 == strcmp(VBasicDTypeKwd(_ENUM_MAX).ascii(), " MAX"), "SelfTest: Enum mismatch"); - UASSERT(0 == strcmp(VBasicDTypeKwd(_ENUM_MAX).dpiType(), " MAX"), + UASSERT(0 == std::strcmp(VBasicDTypeKwd(_ENUM_MAX).ascii(), " MAX"), + "SelfTest: Enum mismatch"); + UASSERT(0 == std::strcmp(VBasicDTypeKwd(_ENUM_MAX).dpiType(), " MAX"), "SelfTest: Enum mismatch"); } inline VBasicDTypeKwd() @@ -786,6 +787,10 @@ public: return (m_e == WIRE || m_e == WREAL || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1 || m_e == PORT || m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == VAR); } + bool isNet() const { + return (m_e == WIRE || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1 + || m_e == SUPPLY0 || m_e == SUPPLY1); + } bool isContAssignable() const { // In Verilog, always ok in SystemVerilog return (m_e == SUPPLY0 || m_e == SUPPLY1 || m_e == WIRE || m_e == WREAL || m_e == IMPLICITWIRE || m_e == TRIWIRE || m_e == TRI0 || m_e == TRI1 @@ -1029,6 +1034,32 @@ inline std::ostream& operator<<(std::ostream& os, const VParseRefExp& rhs) { return os << rhs.ascii(); } +//###################################################################### + +class VStrength final { +public: + enum en : uint8_t { HIGHZ, SMALL, MEDIUM, WEAK, LARGE, PULL, STRONG, SUPPLY }; + enum en m_e; + + inline VStrength(en strengthLevel) + : m_e(strengthLevel) {} + explicit inline VStrength(int _e) + : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning + + operator en() const { return m_e; } + const char* ascii() const { + static const char* const names[] + = {"highz", "small", "medium", "weak", "large", "pull", "strong", "supply"}; + return names[m_e]; + } +}; +inline bool operator==(const VStrength& lhs, const VStrength& rhs) { return lhs.m_e == rhs.m_e; } +inline bool operator==(const VStrength& lhs, VStrength::en rhs) { return lhs.m_e == rhs; } +inline bool operator==(VStrength::en lhs, const VStrength& rhs) { return lhs == rhs.m_e; } +inline std::ostream& operator<<(std::ostream& os, const VStrength& rhs) { + return os << rhs.ascii(); +} + //###################################################################### // VNumRange - Structure containing numeric range information // See also AstRange, which is a symbolic version of this diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 59c3d4982..2d6b2e4da 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1834,6 +1834,10 @@ void AstSenItem::dump(std::ostream& str) const { this->AstNode::dump(str); str << " [" << edgeType().ascii() << "]"; } +void AstStrengthSpec::dump(std::ostream& str) const { + this->AstNode::dump(str); + str << " (" << m_s0.ascii() << ", " << m_s1.ascii() << ")"; +} void AstParseRef::dump(std::ostream& str) const { this->AstNode::dump(str); str << " [" << expect().ascii() << "]"; diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index d2bfd630f..1cb1ac17e 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -290,6 +290,23 @@ public: virtual bool same(const AstNode* /*samep*/) const override { return true; } }; +class AstStrengthSpec final : public AstNode { +private: + VStrength m_s0; // Drive 0 strength + VStrength m_s1; // Drive 1 strength + +public: + AstStrengthSpec(FileLine* fl, VStrength s0, VStrength s1) + : ASTGEN_SUPER_StrengthSpec(fl) + , m_s0{s0} + , m_s1{s1} {} + + ASTNODE_NODE_FUNCS(StrengthSpec) + VStrength strength0() { return m_s0; } + VStrength strength1() { return m_s1; } + virtual void dump(std::ostream& str) const override; +}; + class AstGatePin final : public AstNodeMath { // Possibly expand a gate primitive input pin value to match the range of the gate primitive public: @@ -2098,6 +2115,7 @@ private: bool m_isRand : 1; // Random variable bool m_isConst : 1; // Table contains constant data bool m_isContinuously : 1; // Ever assigned continuously (for force/release) + bool m_hasStrengthAssignment : 1; // Is on LHS of assignment with strength specifier bool m_isStatic : 1; // Static C variable (for Verilog see instead isAutomatic) bool m_isPulldown : 1; // Tri0 bool m_isPullup : 1; // Tri1 @@ -2139,6 +2157,7 @@ private: m_isRand = false; m_isConst = false; m_isContinuously = false; + m_hasStrengthAssignment = false; m_isStatic = false; m_isPulldown = false; m_isPullup = false; @@ -2303,6 +2322,8 @@ public: void isIfaceParent(bool flag) { m_isIfaceParent = flag; } void funcLocal(bool flag) { m_funcLocal = flag; } void funcReturn(bool flag) { m_funcReturn = flag; } + void hasStrengthAssignment(bool flag) { m_hasStrengthAssignment = flag; } + bool hasStrengthAssignment() { return m_hasStrengthAssignment; } void isDpiOpenArray(bool flag) { m_isDpiOpenArray = flag; } bool isDpiOpenArray() const { return m_isDpiOpenArray; } bool isHideLocal() const { return m_isHideLocal; } @@ -2340,6 +2361,7 @@ public: bool isIfaceRef() const { return (varType() == VVarType::IFACEREF); } bool isIfaceParent() const { return m_isIfaceParent; } bool isSignal() const { return varType().isSignal(); } + bool isNet() const { return varType().isNet(); } bool isTemp() const { return varType().isTemp(); } bool isToggleCoverable() const { return ((isIO() || isSignal()) @@ -3648,6 +3670,8 @@ public: AstAssignW(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* timingControlp = nullptr) : ASTGEN_SUPER_AssignW(fl, lhsp, rhsp, timingControlp) {} ASTNODE_NODE_FUNCS(AssignW) + AstStrengthSpec* strengthSpecp() const { return VN_AS(op4p(), StrengthSpec); } + void strengthSpecp(AstStrengthSpec* const strengthSpecp) { setOp4p((AstNode*)strengthSpecp); } virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { AstNode* const controlp = timingControlp() ? timingControlp()->cloneTree(false) : nullptr; return new AstAssignW(this->fileline(), lhsp, rhsp, controlp); diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index d2e9e66d7..4bdc05cb4 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -86,7 +86,7 @@ private: string::size_type pos; while ((pos = dottedname.find("__DOT__")) != string::npos) { const string ident = dottedname.substr(0, pos); - dottedname = dottedname.substr(pos + strlen("__DOT__")); + dottedname = dottedname.substr(pos + std::strlen("__DOT__")); if (nodep->name() != "") { m_displayScope = dot(m_displayScope, ident); m_namedScope = dot(m_namedScope, ident); diff --git a/src/V3Const.cpp b/src/V3Const.cpp index c962996be..9b6cfe84c 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -2872,6 +2872,7 @@ private: if (m_wremove && !m_params && m_doNConst && m_modp && operandConst(nodep->rhsp()) && !VN_AS(nodep->rhsp(), Const)->num().isFourState() && varrefp // Don't do messes with BITREFs/ARRAYREFs + && !varrefp->varp()->hasStrengthAssignment() // Strengths are resolved in V3Tristate && !varrefp->varp()->valuep() // Not already constified && !varrefp->varScopep()) { // Not scoped (or each scope may have different initial // value) diff --git a/src/V3EmitCBase.cpp b/src/V3EmitCBase.cpp index 1e3e9383f..40198fa76 100644 --- a/src/V3EmitCBase.cpp +++ b/src/V3EmitCBase.cpp @@ -57,11 +57,11 @@ string EmitCBaseVisitor::funcNameProtect(const AstCFunc* nodep, const AstNodeMod return name; } -AstCFile* EmitCBaseVisitor::newCFile(const string& filename, bool slow, bool source) { +AstCFile* EmitCBaseVisitor::newCFile(const string& filename, bool slow, bool source, bool add) { AstCFile* const cfilep = new AstCFile(v3Global.rootp()->fileline(), filename); cfilep->slow(slow); cfilep->source(source); - v3Global.rootp()->addFilesp(cfilep); + if (add) v3Global.rootp()->addFilesp(cfilep); return cfilep; } diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index 66b954f35..2451cfdfc 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -100,7 +100,7 @@ public: && (varp->basicp() && !varp->basicp()->isOpaque()); // Aggregates can't be anon } - static AstCFile* newCFile(const string& filename, bool slow, bool source); + static AstCFile* newCFile(const string& filename, bool slow, bool source, bool add = true); string cFuncArgs(const AstCFunc* nodep); void emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp, bool withScope); void emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp, bool cLinkage = false); diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 43d016c3f..1426679a7 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -36,18 +36,20 @@ constexpr int EMITC_NUM_CONSTW = 8; class EmitCLazyDecls final : public VNVisitor { // NODE STATE/TYPES - // AstNode::user2() -> bool. Already emitted decl for symbols. - const VNUser2InUse m_inuser2; + // None allowed to support threaded emitting // MEMBERS std::unordered_set m_emittedManually; // Set of names already declared manually. EmitCBaseVisitor& m_emitter; // For access to file output bool m_needsBlankLine = false; // Emit blank line if any declarations were emitted (cosmetic) + std::set m_emitted; // -> in set. Already emitted decl for symbols. // METHODS + bool declaredOnce(AstNode* nodep) { return m_emitted.insert(nodep).second; } + void lazyDeclare(AstCFunc* funcp) { // Already declared in this compilation unit - if (funcp->user2SetOnce()) return; + if (!declaredOnce(funcp)) return; // Check if this kind of function is lazily declared if (!(funcp->isMethod() && funcp->isLoose()) && !funcp->dpiImportPrototype()) return; // Already declared manually @@ -58,7 +60,7 @@ class EmitCLazyDecls final : public VNVisitor { } void lazyDeclareConstPoolVar(AstVar* varp) { - if (varp->user2SetOnce()) return; // Already declared + if (!declaredOnce(varp)) return; // Already declared const string nameProtect = m_emitter.topClassName() + "__ConstPool__" + varp->nameProtect(); m_emitter.puts("extern const "); @@ -106,8 +108,8 @@ public: m_emitter.puts(suffix); m_emitter.ensureNewLine(); } - void declared(AstCFunc* nodep) { nodep->user2SetOnce(); } - void reset() { AstNode::user2ClearTree(); } + void declared(AstCFunc* nodep) { m_emitted.insert(nodep); } + void reset() { m_emitted.clear(); } }; //###################################################################### diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index ee053cd4b..f4c90a5ed 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -148,6 +148,7 @@ class EmitCImp final : EmitCFunc { const std::set* m_requiredHeadersp; // Header files required by output file std::string m_subFileName; // substring added to output filenames V3UniqueNames m_uniqueNames; // For generating unique file names + std::deque& m_cfilesr; // cfiles generated by this emit // METHODS void openNextOutputFile(const std::set& headers, const string& subFileName) { @@ -160,7 +161,8 @@ class EmitCImp final : EmitCFunc { // Unfortunately we have some lint checks here, so we can't just skip processing. // We should move them to a different stage. const string filename = VL_DEV_NULL; - newCFile(filename, /* slow: */ m_slow, /* source: */ true); + m_cfilesr.push_back( + newCFile(filename, /* slow: */ m_slow, /* source: */ true, /* add */ false)); m_ofp = new V3OutCFile(filename); } else { string filename = v3Global.opt.makeDir() + "/" + prefixNameProtect(m_fileModp); @@ -170,7 +172,8 @@ class EmitCImp final : EmitCFunc { } if (m_slow) filename += "__Slow"; filename += ".cpp"; - newCFile(filename, /* slow: */ m_slow, /* source: */ true); + m_cfilesr.push_back( + newCFile(filename, /* slow: */ m_slow, /* source: */ true, /* add */ false)); m_ofp = v3Global.opt.systemC() ? new V3OutScFile(filename) : new V3OutCFile(filename); } @@ -527,9 +530,10 @@ class EmitCImp final : EmitCFunc { EmitCFunc::visit(nodep); } - explicit EmitCImp(const AstNodeModule* modp, bool slow) + explicit EmitCImp(const AstNodeModule* modp, bool slow, std::deque& cfilesr) : m_fileModp{modp} - , m_slow{slow} { + , m_slow{slow} + , m_cfilesr{cfilesr} { UINFO(5, " Emitting implementation of " << prefixNameProtect(modp) << endl); m_modp = modp; @@ -548,7 +552,9 @@ class EmitCImp final : EmitCFunc { virtual ~EmitCImp() override = default; public: - static void main(const AstNodeModule* modp, bool slow) { EmitCImp{modp, slow}; } + static void main(const AstNodeModule* modp, bool slow, std::deque& cfilesr) { + EmitCImp{modp, slow, cfilesr}; + } }; //###################################################################### @@ -556,14 +562,14 @@ public: class EmitCTrace final : EmitCFunc { // NODE STATE/TYPES - // Cleared on netlist - // AstNode::user1() -> int. Enum number - const VNUser1InUse m_inuser1; + // None allowed to support threaded emitting // MEMBERS const bool m_slow; // Making slow file int m_enumNum = 0; // Enumeration number (whole netlist) V3UniqueNames m_uniqueNames; // For generating unique file names + std::unordered_map m_enumNumMap; // EnumDType to enumeration number + std::deque& m_cfilesr; // cfiles generated by this emit // METHODS void openNextOutputFile() { @@ -578,8 +584,9 @@ class EmitCTrace final : EmitCFunc { if (m_slow) filename += "__Slow"; filename += ".cpp"; - AstCFile* const cfilep = newCFile(filename, m_slow, true /*source*/); + AstCFile* const cfilep = newCFile(filename, m_slow, true /*source*/, false /*add*/); cfilep->support(true); + m_cfilesr.push_back(cfilep); if (optSystemC()) { m_ofp = new V3OutScFile(filename); @@ -715,10 +722,10 @@ class EmitCTrace final : EmitCFunc { // Skip over refs-to-refs, but stop before final ref so can get data type name // Alternatively back in V3Width we could push enum names from upper typedefs if (AstEnumDType* const enump = VN_CAST(nodep->skipRefToEnump(), EnumDType)) { - int enumNum = enump->user1(); + int enumNum = m_enumNumMap[enump]; if (!enumNum) { enumNum = ++m_enumNum; - enump->user1(enumNum); + m_enumNumMap[enump] = enumNum; int nvals = 0; puts("{\n"); puts("const char* " + protect("__VenumItemNames") + "[]\n"); @@ -868,8 +875,9 @@ class EmitCTrace final : EmitCFunc { } } - explicit EmitCTrace(AstNodeModule* modp, bool slow) - : m_slow{slow} { + explicit EmitCTrace(AstNodeModule* modp, bool slow, std::deque& cfilesr) + : m_slow{slow} + , m_cfilesr{cfilesr} { m_modp = modp; // Open output file openNextOutputFile(); @@ -883,7 +891,9 @@ class EmitCTrace final : EmitCFunc { virtual ~EmitCTrace() override = default; public: - static void main(AstNodeModule* modp, bool slow) { EmitCTrace{modp, slow}; } + static void main(AstNodeModule* modp, bool slow, std::deque& cfilesr) { + EmitCTrace{modp, slow, cfilesr}; + } }; //###################################################################### @@ -893,19 +903,27 @@ void V3EmitC::emitcImp() { UINFO(2, __FUNCTION__ << ": " << endl); // Make parent module pointers available. const EmitCParentModule emitCParentModule; + std::list> cfiles; // Process each module in turn for (const AstNode* nodep = v3Global.rootp()->modulesp(); nodep; nodep = nodep->nextp()) { if (VN_IS(nodep, Class)) continue; // Imped with ClassPackage const AstNodeModule* const modp = VN_AS(nodep, NodeModule); - EmitCImp::main(modp, /* slow: */ true); - EmitCImp::main(modp, /* slow: */ false); + cfiles.emplace_back(); + EmitCImp::main(modp, /* slow: */ true, cfiles.back()); + cfiles.emplace_back(); + EmitCImp::main(modp, /* slow: */ false, cfiles.back()); } // Emit trace routines (currently they can only exist in the top module) if (v3Global.opt.trace() && !v3Global.opt.lintOnly()) { - EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ true); - EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ false); + cfiles.emplace_back(); + EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ true, cfiles.back()); + cfiles.emplace_back(); + EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ false, cfiles.back()); + } + for (const auto& collr : cfiles) { + for (const auto cfilep : collr) v3Global.rootp()->addFilesp(cfilep); } } diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp index 443e4f3f8..74104e500 100644 --- a/src/V3EmitCModel.cpp +++ b/src/V3EmitCModel.cpp @@ -555,7 +555,7 @@ class EmitCModel final : public EmitCFunc { // Some hackery to locate handle__V for trace_init_task // Considered a pragma on the handle, but that still doesn't help us attach it here string handle = funcp->name(); - const size_t wr_len = strlen("__Vdpiimwrap_"); + const size_t wr_len = std::strlen("__Vdpiimwrap_"); UASSERT_OBJ(handle.substr(0, wr_len) == "__Vdpiimwrap_", funcp, "Strange trace_init_task function name"); handle = "vlSymsp->TOP." + handle.substr(wr_len); diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 8195d705d..d2c3fbf93 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -211,7 +211,7 @@ class EmitCSyms final : EmitCBaseVisitor { const string::size_type dpos = whole.rfind("__DOT__"); if (dpos != string::npos) { scpName = whole.substr(0, dpos); - varBase = whole.substr(dpos + strlen("__DOT__")); + varBase = whole.substr(dpos + std::strlen("__DOT__")); } else { varBase = whole; } diff --git a/src/V3File.cpp b/src/V3File.cpp index 57452b969..c4adf58bc 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -94,7 +94,7 @@ class V3FileDependImp final { const string fn = filename(); const int err = stat(fn.c_str(), &m_stat); if (err != 0) { - memset(&m_stat, 0, sizeof(m_stat)); + std::memset(&m_stat, 0, sizeof(m_stat)); m_stat.st_mtime = 1; m_exists = false; // Not an error... This can occur due to `line directives in the .vpp files @@ -389,7 +389,7 @@ private: if (!m_pidExited && waitpid(m_pid, &m_pidStatus, hang ? 0 : WNOHANG)) { UINFO(1, "--pipe-filter: Exited, status " << m_pidStatus << " exit=" << WEXITSTATUS(m_pidStatus) << " err" - << strerror(errno) << endl); + << std::strerror(errno) << endl); m_readEof = true; m_pidExited = true; } @@ -495,7 +495,7 @@ private: constexpr int P_WR = 1; if (pipe(fd_stdin) != 0 || pipe(fd_stdout) != 0) { - v3fatal("--pipe-filter: Can't pipe: " << strerror(errno)); + v3fatal("--pipe-filter: Can't pipe: " << std::strerror(errno)); } if (fd_stdin[P_RD] <= 2 || fd_stdin[P_WR] <= 2 || fd_stdout[P_RD] <= 2 || fd_stdout[P_WR] <= 2) { @@ -507,7 +507,7 @@ private: UINFO(1, "--pipe-filter: /bin/sh -c " << command << endl); const pid_t pid = fork(); - if (pid < 0) v3fatal("--pipe-filter: fork failed: " << strerror(errno)); + if (pid < 0) v3fatal("--pipe-filter: fork failed: " << std::strerror(errno)); if (pid == 0) { // Child UINFO(6, "In child\n"); close(fd_stdin[P_WR]); @@ -518,7 +518,7 @@ private: execl("/bin/sh", "sh", "-c", command.c_str(), static_cast(nullptr)); // Don't use v3fatal, we don't share the common structures any more - fprintf(stderr, "--pipe-filter: exec failed: %s\n", strerror(errno)); + fprintf(stderr, "--pipe-filter: exec failed: %s\n", std::strerror(errno)); _exit(1); } else { // Parent UINFO(6, "In parent, child pid " << pid << " stdin " << fd_stdin[P_WR] << "->" diff --git a/src/V3File.h b/src/V3File.h index 309f136c9..95b29eb8d 100644 --- a/src/V3File.h +++ b/src/V3File.h @@ -224,7 +224,7 @@ private: std::size_t len = strlen(str); std::size_t availableBytes = WRITE_BUFFER_SIZE_BYTES - m_usedBytes; while (VL_UNLIKELY(len >= availableBytes)) { - memcpy(m_bufferp->data() + m_usedBytes, str, availableBytes); + std::memcpy(m_bufferp->data() + m_usedBytes, str, availableBytes); m_usedBytes = WRITE_BUFFER_SIZE_BYTES; writeBlock(); str += availableBytes; @@ -232,7 +232,7 @@ private: availableBytes = WRITE_BUFFER_SIZE_BYTES; } if (len > 0) { - memcpy(m_bufferp->data() + m_usedBytes, str, len); + std::memcpy(m_bufferp->data() + m_usedBytes, str, len); m_usedBytes += len; } } diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index e5b2e32ae..fd7669275 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -185,7 +185,7 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) { const char* const ln = textp; while (*textp && !isspace(*textp)) textp++; if (isdigit(*ln)) { - lineno(atoi(ln)); + lineno(std::atoi(ln)); } else { fail = true; } @@ -207,7 +207,7 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) { // Grab level while (*textp && (isspace(*textp) || *textp == '"')) textp++; if (isdigit(*textp)) { - enterExitRef = atoi(textp); + enterExitRef = std::atoi(textp); if (enterExitRef >= 3) fail = true; } else { enterExitRef = 0; diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 02e6b439b..493beaf4d 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -919,7 +919,7 @@ class LinkDotFindVisitor final : public VNVisitor { string::size_type pos; if ((pos = dottedname.rfind("__DOT__")) != string::npos) { const string dotted = dottedname.substr(0, pos); - const string ident = dottedname.substr(pos + strlen("__DOT__")); + const string ident = dottedname.substr(pos + std::strlen("__DOT__")); string baddot; VSymEnt* okSymp; aboveSymp = m_statep->findDotted(nodep->fileline(), aboveSymp, dotted, baddot, okSymp); diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp index 9ef0c248d..09c91ff1b 100644 --- a/src/V3LinkLValue.cpp +++ b/src/V3LinkLValue.cpp @@ -37,6 +37,7 @@ private: // STATE bool m_setContinuously = false; // Set that var has some continuous assignment + bool m_setStrengthSpecified = false; // Set that var has assignment with strength specified. VAccess m_setRefLvalue; // Set VarRefs to lvalues for pin assignments AstNodeFTask* m_ftaskp = nullptr; // Function or task we're inside @@ -51,6 +52,9 @@ private: if (nodep->varp()) { if (nodep->access().isWriteOrRW() && m_setContinuously) { nodep->varp()->isContinuously(true); + // Strength may only be specified in continuous assignment, + // so it is needed to check only if m_setContinuously is true + if (m_setStrengthSpecified) nodep->varp()->hasStrengthAssignment(true); } if (nodep->access().isWriteOrRW() && !m_ftaskp && nodep->varp()->isReadOnly()) { nodep->v3warn(ASSIGNIN, @@ -78,9 +82,13 @@ private: { m_setRefLvalue = VAccess::WRITE; m_setContinuously = VN_IS(nodep, AssignW) || VN_IS(nodep, AssignAlias); + if (AstAssignW* assignwp = VN_CAST(nodep, AssignW)) { + if (assignwp->strengthSpecp()) m_setStrengthSpecified = true; + } iterateAndNextNull(nodep->lhsp()); m_setRefLvalue = VAccess::NOCHANGE; m_setContinuously = false; + m_setStrengthSpecified = false; iterateAndNextNull(nodep->rhsp()); } } diff --git a/src/V3Number.cpp b/src/V3Number.cpp index d7473cd29..81b059442 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -156,14 +156,15 @@ void V3Number::V3NumberCreate(AstNode* nodep, const char* sourcep, FileLine* fl) } value_startp = cp; - if (atoi(widthn.c_str())) { - if (atoi(widthn.c_str()) < 0 || atoi(widthn.c_str()) > v3Global.opt.maxNumWidth()) { + if (std::atoi(widthn.c_str())) { + if (std::atoi(widthn.c_str()) < 0 + || std::atoi(widthn.c_str()) > v3Global.opt.maxNumWidth()) { // atoi might convert large number to negative, so can't tell which v3error("Unsupported: Width of number exceeds implementation limit: " << sourcep << " (IEEE 1800-2017 6.9.1)"); width(v3Global.opt.maxNumWidth(), true); } else { - width(atoi(widthn.c_str()), true); + width(std::atoi(widthn.c_str()), true); } } } else { @@ -278,7 +279,8 @@ void V3Number::V3NumberCreate(AstNode* nodep, const char* sourcep, FileLine* fl) } } else { // Convert bin/octal number to hex - for (const char* cp = value_startp + strlen(value_startp) - 1; cp >= value_startp; cp--) { + for (const char* cp = value_startp + std::strlen(value_startp) - 1; cp >= value_startp; + cp--) { if (*cp != '_' && *cp != '0' && obit >= width()) { v3error("Too many digits for " << width() << " bit number: " << sourcep); break; @@ -698,7 +700,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const { if (fmtsize != "0") str += ' '; } } - const size_t fmtsizen = static_cast(atoi(fmtsize.c_str())); + const size_t fmtsizen = static_cast(std::atoi(fmtsize.c_str())); str = displayPad(fmtsizen, ' ', left, str); return str; } @@ -747,7 +749,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const { } const bool zeropad = fmtsize.length() > 0 && fmtsize[0] == '0'; // fmtsize might have changed since we parsed the %fmtsize - const size_t fmtsizen = static_cast(atoi(fmtsize.c_str())); + const size_t fmtsizen = static_cast(std::atoi(fmtsize.c_str())); str = displayPad(fmtsizen, (zeropad ? '0' : ' '), left, str); return str; } @@ -802,7 +804,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const { return str; } case '@': { // Packed string - const size_t fmtsizen = static_cast(atoi(fmtsize.c_str())); + const size_t fmtsizen = static_cast(std::atoi(fmtsize.c_str())); str = displayPad(fmtsizen, ' ', left, toString()); return str; } diff --git a/src/V3OptionParser.cpp b/src/V3OptionParser.cpp index 308a26e10..8035916e7 100644 --- a/src/V3OptionParser.cpp +++ b/src/V3OptionParser.cpp @@ -130,8 +130,8 @@ V3OptionParser::ActionIfs* V3OptionParser::find(const char* optp) { for (auto&& act : m_pimpl->m_options) { if (act.second->isFOnOffAllowed()) { // Find starts with "-fno" if (const char* const nop - = VString::startsWith(optp, "-fno-") ? (optp + strlen("-fno-")) : nullptr) { - if (act.first.substr(strlen("-f"), std::string::npos) + = VString::startsWith(optp, "-fno-") ? (optp + std::strlen("-fno-")) : nullptr) { + if (act.first.substr(std::strlen("-f"), std::string::npos) == nop) { // [-f]opt = [-fno-]opt return act.second.get(); } @@ -139,7 +139,7 @@ V3OptionParser::ActionIfs* V3OptionParser::find(const char* optp) { } if (act.second->isOnOffAllowed()) { // Find starts with "-no" if (const char* const nop - = VString::startsWith(optp, "-no") ? (optp + strlen("-no")) : nullptr) { + = VString::startsWith(optp, "-no") ? (optp + std::strlen("-no")) : nullptr) { if (act.first == nop || act.first == (std::string{"-"} + nop)) { return act.second.get(); } @@ -206,7 +206,7 @@ void V3OptionParser::finalize() { m_pimpl->m_spellCheck.pushCandidate(opt.first); if (opt.second->isFOnOffAllowed()) { m_pimpl->m_spellCheck.pushCandidate( - "-fno-" + opt.first.substr(strlen("-f"), std::string::npos)); + "-fno-" + opt.first.substr(std::strlen("-f"), std::string::npos)); } if (opt.second->isOnOffAllowed()) m_pimpl->m_spellCheck.pushCandidate("-no" + opt.first); } diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 1f50989cc..5e0a4a57f 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -435,6 +435,11 @@ string V3Options::allArgsStringForHierBlock(bool forTop) const { return out; } +void V3Options::ccSet() { // --cc + m_outFormatOk = true; + m_systemC = false; +} + //###################################################################### // File searching @@ -727,9 +732,10 @@ bool V3Options::coroutineSupport() { // V3 Options notification methods void V3Options::notify() { - FileLine* const cmdfl = new FileLine(FileLine::commandLineFilename()); - // Notify that all arguments have been passed and final modification can be made. + FileLine* const cmdfl = new FileLine{FileLine::commandLineFilename()}; + + if (!outFormatOk() && v3Global.opt.main()) ccSet(); // --main implies --cc if not provided if (!outFormatOk() && !cdc() && !dpiHdrOnly() && !lintOnly() && !preprocOnly() && !xmlOnly()) { v3fatal("verilator: Need --cc, --sc, --cdc, --dpi-hdr-only, --lint-only, " "--xml-only or --E option"); @@ -910,8 +916,8 @@ void V3Options::parseOpts(FileLine* fl, int argc, char** argv) { //====================================================================== bool V3Options::suffixed(const string& sw, const char* arg) { - if (strlen(arg) > sw.length()) return false; - return (0 == strcmp(sw.c_str() + sw.length() - strlen(arg), arg)); + if (std::strlen(arg) > sw.length()) return false; + return (0 == std::strcmp(sw.c_str() + sw.length() - std::strlen(arg), arg)); } void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char** argv) { @@ -1010,10 +1016,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-build", Set, &m_build); DECL_OPTION("-CFLAGS", CbVal, callStrSetter(&V3Options::addCFlags)); - DECL_OPTION("-cc", CbCall, [this]() { - m_outFormatOk = true; - m_systemC = false; - }); + DECL_OPTION("-cc", CbCall, [this]() { ccSet(); }); DECL_OPTION("-cdc", OnOff, &m_cdc); DECL_OPTION("-clk", CbVal, callStrSetter(&V3Options::addClocker)); DECL_OPTION("-no-clk", CbVal, callStrSetter(&V3Options::addNoClocker)); @@ -1024,15 +1027,15 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-comp-limit-parens", Set, &m_compLimitParens).undocumented(); DECL_OPTION("-comp-limit-syms", CbVal, [](int val) { VName::maxLength(val); }).undocumented(); DECL_OPTION("-compiler", CbVal, [this, fl](const char* valp) { - if (!strcmp(valp, "clang")) { + if (!std::strcmp(valp, "clang")) { m_compLimitBlocks = 80; // limit unknown m_compLimitMembers = 64; // soft limit, has slowdown bug as of clang++ 3.8 m_compLimitParens = 240; // controlled by -fbracket-depth, which defaults to 256 - } else if (!strcmp(valp, "gcc")) { + } else if (!std::strcmp(valp, "gcc")) { m_compLimitBlocks = 0; // Bug free m_compLimitMembers = 64; // soft limit, has slowdown bug as of g++ 7.1 m_compLimitParens = 240; // Unlimited, but generate same code as for clang - } else if (!strcmp(valp, "msvc")) { + } else if (!std::strcmp(valp, "msvc")) { m_compLimitBlocks = 80; // 128, but allow some room m_compLimitMembers = 0; // probably ok, and AFAIK doesn't support anon structs m_compLimitParens = 80; // 128, but allow some room @@ -1183,11 +1186,11 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char m_makeDir = valp; addIncDirFallback(m_makeDir); // Need to find generated files there too }); - DECL_OPTION("-main", OnOff, &m_main).undocumented(); // Future + DECL_OPTION("-main", OnOff, &m_main); DECL_OPTION("-make", CbVal, [this, fl](const char* valp) { - if (!strcmp(valp, "cmake")) { + if (!std::strcmp(valp, "cmake")) { m_cmake = true; - } else if (!strcmp(valp, "gmake")) { + } else if (!std::strcmp(valp, "gmake")) { m_gmake = true; } else { fl->v3fatal("Unknown --make system specified: '" << valp << "'"); @@ -1280,10 +1283,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-pins-uint8", OnOff, &m_pinsUint8); DECL_OPTION("-pipe-filter", Set, &m_pipeFilter); DECL_OPTION("-pp-comments", OnOff, &m_ppComments); - DECL_OPTION("-prefix", CbVal, [this](const char* valp) { - m_prefix = valp; - if (m_modPrefix == "") m_modPrefix = m_prefix; - }); + DECL_OPTION("-prefix", Set, &m_prefix); DECL_OPTION("-private", CbCall, [this]() { m_public = false; }); DECL_OPTION("-prof-c", OnOff, &m_profC); DECL_OPTION("-prof-cfuncs", CbCall, [this]() { m_profC = m_profCFuncs = true; }); @@ -1339,13 +1339,13 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char if (m_threads < 0) fl->v3fatal("--threads must be >= 0: " << valp); }); DECL_OPTION("-threads-dpi", CbVal, [this, fl](const char* valp) { - if (!strcmp(valp, "all")) { + if (!std::strcmp(valp, "all")) { m_threadsDpiPure = true; m_threadsDpiUnpure = true; - } else if (!strcmp(valp, "none")) { + } else if (!std::strcmp(valp, "none")) { m_threadsDpiPure = false; m_threadsDpiUnpure = false; - } else if (!strcmp(valp, "pure")) { + } else if (!std::strcmp(valp, "pure")) { m_threadsDpiPure = true; m_threadsDpiUnpure = false; } else { @@ -1481,13 +1481,13 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-waiver-output", Set, &m_waiverOutput); DECL_OPTION("-x-assign", CbVal, [this, fl](const char* valp) { - if (!strcmp(valp, "0")) { + if (!std::strcmp(valp, "0")) { m_xAssign = "0"; - } else if (!strcmp(valp, "1")) { + } else if (!std::strcmp(valp, "1")) { m_xAssign = "1"; - } else if (!strcmp(valp, "fast")) { + } else if (!std::strcmp(valp, "fast")) { m_xAssign = "fast"; - } else if (!strcmp(valp, "unique")) { + } else if (!std::strcmp(valp, "unique")) { m_xAssign = "unique"; } else { fl->v3fatal("Unknown setting for --x-assign: '" @@ -1496,11 +1496,11 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char } }); DECL_OPTION("-x-initial", CbVal, [this, fl](const char* valp) { - if (!strcmp(valp, "0")) { + if (!std::strcmp(valp, "0")) { m_xInitial = "0"; - } else if (!strcmp(valp, "fast")) { + } else if (!std::strcmp(valp, "fast")) { m_xInitial = "fast"; - } else if (!strcmp(valp, "unique")) { + } else if (!std::strcmp(valp, "unique")) { m_xInitial = "unique"; } else { fl->v3fatal("Unknown setting for --x-initial: '" @@ -1522,11 +1522,12 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char for (int i = 0; i < argc;) { UINFO(9, " Option: " << argv[i] << endl); - if (!strcmp(argv[i], "-j") || !strcmp(argv[i], "--j")) { // Allow gnu -- switches + if (!std::strcmp(argv[i], "-j") + || !std::strcmp(argv[i], "--j")) { // Allow gnu -- switches ++i; m_buildJobs = 0; // Unlimited parallelism if (i < argc && isdigit(argv[i][0])) { - m_buildJobs = atoi(argv[i]); + m_buildJobs = std::atoi(argv[i]); if (m_buildJobs <= 0) { fl->v3error("-j accepts positive integer, but '" << argv[i] << "' is passed"); } diff --git a/src/V3Options.h b/src/V3Options.h index 4b1b7a016..ad966e5b5 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -410,8 +410,9 @@ public: void addNoClocker(const string& signame); void addVFile(const string& filename); void addForceInc(const string& filename); - void notify(); bool available() const { return m_available; } + void ccSet(); + void notify(); // ACCESSORS (options) bool preprocOnly() const { return m_preprocOnly; } diff --git a/src/V3Os.cpp b/src/V3Os.cpp index c410c6735..2abc200c0 100644 --- a/src/V3Os.cpp +++ b/src/V3Os.cpp @@ -347,7 +347,7 @@ int V3Os::system(const string& command) { const int ret = ::system(command.c_str()); if (VL_UNCOVERABLE(ret == -1)) { v3fatal("Failed to execute command:" // LCOV_EXCL_LINE - << command << " " << strerror(errno)); + << command << " " << std::strerror(errno)); return -1; // LCOV_EXCL_LINE } else { UASSERT(WIFEXITED(ret), "system(" << command << ") returned unexpected value of " << ret); diff --git a/src/V3ParseGrammar.cpp b/src/V3ParseGrammar.cpp index 8e95d13c8..66670338e 100644 --- a/src/V3ParseGrammar.cpp +++ b/src/V3ParseGrammar.cpp @@ -84,9 +84,13 @@ AstArg* V3ParseGrammar::argWrapList(AstNode* nodep) { } AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, const string& name, int value) { - return new AstAssignW( - fileline, new AstVarRef(fileline, name, VAccess::WRITE), - new AstConst(fileline, AstConst::StringToParse(), (value ? "'1" : "'0"))); + AstAssignW* assignp + = new AstAssignW{fileline, new AstVarRef{fileline, name, VAccess::WRITE}, + new AstConst{fileline, AstConst::StringToParse{}, (value ? "'1" : "'0")}}; + AstStrengthSpec* strengthSpecp + = new AstStrengthSpec{fileline, VStrength::SUPPLY, VStrength::SUPPLY}; + assignp->strengthSpecp(strengthSpecp); + return assignp; } AstRange* V3ParseGrammar::scrubRange(AstNodeRange* nrangep) { diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index 924a5062b..1d2832ce5 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -150,8 +150,8 @@ void V3ParseImp::lexVerilatorCmtLint(FileLine* fl, const char* textp, bool warnO void V3ParseImp::lexVerilatorCmtBad(FileLine* fl, const char* textp) { string cmtparse = textp; - if (cmtparse.substr(0, strlen("/*verilator")) == "/*verilator") { - cmtparse.replace(0, strlen("/*verilator"), ""); + if (cmtparse.substr(0, std::strlen("/*verilator")) == "/*verilator") { + cmtparse.replace(0, std::strlen("/*verilator"), ""); } while (isspace(cmtparse[0])) cmtparse.replace(0, 1, ""); string cmtname; @@ -178,14 +178,14 @@ void V3ParseImp::lexErrorPreprocDirective(FileLine* fl, const char* textp) { } string V3ParseImp::lexParseTag(const char* textp) { - string tmp = textp + strlen("/*verilator tag "); + string tmp = textp + std::strlen("/*verilator tag "); string::size_type pos; if ((pos = tmp.rfind("*/")) != string::npos) tmp.erase(pos); return tmp; } double V3ParseImp::lexParseTimenum(const char* textp) { - const size_t length = strlen(textp); + const size_t length = std::strlen(textp); char* const strgp = new char[length + 1]; char* dp = strgp; const char* sp = textp; @@ -234,7 +234,7 @@ size_t V3ParseImp::ppInputToLex(char* buf, size_t max_size) { m_ppBuffers.push_front(remainder); // Put back remainder for next time len = (max_size - got); } - memcpy(buf + got, front.c_str(), len); + std::memcpy(buf + got, front.c_str(), len); got += len; } if (debug() >= 9) { @@ -398,8 +398,7 @@ void V3ParseImp::tokenPipeline() { const int nexttok = nexttokp->token; yylval = curValue; // Now potentially munge the current token - if (token == '(' - && (nexttok == ygenSTRENGTH || nexttok == ySUPPLY0 || nexttok == ySUPPLY1)) { + if (token == '(' && isStrengthToken(nexttok)) { token = yP_PAR__STRENGTH; } else if (token == ':') { if (nexttok == yBEGIN) { @@ -483,6 +482,12 @@ void V3ParseImp::tokenPipeline() { // effectively returns yylval } +bool V3ParseImp::isStrengthToken(int tok) { + return tok == ygenSTRENGTH || tok == ySUPPLY0 || tok == ySUPPLY1 || tok == ySTRONG0 + || tok == ySTRONG1 || tok == yPULL0 || tok == yPULL1 || tok == yWEAK0 || tok == yWEAK1 + || tok == yHIGHZ0 || tok == yHIGHZ1; +} + void V3ParseImp::tokenPipelineSym() { // If an id, change the type based on symbol table // Note above sometimes converts yGLOBAL to a yaID__LEX diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index c5cf4bd36..54a241365 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -121,6 +121,7 @@ struct V3ParseBisonYYSType { V3ErrorCode::en errcodeen; VAttrType::en attrtypeen; VLifetime::en lifetime; + VStrength::en strength; #include "V3Ast__gen_yystype.h" }; @@ -216,6 +217,7 @@ public: } int lexKwdLastState() const { return m_lexKwdLast; } static const char* tokenName(int tok); + static bool isStrengthToken(int tok); void ppPushText(const string& text) { m_ppBuffers.push_back(text); diff --git a/src/V3PreLex.l b/src/V3PreLex.l index bfe69e7c7..a83a55db9 100644 --- a/src/V3PreLex.l +++ b/src/V3PreLex.l @@ -126,7 +126,7 @@ bom [\357\273\277] if (LEXP->m_protBytes > 0) { LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "multiple `pragma protected encoding sections"); } - res = sscanf(yytext + strlen("encoding"), " = (enctype = \"%15[A-Za-z0-9]\", line_length = %d, bytes = %d)", &enctype[0], &LEXP->m_protLength, &LEXP->m_protBytes); + res = sscanf(yytext + std::strlen("encoding"), " = (enctype = \"%15[A-Za-z0-9]\", line_length = %d, bytes = %d)", &enctype[0], &LEXP->m_protLength, &LEXP->m_protBytes); if (res == 0) LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "`pragma protected encoding must have an \"enctype\" field"); LEXP->m_encType = !VL_STRCASECMP(enctype, "uuencode") ? Enctype::UUENCODE : @@ -242,7 +242,7 @@ bom [\357\273\277] "`__LINE__" { FL_FWDC; static char buf[25]; VL_SNPRINTF(buf, 25, "%d", LEXP->curFilelinep()->lastLineno()); - yytext = buf; yyleng = strlen(yytext); + yytext = buf; yyleng = std::strlen(yytext); return VP_TEXT; } /* Pass-through strings */ diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index 59ba4398b..0cf66dc24 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -395,7 +395,7 @@ string V3PreProcImp::commentCleanup(const string& text) { } bool V3PreProcImp::commentTokenMatch(string& cmdr, const char* strg) { - int len = strlen(strg); + int len = std::strlen(strg); if (VString::startsWith(cmdr, strg) && (cmdr[len] == '\0' || isspace(cmdr[len]))) { if (isspace(cmdr[len])) len++; cmdr = cmdr.substr(len); @@ -425,27 +425,27 @@ void V3PreProcImp::comment(const string& text) { bool synth = false; bool vlcomment = false; if ((cp[0] == 'v' || cp[0] == 'V') && VString::startsWith(cp + 1, "erilator")) { - cp += strlen("verilator"); + cp += std::strlen("verilator"); if (*cp == '_') { fileline()->v3error("Extra underscore in meta-comment;" " use /*verilator {...}*/ not /*verilator_{...}*/"); } vlcomment = true; } else if (VString::startsWith(cp, "synopsys")) { - cp += strlen("synopsys"); + cp += std::strlen("synopsys"); synth = true; if (*cp == '_') { fileline()->v3error("Extra underscore in meta-comment;" " use /*synopsys {...}*/ not /*synopsys_{...}*/"); } } else if (VString::startsWith(cp, "cadence")) { - cp += strlen("cadence"); + cp += std::strlen("cadence"); synth = true; } else if (VString::startsWith(cp, "pragma")) { - cp += strlen("pragma"); + cp += std::strlen("pragma"); synth = true; } else if (VString::startsWith(cp, "ambit synthesis")) { - cp += strlen("ambit synthesis"); + cp += std::strlen("ambit synthesis"); synth = true; } else { return; @@ -478,7 +478,7 @@ void V3PreProcImp::comment(const string& text) { string::size_type pos; if ((pos = cmd.find("public_flat_rw")) != string::npos) { // "/*verilator public_flat_rw @(foo) */" -> "/*verilator public_flat_rw*/ @(foo)" - cmd = cmd.substr(pos + strlen("public_flat_rw")); + cmd = cmd.substr(pos + std::strlen("public_flat_rw")); while (isspace(cmd[0])) cmd = cmd.substr(1); if (!printed) insertUnreadback("/*verilator public_flat_rw*/ " + cmd + " /**/"); } else { @@ -1593,7 +1593,7 @@ string V3PreProcImp::getline() { if (isEof()) return ""; const char* rtnp; bool gotEof = false; - while (nullptr == (rtnp = strchr(m_lineChars.c_str(), '\n')) && !gotEof) { + while (nullptr == (rtnp = std::strchr(m_lineChars.c_str(), '\n')) && !gotEof) { string buf; const int tok = getFinalToken(buf /*ref*/); if (debug() >= 5) { diff --git a/src/V3String.cpp b/src/V3String.cpp index 9d20bd078..1a42ee2e7 100644 --- a/src/V3String.cpp +++ b/src/V3String.cpp @@ -150,7 +150,7 @@ double VString::parseDouble(const string& str, bool* successp) { char* endp = strgp; const double d = strtod(strgp, &endp); const size_t parsed_len = endp - strgp; - if (parsed_len != strlen(strgp)) { + if (parsed_len != std::strlen(strgp)) { if (successp) *successp = false; } VL_DO_DANGLING(delete[] strgp, strgp); @@ -402,7 +402,7 @@ void VHashSha256::selfTest() { string VName::dehash(const string& in) { static const char VHSH[] = "__Vhsh"; - static const size_t DOT_LEN = strlen("__DOT__"); + static const size_t DOT_LEN = std::strlen("__DOT__"); std::string dehashed; // Need to split 'in' into components separated by __DOT__, 'last_dot_pos' diff --git a/src/V3Subst.cpp b/src/V3Subst.cpp index ef7562ac5..ce43a7fd0 100644 --- a/src/V3Subst.cpp +++ b/src/V3Subst.cpp @@ -359,6 +359,13 @@ private: } virtual void visit(AstVar*) override {} virtual void visit(AstConst*) override {} + virtual void visit(AstModule* nodep) override { + ++m_ops; + if (!nodep->isSubstOptimizable()) m_ops = SUBST_MAX_OPS_NA; + iterateChildren(nodep); + // Reduce peak memory usage by reclaiming the edited AstNodes + doDeletes(); + } virtual void visit(AstNode* nodep) override { m_ops++; if (!nodep->isSubstOptimizable()) m_ops = SUBST_MAX_OPS_NA; diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index b5e983978..733d4ad74 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -55,6 +55,33 @@ // duplicating vars and logic that is common between each instance of a // module. // +// +// Another thing done in this phase is signal strength handling. +// Currently they are only supported in assignments and only in case when the strongest assignment +// has constant with all bits equal on the RHS. It is the case when they can be statically +// resolved. +// +// Static resolution is done in the following way: +// - The assignment of value 0 (size may be greater than 1), that has greatest strength (the +// one corresponding to 0) of all other assignments of 0, has to be found. +// - The same is done for value '1 and strength corresponding to value 1. +// - The greater of these two strengths is chosen. If they are equal the one that corresponds +// to 1 is taken as the greatest. +// - All assignments, that have strengths weaker or equal to the one that was found before, are +// removed. They are the assignments with constants on the RHS and also all assignments that have +// both strengths non-greater that the one was found, because they are weaker no matter what is on +// RHS. +// +// All assignments that are stronger than the one with strongest constant are left as they are. +// +// There is a possible problem with equally strong assignments, because multiple assignments with +// the same strength, but different values should result in x value, but these values are +// unsupported. +// +// Singal strength can also be used in simple logic gates parsed as assignments (see verilog.y), +// but these gates are then either removed (if they are weaker than the strongest constant) or +// handled as the gates witout signal strengths are handled now. In other words, gate with greater +// strength won't properly overwrite weaker driver. //************************************************************************* #include "config_build.h" @@ -340,6 +367,8 @@ class TristateVisitor final : public TristateBaseVisitor { // TYPES using RefVec = std::vector; using VarMap = std::unordered_map; + using Assigns = std::vector; + using VarToAssignsMap = std::map; enum : uint8_t { U2_GRAPHING = 1, // bit[0] if did m_graphing visit U2_NONGRAPH = 2, // bit[1] if did !m_graphing visit @@ -352,6 +381,7 @@ class TristateVisitor final : public TristateBaseVisitor { AstNodeModule* m_modp = nullptr; // Current module AstCell* m_cellp = nullptr; // current cell VarMap m_lhsmap; // Tristate left-hand-side driver map + VarToAssignsMap m_assigns; // Assigns in current module int m_unique = 0; bool m_alhs = false; // On LHS of assignment const AstNode* m_logicp = nullptr; // Current logic being built @@ -636,6 +666,117 @@ class TristateVisitor final : public TristateBaseVisitor { nodep->addStmtp(assp); } + void addToAssignmentList(AstAssignW* nodep) { + if (AstVarRef* const varRefp = VN_CAST(nodep->lhsp(), VarRef)) { + if (varRefp->varp()->isNet()) { + m_assigns[varRefp->varp()].push_back(nodep); + } else if (nodep->strengthSpecp()) { + if (!varRefp->varp()->isNet()) + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Signal strengths are unsupported " + "on the following variable type: " + << varRefp->varp()->varType()); + + nodep->strengthSpecp()->unlinkFrBack()->deleteTree(); + } + } else if (nodep->strengthSpecp()) { + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: Assignments with signal strength with LHS of type: " + << nodep->lhsp()->prettyTypeName()); + } + } + + uint8_t getStrength(AstAssignW* const nodep, bool value) { + if (AstStrengthSpec* const strengthSpec = nodep->strengthSpecp()) { + return value ? strengthSpec->strength1() : strengthSpec->strength0(); + } + return VStrength::STRONG; // default strength is strong + } + + bool assignmentOfValueOnAllBits(AstAssignW* const nodep, bool value) { + if (AstConst* const constp = VN_CAST(nodep->rhsp(), Const)) { + const V3Number num = constp->num(); + return value ? num.isEqAllOnes() : num.isEqZero(); + } + return false; + } + + AstAssignW* getStrongestAssignmentOfValue(const Assigns& assigns, bool value) { + auto maxIt = std::max_element( + assigns.begin(), assigns.end(), [&](AstAssignW* ap, AstAssignW* bp) { + bool valuesOnRhsA = assignmentOfValueOnAllBits(ap, value); + bool valuesOnRhsB = assignmentOfValueOnAllBits(bp, value); + if (!valuesOnRhsA) return valuesOnRhsB; + if (!valuesOnRhsB) return false; + return getStrength(ap, value) < getStrength(bp, value); + }); + // If not all assignments have const with all bits equal to value on the RHS, + // std::max_element will return one of them anyway, so it has to be checked before + // returning + return assignmentOfValueOnAllBits(*maxIt, value) ? *maxIt : nullptr; + } + + void removeWeakerAssignments(Assigns& assigns) { + // Weaker assignments are these assignments that can't change the final value of the net. + // If the value of the RHS is known, only strength corresponding to its value is taken into + // account. Assignments of constants that have bits both 0 and 1 are skipped here, because + // it would involve handling parts of bits separately. + + // First, the strongest assignment, that has value on the RHS consisting of only 1 or only + // 0, has to be found. + AstAssignW* const strongest0p = getStrongestAssignmentOfValue(assigns, 0); + AstAssignW* const strongest1p = getStrongestAssignmentOfValue(assigns, 1); + AstAssignW* strongestp = nullptr; + uint8_t greatestKnownStrength = 0; + const auto getIfStrongest = [&](AstAssignW* const strongestCandidatep, bool value) { + if (!strongestCandidatep) return; + uint8_t strength = getStrength(strongestCandidatep, value); + if (strength >= greatestKnownStrength) { + greatestKnownStrength = strength; + strongestp = strongestCandidatep; + } + }; + getIfStrongest(strongest0p, 0); + getIfStrongest(strongest1p, 1); + + if (strongestp) { + // Then all weaker assignments can be safely removed. + // Assignments of the same strength are also removed, because duplicates aren't needed. + // One problem is with 2 assignments of different values and equal strengths. It should + // result in assignment of x value, but these values aren't supported now. + auto removedIt + = std::remove_if(assigns.begin(), assigns.end(), [&](AstAssignW* assignp) { + if (assignp == strongestp) return false; + const uint8_t strength0 = getStrength(assignp, 0); + const uint8_t strength1 = getStrength(assignp, 1); + const bool toRemove = (strength0 <= greatestKnownStrength + && strength1 <= greatestKnownStrength) + || (strength0 <= greatestKnownStrength + && assignmentOfValueOnAllBits(assignp, 0)) + || (strength1 <= greatestKnownStrength + && assignmentOfValueOnAllBits(assignp, 1)); + if (toRemove) { + // Don't propagate tristate if its assignment is removed. + TristateVertex* const vertexp + = reinterpret_cast(assignp->rhsp()->user5p()); + if (vertexp) vertexp->isTristate(false); + VL_DO_DANGLING(pushDeletep(assignp->unlinkFrBack()), assignp); + return true; + } + return false; + }); + assigns.erase(removedIt, assigns.end()); + } + } + + void resolveMultipleNetAssignments() { + for (auto& varpAssigns : m_assigns) { + if (varpAssigns.second.size() > 1) { + // first the static resolution is tried + removeWeakerAssignments(varpAssigns.second); + } + } + } + // VISITORS virtual void visit(AstConst* nodep) override { UINFO(9, dbgState() << nodep << endl); @@ -889,6 +1030,8 @@ class TristateVisitor final : public TristateBaseVisitor { void visitAssign(AstNodeAssign* nodep) { if (m_graphing) { + if (AstAssignW* assignWp = VN_CAST(nodep, AssignW)) addToAssignmentList(assignWp); + if (nodep->user2() & U2_GRAPHING) return; VL_RESTORER(m_logicp); m_logicp = nodep; @@ -1373,6 +1516,7 @@ class TristateVisitor final : public TristateBaseVisitor { VL_RESTORER(m_graphing); VL_RESTORER(m_unique); VL_RESTORER(m_lhsmap); + VL_RESTORER(m_assigns); // Not preserved, needs pointer instead: TristateGraph origTgraph = m_tgraph; UASSERT_OBJ(m_tgraph.empty(), nodep, "Unsupported: NodeModule under NodeModule"); { @@ -1382,6 +1526,7 @@ class TristateVisitor final : public TristateBaseVisitor { m_unique = 0; m_logicp = nullptr; m_lhsmap.clear(); + m_assigns.clear(); m_modp = nodep; // Walk the graph, finding all variables and tristate constructs { @@ -1389,6 +1534,8 @@ class TristateVisitor final : public TristateBaseVisitor { iterateChildren(nodep); m_graphing = false; } + // resolve multiple net assignments and signal strengths + resolveMultipleNetAssignments(); // Use graph to find tristate signals m_tgraph.graphWalk(nodep); // Build the LHS drivers map for this module diff --git a/src/V3Waiver.cpp b/src/V3Waiver.cpp index 42d222fe8..41a07c1ff 100644 --- a/src/V3Waiver.cpp +++ b/src/V3Waiver.cpp @@ -6,9 +6,10 @@ // //************************************************************************* // -// 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. +// Copyright 2020-2022 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 // //************************************************************************* diff --git a/src/V3Width.cpp b/src/V3Width.cpp index a2b6ace1e..1e625d4f7 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -538,7 +538,7 @@ private: || VN_IS(vdtypep, DynArrayDType) // || VN_IS(vdtypep, QueueDType)) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: Concatenation to form " - << vdtypep->prettyDTypeNameQ() << "data type"); + << vdtypep->prettyDTypeNameQ() << " data type"); } iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); @@ -3256,6 +3256,7 @@ private: nodep->dtypeFrom(ftaskp); nodep->classOrPackagep(classp); if (VN_IS(ftaskp, Task)) nodep->makeStatement(); + processFTaskRefArgs(nodep); } return; } @@ -5910,7 +5911,8 @@ private: "Node has no type"); // Perhaps forgot to do a prelim visit on it? // // For DOUBLE under a logical op, add implied test against zero, never a warning - if (underp && underp->isDouble()) { + AstNodeDType* const underVDTypep = underp ? underp->dtypep()->skipRefp() : nullptr; + if (underp && underVDTypep->isDouble()) { UINFO(6, " spliceCvtCmpD0: " << underp << endl); VNRelinker linker; underp->unlinkFrBack(&linker); @@ -5918,13 +5920,12 @@ private: = new AstNeqD(nodep->fileline(), underp, new AstConst(nodep->fileline(), AstConst::RealDouble(), 0.0)); linker.relink(newp); - } else if (VN_IS(underp->dtypep(), ClassRefDType) - || (VN_IS(underp->dtypep(), BasicDType) - && VN_AS(underp->dtypep(), BasicDType)->keyword() - == VBasicDTypeKwd::CHANDLE)) { + } else if (VN_IS(underVDTypep, ClassRefDType) + || (VN_IS(underVDTypep, BasicDType) + && VN_AS(underVDTypep, BasicDType)->keyword() == VBasicDTypeKwd::CHANDLE)) { // Allow warning-free "if (handle)" VL_DO_DANGLING(fixWidthReduce(underp), underp); // Changed - } else if (!underp->dtypep()->basicp()) { + } else if (!underVDTypep->basicp()) { nodep->v3error("Logical operator " << nodep->prettyTypeName() << " expects a non-complex data type on the " << side << "."); @@ -6065,7 +6066,7 @@ private: } if ((VN_IS(nodep, Add) && underp->width() == 1 && underp->isOne()) || (VN_IS(nodep, Sub) && underp->width() == 1 && underp->isOne() - && 0 == strcmp(side, "RHS"))) { + && 0 == std::strcmp(side, "RHS"))) { // "foo + 1'b1", or "foo - 1'b1" are very common, people assume // they extend correctly warnOn = false; diff --git a/src/astgen b/src/astgen index 44529a0e4..f8860dce0 100755 --- a/src/astgen +++ b/src/astgen @@ -8,9 +8,125 @@ import re import sys # from pprint import pprint, pformat -Types = [] -Classes = {} -Children = {} + +class Node: + def __init__(self, name, superClass): + self._name = name + self._superClass = superClass + self._subClasses = [] # Initially list, but tuple after completion + self._allSuperClasses = None # Computed on demand after completion + self._allSubClasses = None # Computed on demand after completion + self._typeId = None # Concrete type identifier number for leaf classes + self._typeIdMin = None # Lowest type identifier number for class + self._typeIdMax = None # Highest type identifier number for class + + @property + def name(self): + return self._name + + @property + def superClass(self): + return self._superClass + + @property + def isCompleted(self): + return isinstance(self._subClasses, tuple) + + # Pre completion methods + def addSubClass(self, subClass): + assert not self.isCompleted + self._subClasses.append(subClass) + + # Computes derived properties over entire class hierarchy. + # No more changes to the hierarchy are allowed once this was called + def complete(self, typeId=0): + assert not self.isCompleted + # Sort sub-classes and convert to tuple, which marks completion + self._subClasses = tuple(sorted(self._subClasses, + key=lambda _: _.name)) + # Leaves + if self.isLeaf: + self._typeId = typeId + return typeId + 1 + + # Non-leaves + for subClass in self._subClasses: + typeId = subClass.complete(typeId) + return typeId + + # Post completion methods + @property + def subClasses(self): + assert self.isCompleted + return self._subClasses + + @property + def isRoot(self): + assert self.isCompleted + return self.superClass is None + + @property + def isLeaf(self): + assert self.isCompleted + return not self.subClasses + + @property + def allSuperClasses(self): + assert self.isCompleted + if self._allSuperClasses is None: + if self.superClass is None: + self._allSuperClasses = () + else: + self._allSuperClasses = self.superClass.allSuperClasses + ( + self.superClass, ) + return self._allSuperClasses + + @property + def allSubClasses(self): + assert self.isCompleted + if self._allSubClasses is None: + if self.isLeaf: + self._allSubClasses = () + else: + self._allSubClasses = self.subClasses + tuple( + _ for subClass in self.subClasses + for _ in subClass.allSubClasses) + return self._allSubClasses + + @property + def typeId(self): + assert self.isCompleted + assert self.isLeaf + return self._typeId + + @property + def typeIdMin(self): + assert self.isCompleted + if self.isLeaf: + return self.typeId + if self._typeIdMin is None: + self._typeIdMin = min(_.typeIdMin for _ in self.allSubClasses) + return self._typeIdMin + + @property + def typeIdMax(self): + assert self.isCompleted + if self.isLeaf: + return self.typeId + if self._typeIdMax is None: + self._typeIdMax = max(_.typeIdMax for _ in self.allSubClasses) + return self._typeIdMax + + def isSubClassOf(self, other): + assert self.isCompleted + if self is other: + return True + return self in other.allSubClasses + + +Nodes = {} +SortedNodes = None + ClassRefs = {} Stages = {} @@ -111,7 +227,7 @@ class Cpt: self.error("Can't parse from function: " + func) typen = match.group(1) subnodes = match.group(2) - if not subclasses_of(typen): + if Nodes[typen].isRoot: self.error("Unknown AstNode typen: " + typen + ": in " + func) mif = "" @@ -166,7 +282,7 @@ class Cpt: elif match_skip: typen = match_skip.group(1) self.tree_skip_visit[typen] = 1 - if typen not in Classes: + if typen not in Nodes: self.error("Unknown node type: " + typen) else: @@ -296,12 +412,13 @@ class Cpt: self.print( " // Bottom class up, as more simple transforms are generally better\n" ) - for typen in sorted(Classes.keys()): + for node in SortedNodes: out_for_type_sc = [] out_for_type = [] - bases = subclasses_of(typen) - bases.append(typen) - for base in bases: + classes = list(node.allSuperClasses) + classes.append(node) + for base in classes: + base = base.name if base not in self.treeop: continue for typefunc in self.treeop[base]: @@ -328,23 +445,23 @@ class Cpt: if len(out_for_type_sc) > 0: # Short-circuited types self.print( " // Generated by astgen with short-circuiting\n" + - " virtual void visit(Ast" + typen + + " virtual void visit(Ast" + node.name + "* nodep) override {\n" + " iterateAndNextNull(nodep->lhsp());\n" + "".join(out_for_type_sc)) if out_for_type[0]: self.print(" iterateAndNextNull(nodep->rhsp());\n") - if is_subclass_of(typen, "NodeTriop"): + if node.isSubClassOf(Nodes["NodeTriop"]): self.print( " iterateAndNextNull(nodep->thsp());\n") self.print("".join(out_for_type) + " }\n") elif len(out_for_type) > 0: # Other types with something to print - skip = typen in self.tree_skip_visit + skip = node.name in self.tree_skip_visit gen = "Gen" if skip else "" override = "" if skip else " override" self.print( " // Generated by astgen\n" + " virtual void visit" + - gen + "(Ast" + typen + "* nodep)" + override + " {\n" + + gen + "(Ast" + node.name + "* nodep)" + override + " {\n" + ("" if skip else " iterateChildren(nodep);\n") + ''.join(out_for_type) + " }\n") @@ -368,11 +485,13 @@ def read_types(filename): if re.search(r'Ast', supern) or classn == "AstNode": classn = re.sub(r'^Ast', '', classn) supern = re.sub(r'^Ast', '', supern) - Classes[classn] = supern - if supern != '': - if supern not in Children: - Children[supern] = {} - Children[supern][classn] = 1 + if supern: + superClass = Nodes[supern] + node = Node(classn, superClass) + Nodes[supern].addSubClass(node) + else: + node = Node(classn, None) + Nodes[classn] = node def read_stages(filename): @@ -424,37 +543,6 @@ def open_file(filename): return fh -def subclasses_of(typen): - cllist = [] - subclass = Classes[typen] - while True: - if subclass not in Classes: - break - cllist.append(subclass) - subclass = Classes[subclass] - - cllist.reverse() - return cllist - - -def children_of(typen): - cllist = [] - todo = [] - todo.append(typen) - while len(todo) != 0: - subclass = todo.pop(0) - if subclass in Children: - for child in sorted(Children[subclass].keys()): - todo.append(child) - cllist.append(child) - - return cllist - - -def is_subclass_of(typen, what): - return typen == what or (typen in children_of(what)) - - # --------------------------------------------------------------------- @@ -468,20 +556,19 @@ def write_report(filename): fh.write(" " + classn + "\n") fh.write("\nClasses:\n") - for typen in sorted(Classes.keys()): - fh.write(" class Ast%-17s\n" % typen) + for node in SortedNodes: + fh.write(" class Ast%-17s\n" % node.name) fh.write(" parent: ") - for subclass in subclasses_of(typen): - if subclass != 'Node': - fh.write("Ast%-12s " % subclass) + for superClass in node.allSuperClasses: + if not superClass.isRoot: + fh.write("Ast%-12s " % superClass.name) fh.write("\n") fh.write(" childs: ") - for subclass in children_of(typen): - if subclass != 'Node': - fh.write("Ast%-12s " % subclass) + for subClass in node.allSubClasses: + fh.write("Ast%-12s " % subClass.name) fh.write("\n") - if ("Ast" + typen) in ClassRefs: # pylint: disable=superfluous-parens - refs = ClassRefs["Ast" + typen] + if ("Ast" + node.name) in ClassRefs: # pylint: disable=superfluous-parens + refs = ClassRefs["Ast" + node.name] fh.write(" newed: ") for stage in sorted(refs['newed'].keys(), key=lambda val: Stages[val] @@ -500,27 +587,27 @@ def write_report(filename): def write_classes(filename): with open_file(filename) as fh: fh.write("class AstNode;\n") - for typen in sorted(Classes.keys()): - fh.write("class Ast%-17s // " % (typen + ";")) - for subclass in subclasses_of(typen): - fh.write("Ast%-12s " % subclass) + for node in SortedNodes: + fh.write("class Ast%-17s // " % (node.name + ";")) + for superClass in node.allSuperClasses: + fh.write("Ast%-12s " % superClass.name) fh.write("\n") def write_visitor_decls(filename): with open_file(filename) as fh: - for typen in sorted(Classes.keys()): - if typen != "Node": - fh.write("virtual void visit(Ast" + typen + "*);\n") + for node in SortedNodes: + if not node.isRoot: + fh.write("virtual void visit(Ast" + node.name + "*);\n") def write_visitor_defns(filename): with open_file(filename) as fh: - for typen in sorted(Classes.keys()): - if typen != "Node": - base = Classes[typen] - fh.write("void VNVisitor::visit(Ast" + typen + - "* nodep) { visit(static_cast(nodep)); }\n") @@ -528,75 +615,51 @@ def write_impl(filename): with open_file(filename) as fh: fh.write("\n") fh.write("// For internal use. They assume argument is not nullptr.\n") - for typen in sorted(Classes.keys()): + for node in SortedNodes: fh.write("template<> inline bool AstNode::privateTypeTest(const AstNode* nodep) { ") - if typen == "Node": + node.name + ">(const AstNode* nodep) { ") + if node.isRoot: fh.write("return true; ") else: fh.write("return ") - if re.search(r'^Node', typen): + if not node.isLeaf: fh.write( "static_cast(nodep->type()) >= static_cast(VNType::first" - + typen + ") && ") + + node.name + ") && ") fh.write( "static_cast(nodep->type()) <= static_cast(VNType::last" - + typen + "); ") + + node.name + "); ") else: - fh.write("nodep->type() == VNType::at" + typen + "; ") + fh.write("nodep->type() == VNType::at" + node.name + "; ") fh.write("}\n") -def write_type_enum(fh, typen, idx, processed, kind, indent): - # Skip this if it has already been processed - if typen in processed: - return idx - # Mark processed - processed[typen] = 1 - - # The last used index - last = None - - if not re.match(r'^Node', typen): - last = idx - if kind == "concrete-enum": - fh.write(" " * (indent * 4) + "at" + typen + " = " + str(idx) + - ",\n") - elif kind == "concrete-ascii": - fh.write(" " * (indent * 4) + "\"" + typen.upper() + "\",\n") - idx += 1 - elif kind == "abstract-enum": - fh.write(" " * (indent * 4) + "first" + typen + " = " + str(idx) + - ",\n") - - if typen in Children: - for child in sorted(Children[typen].keys()): - (idx, last) = write_type_enum(fh, child, idx, processed, kind, - indent) - - if re.match(r'^Node', typen) and kind == "abstract-enum": - fh.write(" " * (indent * 4) + "last" + typen + " = " + str(last) + - ",\n") - - return [idx, last] - - def write_types(filename): with open_file(filename) as fh: fh.write(" enum en : uint16_t {\n") - (final, ignored) = write_type_enum( # pylint: disable=W0612 - fh, "Node", 0, {}, "concrete-enum", 2) - fh.write(" _ENUM_END = " + str(final) + "\n") + for node in sorted(filter(lambda _: _.isLeaf, SortedNodes), + key=lambda _: _.typeId): + fh.write(" at" + node.name + " = " + str(node.typeId) + + ",\n") + fh.write(" _ENUM_END = " + str(Nodes["Node"].typeIdMax + 1) + + "\n") fh.write(" };\n") fh.write(" enum bounds : uint16_t {\n") - write_type_enum(fh, "Node", 0, {}, "abstract-enum", 2) + for node in sorted(filter(lambda _: not _.isLeaf, SortedNodes), + key=lambda _: _.typeIdMin): + fh.write(" first" + node.name + " = " + + str(node.typeIdMin) + ",\n") + fh.write(" last" + node.name + " = " + str(node.typeIdMax) + + ",\n") fh.write(" _BOUNDS_END\n") fh.write(" };\n") fh.write(" const char* ascii() const {\n") fh.write(" static const char* const names[_ENUM_END + 1] = {\n") - write_type_enum(fh, "Node", 0, {}, "concrete-ascii", 3) + for node in sorted(filter(lambda _: _.isLeaf, SortedNodes), + key=lambda _: _.typeId): + fh.write(" \"" + node.name.upper() + "\",\n") fh.write(" \"_ENUM_END\"\n") fh.write(" };\n") fh.write(" return names[m_e];\n") @@ -605,45 +668,21 @@ def write_types(filename): def write_yystype(filename): with open_file(filename) as fh: - for typen in sorted(Classes.keys()): - fh.write("Ast{t}* {m}p;\n".format(t=typen, - m=typen[0].lower() + typen[1:])) + for node in SortedNodes: + fh.write("Ast{t}* {m}p;\n".format(t=node.name, + m=node.name[0].lower() + + node.name[1:])) def write_macros(filename): with open_file(filename) as fh: - typen = "None" - base = "None" - - in_filename = "V3AstNodes.h" - ifile = Args.I + "/" + in_filename - with open(ifile) as ifh: - for (lineno, line) in enumerate(ifh, 1): - # Drop expanded macro definitions - but keep empty line so compiler - # message locations are accurate - line = re.sub(r'^\s*#(define|undef)\s+ASTGEN_.*$', '', line) - - # Track current node type and base class - match = re.search( - r'\s*class\s*Ast(\S+)\s*(final|VL_NOT_FINAL)?\s*:\s*(public)?\s*(AstNode\S*)', - line) - if match: - typen = match.group(1) - base = match.group(4) - if not typen.startswith("Node"): - macro = "#define ASTGEN_SUPER_{t}(...) {b}(VNType::at{t}, __VA_ARGS__)\n" \ - .format(b=base, t=typen) - fh.write(macro) - - match = re.search(r"ASTGEN_SUPER_(\w+)", line) - if match: - if typen != match.group(1): - print(( - "V3AstNodes.h:{l} ERROR: class Ast{t} calls wrong superclass " - + - "constructor macro (should call ASTGEN_SUPER_{t})" - ).format(l=lineno, t=typen)) - sys.exit(1) + for node in SortedNodes: + # Only care about leaf classes + if not node.isLeaf: + continue + fh.write( + "#define ASTGEN_SUPER_{t}(...) Ast{b}(VNType::at{t}, __VA_ARGS__)\n" + .format(t=node.name, b=node.superClass.name)) ###################################################################### @@ -673,19 +712,24 @@ Args = parser.parse_args() read_types(Args.I + "/V3Ast.h") read_types(Args.I + "/V3AstNodes.h") -for typen in sorted(Classes.keys()): + +# Compute derived properties over the whole AstNode hierarchy +Nodes["Node"].complete() + +SortedNodes = tuple(map(lambda _: Nodes[_], sorted(Nodes.keys()))) + +for node in SortedNodes: # Check all leaves are not AstNode* and non-leaves are AstNode* - children = children_of(typen) - if re.match(r'^Node', typen): - if len(children) == 0: + if re.match(r'^Node', node.name): + if node.isLeaf: sys.exit( "%Error: Final AstNode subclasses must not be named AstNode*: Ast" - + typen) + + node.name) else: - if len(children) != 0: + if not node.isLeaf: sys.exit( "%Error: Non-final AstNode subclasses must be named AstNode*: Ast" - + typen) + + node.name) read_stages(Args.I + "/Verilator.cpp") diff --git a/src/verilog.l b/src/verilog.l index 798b44ef3..2f32764ac 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -327,8 +327,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "forever" { FL; return yFOREVER; } "fork" { FL; return yFORK; } "function" { FL; return yFUNCTION; } - "highz0" { FL; return ygenSTRENGTH; } - "highz1" { FL; return ygenSTRENGTH; } + "highz0" { FL; return yHIGHZ0; } + "highz1" { FL; return yHIGHZ1; } "if" { FL; return yIF; } "initial" { FL; return yINITIAL; } "inout" { FL; return yINOUT; } @@ -352,8 +352,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "pmos" { FL; return yPMOS; } "posedge" { FL; return yPOSEDGE; } "primitive" { FL; return yPRIMITIVE; } - "pull0" { FL; return ygenSTRENGTH; } - "pull1" { FL; return ygenSTRENGTH; } + "pull0" { FL; return yPULL0; } + "pull1" { FL; return yPULL1; } "pulldown" { FL; return yPULLDOWN; } "pullup" { FL; return yPULLUP; } "rcmos" { FL; return yRCMOS; } @@ -371,8 +371,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "small" { FL; return ygenSTRENGTH; } "specify" { FL; return ySPECIFY; } "specparam" { FL; return ySPECPARAM; } - "strong0" { FL; return ygenSTRENGTH; } - "strong1" { FL; return ygenSTRENGTH; } + "strong0" { FL; return ySTRONG0; } + "strong1" { FL; return ySTRONG1; } "supply0" { FL; return ySUPPLY0; } "supply1" { FL; return ySUPPLY1; } "table" { FL; yy_push_state(TABLE); return yTABLE; } @@ -390,8 +390,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "vectored" { FL; return yVECTORED; } "wait" { FL; return yWAIT; } "wand" { FL; return yWAND; } - "weak0" { FL; return ygenSTRENGTH; } - "weak1" { FL; return ygenSTRENGTH; } + "weak0" { FL; return yWEAK0; } + "weak1" { FL; return yWEAK1; } "while" { FL; return yWHILE; } "wire" { FL; return yWIRE; } "wor" { FL; return yWOR; } @@ -1008,7 +1008,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} return yaT_RESETALL; } // Rest handled by preproc "`suppress_faults" { FL_FWD; FL_BRK; } // Verilog-XL compatibility "`timescale"{ws}+[^\n\r]* { FL; PARSEP->lexTimescaleParse(yylval.fl, - yytext + strlen("`timescale")); + yytext + std::strlen("`timescale")); FL_BRK; } "`unconnected_drive"{ws}+"pull0" { FL; return yaT_UNCONNECTED_PULL0; } "`unconnected_drive"{ws}+"pull1" { FL; return yaT_UNCONNECTED_PULL1; } diff --git a/src/verilog.y b/src/verilog.y index 3d9cbb88e..60f90255d 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -58,6 +58,13 @@ assignp->timingControlp(nodep == assignsp ? delayp : delayp->cloneTree(false)); \ } \ } +#define STRENGTHUNSUP(nodep) \ + { \ + if (nodep) { \ + BBUNSUP((nodep->fileline()), "Unsupported: Strength specifier on this gate type"); \ + nodep->deleteTree(); \ + } \ + } //====================================================================== // Statics (for here only) @@ -79,6 +86,7 @@ public: AstNodeDType* m_varDTypep = nullptr; // Pointer to data type for next signal declaration AstNodeDType* m_memDTypep = nullptr; // Pointer to data type for next member declaration AstNode* m_netDelayp = nullptr; // Pointer to delay for next signal declaration + AstStrengthSpec* m_netStrengthp = nullptr; // Pointer to strength for next net declaration AstNodeModule* m_modp = nullptr; // Last module for timeunits bool m_pinAnsi = false; // In ANSI port list FileLine* m_instModuleFl = nullptr; // Fileline of module referenced for instantiations @@ -183,6 +191,7 @@ public: m_varDTypep = dtypep; } void setNetDelay(AstNode* netDelayp) { m_netDelayp = netDelayp; } + void setNetStrength(AstStrengthSpec* netStrengthp) { m_netStrengthp = netStrengthp; } void pinPush() { m_pinStack.push(m_pinNum); m_pinNum = 1; @@ -302,6 +311,16 @@ int V3ParseGrammar::s_modTypeImpNum = 0; if (nodep) nodep->deleteTree(); \ } +#define APPLY_STRENGTH_TO_LIST(beginp, strengthSpecNodep, typeToCast) \ + { \ + if (AstStrengthSpec* specp = VN_CAST(strengthSpecNodep, StrengthSpec)) { \ + for (auto* nodep = beginp; nodep; nodep = nodep->nextp()) { \ + auto* const assignp = VN_AS(nodep, typeToCast); \ + assignp->strengthSpecp(nodep == beginp ? specp : specp->cloneTree(false)); \ + } \ + } \ + } + static void ERRSVKWD(FileLine* fileline, const string& tokname) { static int toldonce = 0; fileline->v3error( @@ -557,6 +576,8 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yGLOBAL__CLOCKING "global-then-clocking" %token yGLOBAL__ETC "global" %token yGLOBAL__LEX "global-in-lex" +%token yHIGHZ0 "highz0" +%token yHIGHZ1 "highz1" %token yIF "if" %token yIFF "iff" //UNSUP %token yIGNORE_BINS "ignore_bins" @@ -611,6 +632,8 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yPROGRAM "program" %token yPROPERTY "property" %token yPROTECTED "protected" +%token yPULL0 "pull0" +%token yPULL1 "pull1" %token yPULLDOWN "pulldown" %token yPULLUP "pullup" %token yPURE "pure" @@ -648,6 +671,8 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token ySTATIC__LEX "static-in-lex" %token ySTRING "string" //UNSUP %token ySTRONG "strong" +%token ySTRONG0 "strong0" +%token ySTRONG1 "strong1" %token ySTRUCT "struct" %token ySUPER "super" %token ySUPPLY0 "supply0" @@ -701,6 +726,8 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) //UNSUP %token yWAIT_ORDER "wait_order" %token yWAND "wand" //UNSUP %token yWEAK "weak" +%token yWEAK0 "weak0" +%token yWEAK1 "weak1" %token yWHILE "while" //UNSUP %token yWILDCARD "wildcard" %token yWIRE "wire" @@ -1731,11 +1758,18 @@ parameter_port_declarationTypeFrontE: // IEEE: parameter_port_declaration w/o as ; net_declaration: // IEEE: net_declaration - excluding implict - net_declarationFront netSigList ';' { $$ = $2; } + net_declarationFront netSigList ';' + { $$ = $2; + if (GRAMMARP->m_netStrengthp) { + VL_DO_CLEAR(delete GRAMMARP->m_netStrengthp, GRAMMARP->m_netStrengthp = nullptr); + }} ; net_declarationFront: // IEEE: beginning of net_declaration - net_declRESET net_type strengthSpecE net_scalaredE net_dataTypeE { VARDTYPE_NDECL($5); } + net_declRESET net_type driveStrengthE net_scalaredE net_dataTypeE + { VARDTYPE_NDECL($5); + GRAMMARP->setNetStrength(VN_CAST($3, StrengthSpec)); + } //UNSUP net_declRESET yINTERCONNECT signingE rangeListE { VARNET($2); VARDTYPE(x); } ; @@ -2441,10 +2475,11 @@ module_common_item: // ==IEEE: module_common_item ; continuous_assign: // IEEE: continuous_assign - yASSIGN strengthSpecE delay_controlE assignList ';' + yASSIGN driveStrengthE delay_controlE assignList ';' { $$ = $4; - PUT_DLYS_IN_ASSIGNS($3, $$); + APPLY_STRENGTH_TO_LIST($4, $2, AssignW); + PUT_DLYS_IN_ASSIGNS($3, $4); } ; @@ -2733,6 +2768,7 @@ netSig: // IEEE: net_decl_assignment - one element from | netId sigAttrListE '=' expr { $$ = VARDONEA($1, *$1, nullptr, $2); auto* const assignp = new AstAssignW{$3, new AstVarRef{$1, *$1, VAccess::WRITE}, $4}; + if (GRAMMARP->m_netStrengthp) assignp->strengthSpecp(GRAMMARP->m_netStrengthp->cloneTree(false)); if ($$->delayp()) assignp->timingControlp($$->delayp()->unlinkFrBack()); // IEEE 1800-2017 10.3.3 $$->addNext(assignp); } | netId variable_dimensionList sigAttrListE @@ -4715,22 +4751,22 @@ stream_expressionOrDataType: // IEEE: from streaming_concatenation // Gate declarations gateDecl: - yBUF delay_controlE gateBufList ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } - | yBUFIF0 delay_controlE gateBufif0List ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } - | yBUFIF1 delay_controlE gateBufif1List ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } - | yNOT delay_controlE gateNotList ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } - | yNOTIF0 delay_controlE gateNotif0List ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } - | yNOTIF1 delay_controlE gateNotif1List ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } - | yAND delay_controlE gateAndList ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } - | yNAND delay_controlE gateNandList ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } - | yOR delay_controlE gateOrList ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } - | yNOR delay_controlE gateNorList ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } - | yXOR delay_controlE gateXorList ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } - | yXNOR delay_controlE gateXnorList ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } - | yPULLUP delay_controlE gatePullupList ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } + yBUF driveStrengthE delay_controlE gateBufList ';' { $$ = $4; STRENGTHUNSUP($2); PUT_DLYS_IN_ASSIGNS($3, $4); } + | yBUFIF0 driveStrengthE delay_controlE gateBufif0List ';' { $$ = $4; STRENGTHUNSUP($2); PUT_DLYS_IN_ASSIGNS($3, $4); } + | yBUFIF1 driveStrengthE delay_controlE gateBufif1List ';' { $$ = $4; STRENGTHUNSUP($2); PUT_DLYS_IN_ASSIGNS($3, $4); } + | yNOT driveStrengthE delay_controlE gateNotList ';' { $$ = $4; APPLY_STRENGTH_TO_LIST($4, $2, AssignW); PUT_DLYS_IN_ASSIGNS($3, $4); } + | yNOTIF0 driveStrengthE delay_controlE gateNotif0List ';' { $$ = $4; STRENGTHUNSUP($2); PUT_DLYS_IN_ASSIGNS($3, $4); } + | yNOTIF1 driveStrengthE delay_controlE gateNotif1List ';' { $$ = $4; STRENGTHUNSUP($2); PUT_DLYS_IN_ASSIGNS($3, $4); } + | yAND driveStrengthE delay_controlE gateAndList ';' { $$ = $4; APPLY_STRENGTH_TO_LIST($4, $2, AssignW); PUT_DLYS_IN_ASSIGNS($3, $4); } + | yNAND driveStrengthE delay_controlE gateNandList ';' { $$ = $4; APPLY_STRENGTH_TO_LIST($4, $2, AssignW); PUT_DLYS_IN_ASSIGNS($3, $4); } + | yOR driveStrengthE delay_controlE gateOrList ';' { $$ = $4; APPLY_STRENGTH_TO_LIST($4, $2, AssignW); PUT_DLYS_IN_ASSIGNS($3, $4); } + | yNOR driveStrengthE delay_controlE gateNorList ';' { $$ = $4; APPLY_STRENGTH_TO_LIST($4, $2, AssignW); PUT_DLYS_IN_ASSIGNS($3, $4); } + | yXOR driveStrengthE delay_controlE gateXorList ';' { $$ = $4; APPLY_STRENGTH_TO_LIST($4, $2, AssignW); PUT_DLYS_IN_ASSIGNS($3, $4); } + | yXNOR driveStrengthE delay_controlE gateXnorList ';' { $$ = $4; APPLY_STRENGTH_TO_LIST($4, $2, AssignW); PUT_DLYS_IN_ASSIGNS($3, $4); } + | yPULLUP delay_controlE gatePullupList ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } | yPULLDOWN delay_controlE gatePulldownList ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } - | yNMOS delay_controlE gateBufif1List ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } // ~=bufif1, as don't have strengths yet - | yPMOS delay_controlE gateBufif0List ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } // ~=bufif0, as don't have strengths yet + | yNMOS delay_controlE gateBufif1List ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } + | yPMOS delay_controlE gateBufif0List ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } // | yTRAN delay_controlE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"tran"); } // Unsupported | yRCMOS delay_controlE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rcmos"); } // Unsupported @@ -4898,21 +4934,33 @@ gatePinExpr: expr { $$ = GRAMMARP->createGatePin($1); } ; -// This list is also hardcoded in VParseLex.l -strength: // IEEE: strength0+strength1 - plus HIGHZ/SMALL/MEDIUM/LARGE - ygenSTRENGTH { BBUNSUP($1, "Unsupported: Verilog 1995 strength specifiers"); } - | ySUPPLY0 { BBUNSUP($1, "Unsupported: Verilog 1995 strength specifiers"); } - | ySUPPLY1 { BBUNSUP($1, "Unsupported: Verilog 1995 strength specifiers"); } +strength0: + ySUPPLY0 { $$ = VStrength::SUPPLY; } + | ySTRONG0 { $$ = VStrength::STRONG; } + | yPULL0 { $$ = VStrength::PULL; } + | yWEAK0 { $$ = VStrength::WEAK; } ; -strengthSpecE: // IEEE: drive_strength + pullup_strength + pulldown_strength + charge_strength - plus empty - /* empty */ { } - | strengthSpec { } +strength1: + ySUPPLY1 { $$ = VStrength::SUPPLY; } + | ySTRONG1 { $$ = VStrength::STRONG; } + | yPULL1 { $$ = VStrength::PULL; } + | yWEAK1 { $$ = VStrength::WEAK; } ; -strengthSpec: // IEEE: drive_strength + pullup_strength + pulldown_strength + charge_strength - plus empty - yP_PAR__STRENGTH strength ')' { } - | yP_PAR__STRENGTH strength ',' strength ')' { } +driveStrengthE: + /* empty */ { $$ = nullptr; } + | driveStrength { $$ = $1; } + ; + + +driveStrength: + yP_PAR__STRENGTH strength0 ',' strength1 ')' { $$ = new AstStrengthSpec{$1, $2, $4}; } + | yP_PAR__STRENGTH strength1 ',' strength0 ')' { $$ = new AstStrengthSpec{$1, $4, $2}; } + | yP_PAR__STRENGTH strength0 ',' yHIGHZ1 ')' { BBUNSUP($4, "Unsupported: highz strength"); } + | yP_PAR__STRENGTH strength1 ',' yHIGHZ0 ')' { BBUNSUP($4, "Unsupported: highz strength"); } + | yP_PAR__STRENGTH yHIGHZ0 ',' strength1 ')' { BBUNSUP($2, "Unsupported: highz strength"); } + | yP_PAR__STRENGTH yHIGHZ1 ',' strength0 ')' { BBUNSUP($2, "Unsupported: highz strength"); } ; //************************************************ diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 5f33c65eb..720d44008 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -1856,7 +1856,7 @@ sub _make_main { if ($self->{savable}) { $fh->print(" const char* save_time_strp = contextp->commandArgsPlusMatch(\"save_time=\");\n"); - $fh->print(" unsigned int save_time = !save_time_strp[0] ? 0 : atoi(save_time_strp+strlen(\"+save_time=\"));\n"); + $fh->print(" unsigned int save_time = !save_time_strp[0] ? 0 : std::atoi(save_time_strp + std::strlen(\"+save_time=\"));\n"); $fh->print(" const char* save_restore_strp = contextp->commandArgsPlusMatch(\"save_restore=\");\n"); $fh->print(" unsigned int save_restore = !save_restore_strp[0] ? 0 : 1;\n"); } diff --git a/test_regress/t/TestCheck.h b/test_regress/t/TestCheck.h index ac42dde3b..2f8cf2283 100644 --- a/test_regress/t/TestCheck.h +++ b/test_regress/t/TestCheck.h @@ -34,7 +34,7 @@ static const bool verbose = false; #define TEST_CHECK_EQ(got, exp) TEST_CHECK(got, exp, ((got) == (exp))); #define TEST_CHECK_NE(got, exp) TEST_CHECK(got, exp, ((got) != (exp))); -#define TEST_CHECK_CSTR(got, exp) TEST_CHECK(got, exp, 0 == strcmp((got), (exp))); +#define TEST_CHECK_CSTR(got, exp) TEST_CHECK(got, exp, 0 == std::strcmp((got), (exp))); #define TEST_CHECK_HEX_EQ(got, exp) \ do { \ diff --git a/test_regress/t/TestSimulator.h b/test_regress/t/TestSimulator.h index 6272887d8..c25304f6e 100644 --- a/test_regress/t/TestSimulator.h +++ b/test_regress/t/TestSimulator.h @@ -28,13 +28,13 @@ private: public: TestSimulator() { vpi_get_vlog_info(&m_info); - if (0 == strcmp(m_info.product, "Verilator")) { + if (0 == std::strcmp(m_info.product, "Verilator")) { m_simulators.verilator = true; - } else if (0 == strcmp(m_info.product, "Verilator")) { + } else if (0 == std::strcmp(m_info.product, "Verilator")) { m_simulators.icarus = true; } else if (0 == strncmp(m_info.product, "Chronologic Simulation VCS", - strlen("Chronologic Simulation VCS"))) { + std::strlen("Chronologic Simulation VCS"))) { m_simulators.vcs = true; } else { printf("%%Warning: %s:%d: Unknown simulator in TestSimulator.h: %s\n", __FILE__, diff --git a/test_regress/t/t_EXAMPLE.v b/test_regress/t/t_EXAMPLE.v index 0e3a9b428..236e0f85d 100644 --- a/test_regress/t/t_EXAMPLE.v +++ b/test_regress/t/t_EXAMPLE.v @@ -13,7 +13,7 @@ // please note it here, otherwise:** // // This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2022 by ____YOUR_NAME_HERE____. +// any use, without warranty, 2022 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 module t(/*AUTOARG*/ diff --git a/test_regress/t/t_class1.v b/test_regress/t/t_class1.v index b584c5be6..c10125c51 100644 --- a/test_regress/t/t_class1.v +++ b/test_regress/t/t_class1.v @@ -12,14 +12,20 @@ class Cls; endclass : Cls module t (/*AUTOARG*/); + typedef Cls Cls2; + initial begin Cls c; + Cls2 c2; if (c != null) $stop; if (c) $stop; + if (c2) $stop; $display("Display: null = \"%p\"", c); // null c = new; + c2 = new; if (c == null) $stop; if (!c) $stop; + if (!c2) $stop; $display("Display: newed = \"%p\"", c); // '{imembera:0, imemberb:0} c.imembera = 10; c.imemberb = 20; diff --git a/test_regress/t/t_class_method_str_literal.pl b/test_regress/t/t_class_method_str_literal.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_class_method_str_literal.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_method_str_literal.v b/test_regress/t/t_class_method_str_literal.v new file mode 100644 index 000000000..3e5e9225d --- /dev/null +++ b/test_regress/t/t_class_method_str_literal.v @@ -0,0 +1,28 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + +class T; + function automatic void print_str(input string a_string); + $display(a_string); + endfunction + + static function automatic void static_print_str(input string a_string); + $display(a_string); + endfunction +endclass + + +initial begin + T t_c = new; + t_c.print_str("function though member"); + t_c.static_print_str("static function through member"); + T::static_print_str("static function through class"); + $write("*-* All Finished *-*\n"); + $finish; +end +endmodule diff --git a/test_regress/t/t_dpi_arg_inout_type.cpp b/test_regress/t/t_dpi_arg_inout_type.cpp index a5c346d8f..f5b109b39 100644 --- a/test_regress/t/t_dpi_arg_inout_type.cpp +++ b/test_regress/t/t_dpi_arg_inout_type.cpp @@ -168,10 +168,10 @@ void i_string(const char** x) { static int n = 0; printf("i_string %d\n", n); if (n++ % 2 == 0) { - if (strcmp(*x, "Hello") != 0) stop(); + if (std::strcmp(*x, "Hello") != 0) stop(); *x = "Good"; } else { - if (strcmp(*x, "World") != 0) stop(); + if (std::strcmp(*x, "World") != 0) stop(); *x = "Bye"; } } @@ -296,10 +296,10 @@ void i_string_t(const char** x) { static int n = 0; printf("i_string_t %d\n", n); if (n++ % 2 == 0) { - if (strcmp(*x, "World") != 0) stop(); + if (std::strcmp(*x, "World") != 0) stop(); *x = "Bye"; } else { - if (strcmp(*x, "Hello") != 0) stop(); + if (std::strcmp(*x, "Hello") != 0) stop(); *x = "Good"; } } @@ -962,10 +962,10 @@ void check_exports() { e_string(&x_string); if ((n % 2) == 0) { if (x_chandle) stop(); - if (strcmp(x_string, "Hello") != 0) stop(); + if (std::strcmp(x_string, "Hello") != 0) stop(); } else { if (x_chandle) stop(); - if (strcmp(x_string, "World") != 0) stop(); + if (std::strcmp(x_string, "World") != 0) stop(); } x_bit = n % 2; @@ -1045,10 +1045,10 @@ void check_exports() { e_string_t(&x_string_t); if ((n % 2) == 0) { if (x_chandle_t != NULL) stop(); - if (strcmp(x_string_t, "World") != 0) stop(); + if (std::strcmp(x_string_t, "World") != 0) stop(); } else { if (x_chandle_t != NULL) stop(); - if (strcmp(x_string_t, "Hello") != 0) stop(); + if (std::strcmp(x_string_t, "Hello") != 0) stop(); } x_bit_t = n % 2; diff --git a/test_regress/t/t_dpi_arg_input_type.cpp b/test_regress/t/t_dpi_arg_input_type.cpp index 1593e1dfc..ee7f56d79 100644 --- a/test_regress/t/t_dpi_arg_input_type.cpp +++ b/test_regress/t/t_dpi_arg_input_type.cpp @@ -155,9 +155,9 @@ void i_string(const char* i) { static int n = 0; printf("i_string %d\n", n); if (n++ % 2 == 0) { - if (strcmp(i, "World") != 0) stop(); + if (std::strcmp(i, "World") != 0) stop(); } else { - if (strcmp(i, "Hello") != 0) stop(); + if (std::strcmp(i, "Hello") != 0) stop(); } } @@ -266,9 +266,9 @@ void i_string_t(const char* i) { static int n = 0; printf("i_string_t %d\n", n); if (n++ % 2 == 0) { - if (strcmp(i, "World") != 0) stop(); + if (std::strcmp(i, "World") != 0) stop(); } else { - if (strcmp(i, "Hello") != 0) stop(); + if (std::strcmp(i, "Hello") != 0) stop(); } } diff --git a/test_regress/t/t_dpi_arg_output_type.cpp b/test_regress/t/t_dpi_arg_output_type.cpp index cf127ee6e..b8eda4a74 100644 --- a/test_regress/t/t_dpi_arg_output_type.cpp +++ b/test_regress/t/t_dpi_arg_output_type.cpp @@ -711,9 +711,9 @@ void check_exports() { e_string(&x_string); if ((n % 2) == 0) { - if (strcmp(x_string, "Hello") != 0) stop(); + if (std::strcmp(x_string, "Hello") != 0) stop(); } else { - if (strcmp(x_string, "World") != 0) stop(); + if (std::strcmp(x_string, "World") != 0) stop(); } e_bit(&x_bit); @@ -772,9 +772,9 @@ void check_exports() { e_string_t(&x_string_t); if ((n % 2) == 0) { - if (strcmp(x_string_t, "Hello") != 0) stop(); + if (std::strcmp(x_string_t, "Hello") != 0) stop(); } else { - if (strcmp(x_string_t, "World") != 0) stop(); + if (std::strcmp(x_string_t, "World") != 0) stop(); } e_bit_t(&x_bit_t); diff --git a/test_regress/t/t_dpi_export_c.cpp b/test_regress/t/t_dpi_export_c.cpp index da9fee221..8b60a1c66 100644 --- a/test_regress/t/t_dpi_export_c.cpp +++ b/test_regress/t/t_dpi_export_c.cpp @@ -115,9 +115,10 @@ int dpix_run_tests() { #ifndef CADENCE // Unimplemented; how hard is it? printf("svDpiVersion: %s\n", svDpiVersion()); - CHECK_RESULT( - bool, - strcmp(svDpiVersion(), "1800-2005") == 0 || strcmp(svDpiVersion(), "P1800-2005") == 0, 1); + CHECK_RESULT(bool, + std::strcmp(svDpiVersion(), "1800-2005") == 0 + || std::strcmp(svDpiVersion(), "P1800-2005") == 0, + 1); #endif CHECK_RESULT(int, dpix_int123(), 0x123); diff --git a/test_regress/t/t_dpi_result_type.cpp b/test_regress/t/t_dpi_result_type.cpp index a0d7b3cb5..bc8314a15 100644 --- a/test_regress/t/t_dpi_result_type.cpp +++ b/test_regress/t/t_dpi_result_type.cpp @@ -303,9 +303,9 @@ void check_exports() { #endif if (e_chandle()) stop(); if ((n % 2) == 0) { - if (strcmp(e_string(), "Hello") != 0) stop(); + if (std::strcmp(e_string(), "Hello") != 0) stop(); } else { - if (strcmp(e_string(), "World") != 0) stop(); + if (std::strcmp(e_string(), "World") != 0) stop(); } if (e_bit() != (n % 2)) stop(); if (e_logic() != !(n % 2)) stop(); @@ -327,9 +327,9 @@ void check_exports() { #endif if (e_chandle_t()) stop(); if ((n % 2) == 0) { - if (strcmp(e_string_t(), "Hello") != 0) stop(); + if (std::strcmp(e_string_t(), "Hello") != 0) stop(); } else { - if (strcmp(e_string_t(), "World") != 0) stop(); + if (std::strcmp(e_string_t(), "World") != 0) stop(); } if (e_bit_t() != (n % 2)) stop(); if (e_logic_t() != !(n % 2)) stop(); diff --git a/test_regress/t/t_dpi_string_c.cpp b/test_regress/t/t_dpi_string_c.cpp index 05b001886..9216d9316 100644 --- a/test_regress/t/t_dpi_string_c.cpp +++ b/test_regress/t/t_dpi_string_c.cpp @@ -39,5 +39,5 @@ extern int dpii_string(const char* s); int dpii_string(const char* s) { printf("dpii_string: %s\n", s); - return strlen(s); + return std::strlen(s); } diff --git a/test_regress/t/t_dpi_var.cpp b/test_regress/t/t_dpi_var.cpp index f35647d41..5f9ee79f1 100644 --- a/test_regress/t/t_dpi_var.cpp +++ b/test_regress/t/t_dpi_var.cpp @@ -60,9 +60,9 @@ void mon_scope_name(const char* namep) { #ifdef TEST_VERBOSE VL_PRINTF("- mon_scope_name('%s', \"%s\");\n", modp, namep); #endif - if (strcmp(namep, "t.sub")) + if (std::strcmp(namep, "t.sub")) vl_fatal(__FILE__, __LINE__, "", (std::string{"Unexp scope name "} + namep).c_str()); - if (strcmp(modp, "t.sub")) + if (std::strcmp(modp, "t.sub")) vl_fatal(__FILE__, __LINE__, "", (std::string{"Unexp dpiscope name "} + modp).c_str()); } diff --git a/test_regress/t/t_flag_main.pl b/test_regress/t/t_flag_main.pl index 381004460..57041562f 100755 --- a/test_regress/t/t_flag_main.pl +++ b/test_regress/t/t_flag_main.pl @@ -11,6 +11,9 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( + verilator_flags => [# Custom as don't want -cc + "-Mdir $Self->{obj_dir}", + "--debug-check", ], verilator_flags2 => ['--exe --build --main'], verilator_make_cmake => 0, verilator_make_gmake => 0, diff --git a/test_regress/t/t_flag_prefix.pl b/test_regress/t/t_flag_prefix.pl new file mode 100755 index 000000000..adcce742d --- /dev/null +++ b/test_regress/t/t_flag_prefix.pl @@ -0,0 +1,49 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Geza Lore. 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( + verilator_flags2 => ["--prefix t_flag_prefix", # should be overridden + "--prefix Vprefix", + "--exe", "--main", "--stats", "--build"], + verilator_make_cmake => 0, + verilator_make_gmake => 0, + make_main => 0, + ); + +execute( + check_finished => 1, + executable => "$Self->{obj_dir}/Vprefix", + ); + +sub check_files { + foreach my $path (glob("$Self->{obj_dir}/*")) { + my $filename = substr $path, ((length $Self->{obj_dir}) + 1); + next if ($filename =~ /^.*\.log$/); + if ($filename =~ /t_flag_prefix/) { + error("bad filename $filename"); + next; + } + next if ($filename =~ /^(.*\.(o|a)|Vprefix)$/); + my $fh = IO::File->new("<$path") or error("$! $filenme"); + while (defined(my $line = $fh->getline)) { + $line =~ s/--prefix V?t_flag_prefix//g; + $line =~ s/obj_vlt\/t_flag_prefix//g; + $line =~ s/t\/t_flag_prefix\.v//g; + error("bad line in $filename: $line") if $line =~ /t_flag_prefix/; + } + } +} + +check_files(); + +ok(1); +1; diff --git a/test_regress/t/t_flag_prefix.v b/test_regress/t/t_flag_prefix.v new file mode 100755 index 000000000..00634520b --- /dev/null +++ b/test_regress/t/t_flag_prefix.v @@ -0,0 +1,35 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Geza Lore. +// SPDX-License-Identifier: CC0-1.0 + +module t; + sub sub(); +endmodule + +module sub; + // no_inline_module, so it goes into separate file + /* verilator no_inline_module */ + + // Goes into const pool which is separate file + wire bit [255:0] C = {32'h1111_1111, + 32'h2222_2222, + 32'h3333_3333, + 32'h4444_4444, + 32'h5555_5555, + 32'h6666_6666, + 32'h7777_7777, + 32'h8888_8888}; + + initial begin + // Note: Base index via $c to prevent optimization + $display("0x%32x", C[$c(0*32)+:32]); + $display("0x%32x", C[$c(2*32)+:32]); + $display("0x%32x", C[$c(4*32)+:32]); + $display("0x%32x", C[$c(6*32)+:32]); + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_mailbox.out b/test_regress/t/t_mailbox.out index 5a7cc1581..4d5432212 100644 --- a/test_regress/t/t_mailbox.out +++ b/test_regress/t/t_mailbox.out @@ -1,4 +1,6 @@ %Error: t/t_mailbox.v:20:4: Can't find typedef: 'mailbox' - 20 | mailbox m; + 20 | mailbox #(int) m; | ^~~~~~~ -%Error: Exiting due to +%Error: Internal Error: t/t_mailbox.v:20:14: ../V3LinkDot.cpp:#: Pin not under instance? + 20 | mailbox #(int) m; + | ^~~ diff --git a/test_regress/t/t_mailbox.v b/test_regress/t/t_mailbox.v index 21eadf323..06ea1f834 100644 --- a/test_regress/t/t_mailbox.v +++ b/test_regress/t/t_mailbox.v @@ -17,7 +17,7 @@ // endclass module t(/*AUTOARG*/); - mailbox m; + mailbox #(int) m; int msg; int out; diff --git a/test_regress/t/t_mailbox_bad.out b/test_regress/t/t_mailbox_bad.out new file mode 100644 index 000000000..4d5432212 --- /dev/null +++ b/test_regress/t/t_mailbox_bad.out @@ -0,0 +1,6 @@ +%Error: t/t_mailbox.v:20:4: Can't find typedef: 'mailbox' + 20 | mailbox #(int) m; + | ^~~~~~~ +%Error: Internal Error: t/t_mailbox.v:20:14: ../V3LinkDot.cpp:#: Pin not under instance? + 20 | mailbox #(int) m; + | ^~~ diff --git a/test_regress/t/t_mailbox_bad.pl b/test_regress/t/t_mailbox_bad.pl new file mode 100755 index 000000000..8de551634 --- /dev/null +++ b/test_regress/t/t_mailbox_bad.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 2022 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_mailbox.v"); + +lint( + verilator_flags2 => ["--xml-only"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_mailbox_bad.v b/test_regress/t/t_mailbox_bad.v new file mode 100644 index 000000000..a8bcb84fc --- /dev/null +++ b/test_regress/t/t_mailbox_bad.v @@ -0,0 +1,17 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + mailbox #(int) m; + + initial begin + m = new(4); + if (m.bad_method() != 0) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_process.v b/test_regress/t/t_process.v index f6ee27bac..0d495ab17 100644 --- a/test_regress/t/t_process.v +++ b/test_regress/t/t_process.v @@ -6,16 +6,16 @@ // Methods defined by IEEE: // class process; -// enum state { FINISHED, RUNNING, WAITING, SUSPENDED, KILLED }; +// enum state { FINISHED, RUNNING, WAITING, SUSPENDED, KILLED }; // UVM uses KILLED, FINISHED // static function process self(); // function state status(); // function void kill(); // task await(); // Warn as unsupported (no UVM library use) // function void suspend(); // Warn as unsupported (no UVM library use) // function void resume(); // Warn as unsupported (no UVM library use) -// function void srandom( int seed ); // Just ignore? -// function string get_randstate(); // Just ignore? -// function void set_randstate( string state ); // Just ignore? +// function void srandom( int seed ); // Operate on all proceses for now? +// function string get_randstate(); // Operate on all proceses for now? +// function void set_randstate( string state ); // Operate on all proceses for now? // endclass module t(/*AUTOARG*/); diff --git a/test_regress/t/t_process_bad.out b/test_regress/t/t_process_bad.out new file mode 100644 index 000000000..a4ada3778 --- /dev/null +++ b/test_regress/t/t_process_bad.out @@ -0,0 +1,10 @@ +%Error: t/t_process.v:22:4: Can't find typedef: 'process' + 22 | process p; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_process.v:26:20: Unsupported: 'process' + 26 | p = process::self(); + | ^~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Internal Error: t/t_process.v:26:11: ../V3LinkDot.cpp:#: Bad package link + 26 | p = process::self(); + | ^~~~~~~ diff --git a/test_regress/t/t_process_bad.pl b/test_regress/t/t_process_bad.pl new file mode 100755 index 000000000..7be24ae56 --- /dev/null +++ b/test_regress/t/t_process_bad.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 2022 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_process.v"); + +lint( + verilator_flags2 => ["--xml-only"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_process_bad.v b/test_regress/t/t_process_bad.v new file mode 100644 index 000000000..d32afb72b --- /dev/null +++ b/test_regress/t/t_process_bad.v @@ -0,0 +1,20 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + process p; + + initial begin + if (p != null) $stop; + p = process::self(); + if (p.bad_method() != 0) $stop; + + p.bad_method_2(); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_sc_names.cpp b/test_regress/t/t_sc_names.cpp index 6839252b0..6f73c4c1d 100644 --- a/test_regress/t/t_sc_names.cpp +++ b/test_regress/t/t_sc_names.cpp @@ -15,7 +15,7 @@ int sc_main(int argc, char* argv[]) { /* We expect to find clk in here. */ for (int i = 0; i < ch.size(); ++i) { - if (!strcmp(ch[i]->basename(), "clk")) found = true; + if (!std::strcmp(ch[i]->basename(), "clk")) found = true; } if (found) { diff --git a/test_regress/t/t_scope_map.cpp b/test_regress/t/t_scope_map.cpp index 9136c8ee3..d9f554d8b 100644 --- a/test_regress/t/t_scope_map.cpp +++ b/test_regress/t/t_scope_map.cpp @@ -100,7 +100,7 @@ int main(int argc, char** argv, char** env) { #endif // Clear out the data - memset(varData, 0, (varBits + 7) / 8); + std::memset(varData, 0, (varBits + 7) / 8); } } diff --git a/test_regress/t/t_semaphore.out b/test_regress/t/t_semaphore.out index 21345fd35..76d60e04d 100644 --- a/test_regress/t/t_semaphore.out +++ b/test_regress/t/t_semaphore.out @@ -1,4 +1,7 @@ %Error: t/t_semaphore.v:17:4: Can't find typedef: 'semaphore' 17 | semaphore s; | ^~~~~~~~~ +%Error: t/t_semaphore.v:18:4: Can't find typedef: 'semaphore' + 18 | semaphore s2; + | ^~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_semaphore.v b/test_regress/t/t_semaphore.v index 322a8541a..bc229ad75 100644 --- a/test_regress/t/t_semaphore.v +++ b/test_regress/t/t_semaphore.v @@ -13,8 +13,9 @@ // endclass module t(/*AUTOARG*/); - //From UVM: + // From UVM: semaphore s; + semaphore s2; int msg; initial begin @@ -30,6 +31,7 @@ module t(/*AUTOARG*/); s.put(2); if (s.try_get(2) <= 0) $stop; +`ifndef VERILATOR fork begin #10; // So later then get() starts below @@ -42,6 +44,10 @@ module t(/*AUTOARG*/); s.get(); end join +`endif + + s2 = new; + if (s2.try_get() != 0) $stop; $write("*-* All Finished *-*\n"); $finish; diff --git a/test_regress/t/t_semaphore_bad.out b/test_regress/t/t_semaphore_bad.out new file mode 100644 index 000000000..76d60e04d --- /dev/null +++ b/test_regress/t/t_semaphore_bad.out @@ -0,0 +1,7 @@ +%Error: t/t_semaphore.v:17:4: Can't find typedef: 'semaphore' + 17 | semaphore s; + | ^~~~~~~~~ +%Error: t/t_semaphore.v:18:4: Can't find typedef: 'semaphore' + 18 | semaphore s2; + | ^~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_semaphore_bad.pl b/test_regress/t/t_semaphore_bad.pl new file mode 100755 index 000000000..92483cce2 --- /dev/null +++ b/test_regress/t/t_semaphore_bad.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 2022 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_semaphore.v"); + +lint( + verilator_flags2 => ["--xml-only"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_semaphore_bad.v b/test_regress/t/t_semaphore_bad.v new file mode 100644 index 000000000..68e6ee38b --- /dev/null +++ b/test_regress/t/t_semaphore_bad.v @@ -0,0 +1,17 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + semaphore s; + + initial begin + s = new(4); + if (s.bad_method() != 0) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_strength_assignments.pl b/test_regress/t/t_strength_assignments.pl new file mode 100755 index 000000000..f5e338520 --- /dev/null +++ b/test_regress/t/t_strength_assignments.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 2022 by Antmicro Ltd. 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_strength_assignments.v b/test_regress/t/t_strength_assignments.v new file mode 100644 index 000000000..8344adbdd --- /dev/null +++ b/test_regress/t/t_strength_assignments.v @@ -0,0 +1,38 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + wire a; + assign (weak0, weak1) a = 1; + assign (weak0, supply1) a = 1; + assign (strong0, strong1) a = 0; + + wire (weak0, weak1) b = 1; + assign (strong0, strong1) b = 0; + + wire [1:0] c; + assign (weak0, supply1) c = '1; + assign (supply0, pull1) c = '1; + assign (strong0, strong1) c = '0; + + supply0 d; + assign (strong0, strong1) d = 1; + + wire (supply0, supply1) e = 'z; + assign (weak0, weak1) e = 1; + + always begin + if (a && !b && c === '1 && !d && e) begin + $write("*-* All Finished *-*\n"); + $finish; + end + else begin + $write("Error: a = %b, b = %b, c = %b, d = %b, e = %b ", a, b, c, d, e); + $write("expected: a = 1, b = 0, c = 11, d = 0, e = 1\n"); + $stop; + end + end +endmodule diff --git a/test_regress/t/t_strength_bufif1.out b/test_regress/t/t_strength_bufif1.out new file mode 100644 index 000000000..0ac300369 --- /dev/null +++ b/test_regress/t/t_strength_bufif1.out @@ -0,0 +1,5 @@ +%Error-UNSUPPORTED: t/t_strength_bufif1.v:9:11: Unsupported: Strength specifier on this gate type + 9 | bufif1 (strong0, strong1) (a, 1'b1, 1'b1); + | ^ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_strength_bufif1.pl b/test_regress/t/t_strength_bufif1.pl new file mode 100755 index 000000000..35c0dfe5b --- /dev/null +++ b/test_regress/t/t_strength_bufif1.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. 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 => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_strength_bufif1.v b/test_regress/t/t_strength_bufif1.v new file mode 100644 index 000000000..0a78b107c --- /dev/null +++ b/test_regress/t/t_strength_bufif1.v @@ -0,0 +1,17 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + wire a; + bufif1 (strong0, strong1) (a, 1'b1, 1'b1); + + always begin + if (a) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_strength_highz.out b/test_regress/t/t_strength_highz.out new file mode 100644 index 000000000..06f32f6e9 --- /dev/null +++ b/test_regress/t/t_strength_highz.out @@ -0,0 +1,14 @@ +%Error-UNSUPPORTED: t/t_strength_highz.v:8:17: Unsupported: highz strength + 8 | wire (weak0, highz1) a = 1; + | ^~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_strength_highz.v:9:19: Unsupported: highz strength + 9 | wire (strong1, highz0) b = 0; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_strength_highz.v:10:10: Unsupported: highz strength + 10 | wire (highz0, pull1) c = 0; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_strength_highz.v:11:10: Unsupported: highz strength + 11 | wire (highz1, supply0) d = 1; + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_strength_highz.pl b/test_regress/t/t_strength_highz.pl new file mode 100755 index 000000000..48bf31461 --- /dev/null +++ b/test_regress/t/t_strength_highz.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +lint( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_strength_highz.v b/test_regress/t/t_strength_highz.v new file mode 100644 index 000000000..340723aba --- /dev/null +++ b/test_regress/t/t_strength_highz.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, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + wire (weak0, highz1) a = 1; + wire (strong1, highz0) b = 0; + wire (highz0, pull1) c = 0; + wire (highz1, supply0) d = 1; + + always begin + if (a === 1'bz && b === 1'bz && c === 1'bz && d === 1'bz) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_strength_strong1_strong1_bad.out b/test_regress/t/t_strength_strong1_strong1_bad.out new file mode 100644 index 000000000..b1e299714 --- /dev/null +++ b/test_regress/t/t_strength_strong1_strong1_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_strength_strong1_strong1_bad.v:8:19: syntax error, unexpected strong1 + 8 | wire (strong1, strong1) a = 1; + | ^~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_strength_strong1_strong1_bad.pl b/test_regress/t/t_strength_strong1_strong1_bad.pl new file mode 100755 index 000000000..19ba90d40 --- /dev/null +++ b/test_regress/t/t_strength_strong1_strong1_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_strength_strong1_strong1_bad.v b/test_regress/t/t_strength_strong1_strong1_bad.v new file mode 100644 index 000000000..ab84216cc --- /dev/null +++ b/test_regress/t/t_strength_strong1_strong1_bad.v @@ -0,0 +1,13 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + wire (strong1, strong1) a = 1; + initial begin + $stop; + end + +endmodule diff --git a/test_regress/t/t_var_sc_bv.cpp b/test_regress/t/t_var_sc_bv.cpp new file mode 100644 index 000000000..d8324bf2f --- /dev/null +++ b/test_regress/t/t_var_sc_bv.cpp @@ -0,0 +1,220 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +#include VM_PREFIX_INCLUDE + +VM_PREFIX* tb = nullptr; +bool pass = true; + +double sc_time_stamp() { return 0; } + +void compare_signals(const sc_signal>& ls, const sc_signal>& rs) { + if (ls.read() != rs.read()) { + pass &= false; + VL_PRINTF("%%Error: Data missmatch in signals %s and %s\n", ls.name(), rs.name()); + } +} + +void compareWls(int obits, WDataInP const lwp, WDataInP const rwp) { + const int words = VL_WORDS_I(obits); + bool same = true; + + for (int i = 0; (i < (words - 1)); ++i) { + if (lwp[i] != rwp[i]) { same = false; } + } + if ((lwp[words - 1] & VL_MASK_E(obits)) != (rwp[words - 1] & VL_MASK_E(obits))) { + same = false; + } + + if (!same) { + pass &= false; + VL_PRINTF("%%Error: There is a difference in VlWide variable %d bits wide\n", obits); + } +} + +// old macro which is correct but has MT issue with range +#define VL_ASSIGN_SBW_MT_ISSUE(obits, svar, rwp) \ + { \ + sc_biguint<(obits)> _butemp; \ + for (int i = 0; i < VL_WORDS_I(obits); ++i) { \ + int msb = ((i + 1) * VL_IDATASIZE) - 1; \ + msb = (msb >= (obits)) ? ((obits)-1) : msb; \ + _butemp.range(msb, i* VL_IDATASIZE) = (rwp)[i]; \ + } \ + (svar).write(_butemp); \ + } + +#ifdef SYSTEMC_VERSION +int sc_main(int, char**) +#else +int main() +#endif +{ + Verilated::debug(0); + tb = new VM_PREFIX("tb"); + + VlWide<8> /*255:0*/ input_var; + VlWide<8> /*255:0*/ out_var; + + // msb is always set to F not to be false positive on checking equality + input_var.m_storage[0] = 0xF2341234; + input_var.m_storage[1] = 0xFEADBEEF; + input_var.m_storage[2] = 0xF5A5A5A5; + input_var.m_storage[3] = 0xF1B2C3D4; + input_var.m_storage[4] = 0xFFFFFFFF; + input_var.m_storage[5] = 0xFAAABBBB; + input_var.m_storage[6] = 0xF000AAAA; + input_var.m_storage[7] = 0xF0101010; + +#ifdef SYSTEMC_VERSION + // clang-format off + sc_signal> SC_NAMED(i_29_s), SC_NAMED(i_29_old_s), SC_NAMED(o_29_s), SC_NAMED(o_29_old_s), + SC_NAMED(i_30_s), SC_NAMED(i_30_old_s), SC_NAMED(o_30_s), SC_NAMED(o_30_old_s), + SC_NAMED(i_31_s), SC_NAMED(i_31_old_s), SC_NAMED(o_31_s), SC_NAMED(o_31_old_s), + SC_NAMED(i_32_s), SC_NAMED(i_32_old_s), SC_NAMED(o_32_s), SC_NAMED(o_32_old_s), + SC_NAMED(i_59_s), SC_NAMED(i_59_old_s), SC_NAMED(o_59_s), SC_NAMED(o_59_old_s), + SC_NAMED(i_60_s), SC_NAMED(i_60_old_s), SC_NAMED(o_60_s), SC_NAMED(o_60_old_s), + SC_NAMED(i_62_s), SC_NAMED(i_62_old_s), SC_NAMED(o_62_s), SC_NAMED(o_62_old_s), + SC_NAMED(i_64_s), SC_NAMED(i_64_old_s), SC_NAMED(o_64_s), SC_NAMED(o_64_old_s), + SC_NAMED(i_119_s), SC_NAMED(i_119_old_s), SC_NAMED(o_119_s), SC_NAMED(o_119_old_s), + SC_NAMED(i_120_s), SC_NAMED(i_120_old_s), SC_NAMED(o_120_s), SC_NAMED(o_120_old_s), + SC_NAMED(i_121_s), SC_NAMED(i_121_old_s), SC_NAMED(o_121_s), SC_NAMED(o_121_old_s), + SC_NAMED(i_127_s), SC_NAMED(i_127_old_s), SC_NAMED(o_127_s), SC_NAMED(o_127_old_s), + SC_NAMED(i_128_s), SC_NAMED(i_128_old_s), SC_NAMED(o_128_s), SC_NAMED(o_128_old_s), + SC_NAMED(i_255_s), SC_NAMED(i_255_old_s), SC_NAMED(o_255_s), SC_NAMED(o_255_old_s), + SC_NAMED(i_256_s), SC_NAMED(i_256_old_s), SC_NAMED(o_256_s), SC_NAMED(o_256_old_s); + + + tb->i_29(i_29_s); tb->i_29_old(i_29_old_s); tb->o_29(o_29_s); tb->o_29_old(o_29_old_s); + tb->i_30(i_30_s); tb->i_30_old(i_30_old_s); tb->o_30(o_30_s); tb->o_30_old(o_30_old_s); + tb->i_31(i_31_s); tb->i_31_old(i_31_old_s); tb->o_31(o_31_s); tb->o_31_old(o_31_old_s); + tb->i_32(i_32_s); tb->i_32_old(i_32_old_s); tb->o_32(o_32_s); tb->o_32_old(o_32_old_s); + tb->i_59(i_59_s); tb->i_59_old(i_59_old_s); tb->o_59(o_59_s); tb->o_59_old(o_59_old_s); + tb->i_60(i_60_s); tb->i_60_old(i_60_old_s); tb->o_60(o_60_s); tb->o_60_old(o_60_old_s); + tb->i_62(i_62_s); tb->i_62_old(i_62_old_s); tb->o_62(o_62_s); tb->o_62_old(o_62_old_s); + tb->i_64(i_64_s); tb->i_64_old(i_64_old_s); tb->o_64(o_64_s); tb->o_64_old(o_64_old_s); + tb->i_119(i_119_s); tb->i_119_old(i_119_old_s); tb->o_119(o_119_s); tb->o_119_old(o_119_old_s); + tb->i_120(i_120_s); tb->i_120_old(i_120_old_s); tb->o_120(o_120_s); tb->o_120_old(o_120_old_s); + tb->i_121(i_121_s); tb->i_121_old(i_121_old_s); tb->o_121(o_121_s); tb->o_121_old(o_121_old_s); + tb->i_127(i_127_s); tb->i_127_old(i_127_old_s); tb->o_127(o_127_s); tb->o_127_old(o_127_old_s); + tb->i_128(i_128_s); tb->i_128_old(i_128_old_s); tb->o_128(o_128_s); tb->o_128_old(o_128_old_s); + tb->i_255(i_255_s); tb->i_255_old(i_255_old_s); tb->o_255(o_255_s); tb->o_255_old(o_255_old_s); + tb->i_256(i_256_s); tb->i_256_old(i_256_old_s); tb->o_256(o_256_s); tb->o_256_old(o_256_old_s); + + // clang-format on + +#endif + +// clang-format off +#ifdef SYSTEMC_VERSION + sc_start(1, SC_NS); +#else + tb->eval(); +#endif + // This testcase is testing multi-thread safe VL_ASSIGN_SBW and VL_ASSIGN_WSB macros. + // Testbench is assigning different number of bits from VlWide input_var variable to different inputs. + // Values around multiple of 30 (i.e. BITS_PER_DIGIT defined in SystemC sc_nbdefs.h) are tested with the special care, since + // it is the value by which the data_ptr of sc_biguint underlying data type is increased by (and not expected 32, as width of uint32_t). + // Correctness of the output is compared against the 'old' macro, which is correct but has multi-threaded issue since it's using range function. + // Second part is testing VL_ASSIGN_WSB in a reverse way, it is reading signals from the previous test, + // and comparing the output with (fraction) of VlWide input_var variable. + + // clang-format on + VL_ASSIGN_SBW(29, i_29_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(29, i_29_old_s, input_var); + VL_ASSIGN_SBW(30, i_30_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(30, i_30_old_s, input_var); + VL_ASSIGN_SBW(31, i_31_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(31, i_31_old_s, input_var); + VL_ASSIGN_SBW(32, i_32_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(32, i_32_old_s, input_var); + VL_ASSIGN_SBW(59, i_59_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(59, i_59_old_s, input_var); + VL_ASSIGN_SBW(60, i_60_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(60, i_60_old_s, input_var); + VL_ASSIGN_SBW(62, i_62_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(62, i_62_old_s, input_var); + VL_ASSIGN_SBW(64, i_64_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(64, i_64_old_s, input_var); + VL_ASSIGN_SBW(119, i_119_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(119, i_119_old_s, input_var); + VL_ASSIGN_SBW(120, i_120_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(120, i_120_old_s, input_var); + VL_ASSIGN_SBW(121, i_121_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(121, i_121_old_s, input_var); + VL_ASSIGN_SBW(127, i_127_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(127, i_127_old_s, input_var); + VL_ASSIGN_SBW(128, i_128_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(128, i_128_old_s, input_var); + VL_ASSIGN_SBW(255, i_255_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(255, i_255_old_s, input_var); + VL_ASSIGN_SBW(256, i_256_s, input_var); + VL_ASSIGN_SBW_MT_ISSUE(256, i_256_old_s, input_var); + +#ifdef SYSTEMC_VERSION + sc_start(1, SC_NS); +#else + tb->eval(); +#endif + compare_signals(o_29_s, o_29_old_s); + compare_signals(o_30_s, o_30_old_s); + compare_signals(o_31_s, o_31_old_s); + compare_signals(o_32_s, o_32_old_s); + compare_signals(o_59_s, o_59_old_s); + compare_signals(o_60_s, o_60_old_s); + compare_signals(o_62_s, o_62_old_s); + compare_signals(o_64_s, o_64_old_s); + compare_signals(o_119_s, o_119_old_s); + compare_signals(o_120_s, o_120_old_s); + compare_signals(o_121_s, o_121_old_s); + compare_signals(o_127_s, o_127_old_s); + compare_signals(o_128_s, o_128_old_s); + compare_signals(o_255_s, o_255_old_s); + compare_signals(o_256_s, o_256_old_s); + + //////////////////////////////// + + VL_ASSIGN_WSB(29, out_var, o_29_s); + compareWls(29, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(30, out_var, o_30_s); + compareWls(30, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(31, out_var, o_31_s); + compareWls(31, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(32, out_var, o_32_s); + compareWls(32, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(59, out_var, o_59_s); + compareWls(59, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(60, out_var, o_60_s); + compareWls(60, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(62, out_var, o_62_s); + compareWls(62, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(64, out_var, o_64_s); + compareWls(64, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(119, out_var, o_119_s); + compareWls(119, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(120, out_var, o_120_s); + compareWls(120, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(121, out_var, o_121_s); + compareWls(121, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(127, out_var, o_127_s); + compareWls(127, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(128, out_var, o_128_s); + compareWls(128, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(255, out_var, o_255_s); + compareWls(255, input_var.data(), out_var.data()); + VL_ASSIGN_WSB(256, out_var, o_256_s); + compareWls(256, input_var.data(), out_var.data()); + + tb->final(); + VL_DO_DANGLING(delete tb, tb); + + if (pass) { + VL_PRINTF("*-* All Finished *-*\n"); + } else { + vl_fatal(__FILE__, __LINE__, "top", "Unexpected results from test\n"); + } + return 0; +} diff --git a/test_regress/t/t_var_sc_bv.pl b/test_regress/t/t_var_sc_bv.pl new file mode 100755 index 000000000..0091e49f0 --- /dev/null +++ b/test_regress/t/t_var_sc_bv.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-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 + +scenarios(vlt_all => 1); + +compile( + make_top_shell => 0, + make_main => 0, + verilator_flags2 => ["--exe $Self->{t_dir}/t_var_sc_bv.cpp --sc -fno-inline"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_var_sc_bv.v b/test_regress/t/t_var_sc_bv.v new file mode 100644 index 000000000..d3164ee09 --- /dev/null +++ b/test_regress/t/t_var_sc_bv.v @@ -0,0 +1,246 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2008 by Lane Brooks. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Outputs + o_29,o_29_old, + o_30,o_30_old, + o_31,o_31_old, + o_32,o_32_old, + o_59,o_59_old, + o_60,o_60_old, + o_62,o_62_old, + o_64,o_64_old, + o_119,o_119_old, + o_120,o_120_old, + o_121,o_121_old, + o_127,o_127_old, + o_128,o_128_old, + o_255,o_255_old, + o_256,o_256_old, + // Inputs + i_29,i_29_old, + i_30,i_30_old, + i_31,i_31_old, + i_32,i_32_old, + i_59,i_59_old, + i_60,i_60_old, + i_62,i_62_old, + i_64,i_64_old, + i_119,i_119_old, + i_120,i_120_old, + i_121,i_121_old, + i_127,i_127_old, + i_128,i_128_old, + i_255,i_255_old, + i_256,i_256_old + ); + input [255:0] i_29; + output wire [255:0] o_29; + input [255:0] i_29_old; + output wire [255:0] o_29_old; + input [255:0] i_30; + output wire [255:0] o_30; + input [255:0] i_30_old; + output wire [255:0] o_30_old; + input [255:0] i_31; + output wire [255:0] o_31; + input [255:0] i_31_old; + output wire [255:0] o_31_old; + input [255:0] i_32; + output wire [255:0] o_32; + input [255:0] i_32_old; + output wire [255:0] o_32_old; + input [255:0] i_59; + output wire [255:0] o_59; + input [255:0] i_59_old; + output wire [255:0] o_59_old; + input [255:0] i_60; + output wire [255:0] o_60; + input [255:0] i_60_old; + output wire [255:0] o_60_old; + input [255:0] i_62; + output wire [255:0] o_62; + input [255:0] i_62_old; + output wire [255:0] o_62_old; + input [255:0] i_64; + output wire [255:0] o_64; + input [255:0] i_64_old; + output wire [255:0] o_64_old; + input [255:0] i_119; + output wire [255:0] o_119; + input [255:0] i_119_old; + output wire [255:0] o_119_old; + input [255:0] i_120; + output wire [255:0] o_120; + input [255:0] i_120_old; + output wire [255:0] o_120_old; + input [255:0] i_121; + output wire [255:0] o_121; + input [255:0] i_121_old; + output wire [255:0] o_121_old; + input [255:0] i_127; + output wire [255:0] o_127; + input [255:0] i_127_old; + output wire [255:0] o_127_old; + input [255:0] i_128; + output wire [255:0] o_128; + input [255:0] i_128_old; + output wire [255:0] o_128_old; + input [255:0] i_255; + output wire [255:0] o_255; + input [255:0] i_255_old; + output wire [255:0] o_255_old; + input [255:0] i_256; + output wire [255:0] o_256; + input [255:0] i_256_old; + output wire [255:0] o_256_old; + + sub sub (.*); +endmodule + +module sub (/*AUTOARG*/ + // Outputs + o_29,o_29_old, + o_30,o_30_old, + o_31,o_31_old, + o_32,o_32_old, + o_59,o_59_old, + o_60,o_60_old, + o_62,o_62_old, + o_64,o_64_old, + o_119,o_119_old, + o_120,o_120_old, + o_121,o_121_old, + o_127,o_127_old, + o_128,o_128_old, + o_255,o_255_old, + o_256,o_256_old, + // Inputs + i_29,i_29_old, + i_30,i_30_old, + i_31,i_31_old, + i_32,i_32_old, + i_59,i_59_old, + i_60,i_60_old, + i_62,i_62_old, + i_64,i_64_old, + i_119,i_119_old, + i_120,i_120_old, + i_121,i_121_old, + i_127,i_127_old, + i_128,i_128_old, + i_255,i_255_old, + i_256,i_256_old + ); + + input [255:0] i_29; + output wire [255:0] o_29; + input [255:0] i_29_old; + output wire [255:0] o_29_old; + input [255:0] i_30; + output wire [255:0] o_30; + input [255:0] i_30_old; + output wire [255:0] o_30_old; + input [255:0] i_31; + output wire [255:0] o_31; + input [255:0] i_31_old; + output wire [255:0] o_31_old; + input [255:0] i_32; + output wire [255:0] o_32; + input [255:0] i_32_old; + output wire [255:0] o_32_old; + input [255:0] i_59; + output wire [255:0] o_59; + input [255:0] i_59_old; + output wire [255:0] o_59_old; + input [255:0] i_60; + output wire [255:0] o_60; + input [255:0] i_60_old; + output wire [255:0] o_60_old; + input [255:0] i_62; + output wire [255:0] o_62; + input [255:0] i_62_old; + output wire [255:0] o_62_old; + input [255:0] i_64; + output wire [255:0] o_64; + input [255:0] i_64_old; + output wire [255:0] o_64_old; + input [255:0] i_119; + output wire [255:0] o_119; + input [255:0] i_119_old; + output wire [255:0] o_119_old; + input [255:0] i_120; + output wire [255:0] o_120; + input [255:0] i_120_old; + output wire [255:0] o_120_old; + input [255:0] i_121; + output wire [255:0] o_121; + input [255:0] i_121_old; + output wire [255:0] o_121_old; + input [255:0] i_127; + output wire [255:0] o_127; + input [255:0] i_127_old; + output wire [255:0] o_127_old; + input [255:0] i_128; + output wire [255:0] o_128; + input [255:0] i_128_old; + output wire [255:0] o_128_old; + input [255:0] i_255; + output wire [255:0] o_255; + input [255:0] i_255_old; + output wire [255:0] o_255_old; + input [255:0] i_256; + output wire [255:0] o_256; + input [255:0] i_256_old; + output wire [255:0] o_256_old; + + assign o_29 = i_29; + assign o_29_old = i_29_old; + + assign o_30 = i_30; + assign o_30_old = i_30_old; + + assign o_31 = i_31; + assign o_31_old = i_31_old; + + assign o_32 = i_32; + assign o_32_old = i_32_old; + + assign o_59 = i_59; + assign o_59_old = i_59_old; + + assign o_60 = i_60; + assign o_60_old = i_60_old; + + assign o_62 = i_62; + assign o_62_old = i_62_old; + + assign o_64 = i_64; + assign o_64_old = i_64_old; + + assign o_119 = i_119; + assign o_119_old = i_119_old; + + assign o_120 = i_120; + assign o_120_old = i_120_old; + + assign o_121 = i_121; + assign o_121_old = i_121_old; + + assign o_127 = i_127; + assign o_127_old = i_127_old; + + assign o_128 = i_128; + assign o_128_old = i_128_old; + + assign o_255 = i_255; + assign o_255_old = i_255_old; + + assign o_256 = i_256; + assign o_256_old = i_256_old; + +endmodule diff --git a/test_regress/t/t_vpi_get.cpp b/test_regress/t/t_vpi_get.cpp index fdd93ee01..898664841 100644 --- a/test_regress/t/t_vpi_get.cpp +++ b/test_regress/t/t_vpi_get.cpp @@ -71,7 +71,7 @@ } #define CHECK_RESULT_CSTR(got, exp) \ - if (strcmp((got), (exp))) { \ + if (std::strcmp((got), (exp))) { \ printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", FILENM, __LINE__, \ (got) ? (got) : "", (exp) ? (exp) : ""); \ return __LINE__; \ diff --git a/test_regress/t/t_vpi_module.cpp b/test_regress/t/t_vpi_module.cpp index 754cc2660..1c2de048c 100644 --- a/test_regress/t/t_vpi_module.cpp +++ b/test_regress/t/t_vpi_module.cpp @@ -61,7 +61,7 @@ } #define CHECK_RESULT_CSTR(got, exp) \ - if (strcmp((got), (exp))) { \ + if (std::strcmp((got), (exp))) { \ printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", FILENM, __LINE__, \ (got) ? (got) : "", (exp) ? (exp) : ""); \ return __LINE__; \ @@ -100,7 +100,7 @@ int mon_check() { CHECK_RESULT_NZ(t_name); // Icarus reports the top most module as "top" - if (strcmp(t_name, "top") == 0) { + if (std::strcmp(t_name, "top") == 0) { it = vpi_iterate(vpiModule, topmod); CHECK_RESULT_NZ(it); CHECK_RESULT(vpi_get(vpiType, it), vpiModule); @@ -129,7 +129,7 @@ int mon_check() { CHECK_RESULT_NZ(mod3); const char* mod_c_name = vpi_get_str(vpiName, mod3); - if (strcmp(mod_c_name, "mod_b") == 0) { + if (std::strcmp(mod_c_name, "mod_b") == 0) { // Full visibility in other simulators, skip mod_b TestVpiHandle mod4 = vpi_scan(it3); CHECK_RESULT_NZ(mod4); diff --git a/test_regress/t/t_vpi_param.cpp b/test_regress/t/t_vpi_param.cpp index 51415a38b..dcc4a7fb9 100644 --- a/test_regress/t/t_vpi_param.cpp +++ b/test_regress/t/t_vpi_param.cpp @@ -71,7 +71,7 @@ } #define CHECK_RESULT_CSTR(got, exp) \ - if (strcmp((got), (exp))) { \ + if (std::strcmp((got), (exp))) { \ printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", FILENM, __LINE__, \ (got) ? (got) : "", (exp) ? (exp) : ""); \ return __LINE__; \ diff --git a/test_regress/t/t_vpi_unimpl.cpp b/test_regress/t/t_vpi_unimpl.cpp index 549d66e1e..e91515a6e 100644 --- a/test_regress/t/t_vpi_unimpl.cpp +++ b/test_regress/t/t_vpi_unimpl.cpp @@ -66,7 +66,7 @@ unsigned int callback_count = 0; } #define CHECK_RESULT_CSTR(got, exp) \ - if (strcmp((got), (exp))) { \ + if (std::strcmp((got), (exp))) { \ printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", FILENM, __LINE__, \ (got) ? (got) : "", (exp) ? (exp) : ""); \ return __LINE__; \ diff --git a/test_regress/t/t_vpi_var.cpp b/test_regress/t/t_vpi_var.cpp index b8186c281..1c5c76f50 100644 --- a/test_regress/t/t_vpi_var.cpp +++ b/test_regress/t/t_vpi_var.cpp @@ -90,7 +90,7 @@ bool verbose = false; } #define CHECK_RESULT_CSTR(got, exp) \ - if (strcmp((got), (exp))) { \ + if (std::strcmp((got), (exp))) { \ printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", FILENM, __LINE__, \ ((got) != NULL) ? (got) : "", ((exp) != NULL) ? (exp) : ""); \ return __LINE__; \ @@ -117,7 +117,7 @@ int _mon_check_mcd() { } status = vpi_mcd_printf(mcd, (PLI_BYTE8*)"hello %s", "vpi_mcd_printf"); - CHECK_RESULT(status, strlen("hello vpi_mcd_printf")); + CHECK_RESULT(status, std::strlen("hello vpi_mcd_printf")); status = vpi_mcd_printf(0, (PLI_BYTE8*)"empty"); CHECK_RESULT(status, 0); @@ -634,7 +634,7 @@ int _mon_check_vlog_info() { CHECK_RESULT_Z(vlog_info.argv[4]); if (TestSimulator::is_verilator()) { CHECK_RESULT_CSTR(vlog_info.product, "Verilator"); - CHECK_RESULT(strlen(vlog_info.version) > 0, 1); + CHECK_RESULT(std::strlen(vlog_info.version) > 0, 1); } return 0; } diff --git a/test_regress/t/t_weak_nor_strong_assign.pl b/test_regress/t/t_weak_nor_strong_assign.pl new file mode 100755 index 000000000..f5e338520 --- /dev/null +++ b/test_regress/t/t_weak_nor_strong_assign.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 2022 by Antmicro Ltd. 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_weak_nor_strong_assign.v b/test_regress/t/t_weak_nor_strong_assign.v new file mode 100644 index 000000000..a3811ca71 --- /dev/null +++ b/test_regress/t/t_weak_nor_strong_assign.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, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + wire a; + nor (pull0, weak1) n1(a, 0, 0); + assign (strong0, weak1) a = 0; + + always begin + if (!a) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule