From 3e986517c314ce68938b60c52273fd29f47b24bf Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 30 Apr 2023 07:10:14 -0400 Subject: [PATCH 001/129] devel release --- CMakeLists.txt | 2 +- Changes | 7 +++++++ configure.ac | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f323c05f..0377c4d08 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ cmake_minimum_required(VERSION 3.15) cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime project(Verilator - VERSION 5.010 + VERSION 5.011 HOMEPAGE_URL https://verilator.org LANGUAGES CXX ) diff --git a/Changes b/Changes index 637d4196d..86fef83fe 100644 --- a/Changes +++ b/Changes @@ -8,6 +8,13 @@ The changes in each Verilator version are described below. The contributors that suggested a given feature are shown in []. Thanks! +Verilator 5.011 devel +========================== + +**Minor:** + + + Verilator 5.010 2023-04-30 ========================== diff --git a/configure.ac b/configure.ac index 3e45cc298..43bd263f1 100644 --- a/configure.ac +++ b/configure.ac @@ -10,7 +10,7 @@ # Then 'make maintainer-dist' #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[5.010 2023-04-30], +AC_INIT([Verilator],[5.011 devel], [https://verilator.org], [verilator],[https://verilator.org]) From 949be9d0a139ae28be4ade2e6b5538021c8ecbfc Mon Sep 17 00:00:00 2001 From: Hennadii Chernyshchyk Date: Tue, 2 May 2023 14:28:56 +0300 Subject: [PATCH 002/129] Optimize VPI callValueCbs (#4155) Co-authored-by: Oleh Maks --- docs/CONTRIBUTORS | 2 ++ include/verilated_vpi.cpp | 44 +++++++++++++++++++-------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 629517575..103cd554d 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -43,6 +43,7 @@ Guokai Chen Gustav Svensk G-A. Kamendje Harald Heckmann +Hennadii Chernyshchyk Howard Su Huang Rui Huanghuang Zhou @@ -108,6 +109,7 @@ Mostafa Gamal Nandu Raj Nathan Kohagen Nathan Myers +Oleh Maksymenko Patrick Stewart Paul Wright Pawel Sagan diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index 4d84eca49..2d2e00664 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -165,6 +165,7 @@ class VerilatedVpioVarBase VL_NOT_FINAL : public VerilatedVpio { protected: const VerilatedVar* m_varp = nullptr; const VerilatedScope* m_scopep = nullptr; + std::string m_fullname; const VerilatedRange& get_range() const { // Determine number of dimensions and return outermost return (m_varp->dims() > 1) ? m_varp->unpacked() : m_varp->packed(); @@ -173,11 +174,13 @@ protected: public: VerilatedVpioVarBase(const VerilatedVar* varp, const VerilatedScope* scopep) : m_varp{varp} - , m_scopep{scopep} {} + , m_scopep{scopep} + , m_fullname{std::string{m_scopep->name()} + '.' + name()} {} explicit VerilatedVpioVarBase(const VerilatedVpioVarBase* varp) { if (varp) { m_varp = varp->m_varp; m_scopep = varp->m_scopep; + m_fullname = varp->m_fullname; } } static VerilatedVpioVarBase* castp(vpiHandle h) { @@ -188,11 +191,7 @@ public: uint32_t size() const override { return get_range().elements(); } const VerilatedRange* rangep() const override { return &get_range(); } const char* name() const override { return m_varp->name(); } - const char* fullname() const override { - static thread_local std::string t_out; - t_out = std::string{m_scopep->name()} + "." + name(); - return t_out.c_str(); - } + const char* fullname() const override { return m_fullname.c_str(); } }; class VerilatedVpioParam final : public VerilatedVpioVarBase { @@ -646,23 +645,22 @@ public: continue; } VerilatedVpiCbHolder& ho = *it++; - if (VerilatedVpioVar* const varop = VerilatedVpioVar::castp(ho.cb_datap()->obj)) { - void* const newDatap = varop->varDatap(); - void* const prevDatap - = varop->prevDatap(); // Was malloced when we added the callback - VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: value_test %s v[0]=%d/%d %p %p\n", - varop->fullname(), *(static_cast(newDatap)), - *(static_cast(prevDatap)), newDatap, - prevDatap);); - if (std::memcmp(prevDatap, newDatap, varop->entSize()) != 0) { - VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: value_callback %" PRId64 " %s v[0]=%d\n", - ho.id(), varop->fullname(), - *(static_cast(newDatap)));); - update.insert(varop); - vpi_get_value(ho.cb_datap()->obj, ho.cb_datap()->value); - (ho.cb_rtnp())(ho.cb_datap()); - called = true; - } + VerilatedVpioVar* const varop = reinterpret_cast(ho.cb_datap()->obj); + void* const newDatap = varop->varDatap(); + void* const prevDatap + = varop->prevDatap(); // Was malloced when we added the callback + VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: value_test %s v[0]=%d/%d %p %p\n", + varop->fullname(), *(static_cast(newDatap)), + *(static_cast(prevDatap)), newDatap, + prevDatap);); + if (std::memcmp(prevDatap, newDatap, varop->entSize()) != 0) { + VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: value_callback %" PRId64 " %s v[0]=%d\n", + ho.id(), varop->fullname(), + *(static_cast(newDatap)));); + update.insert(varop); + vpi_get_value(ho.cb_datap()->obj, ho.cb_datap()->value); + (ho.cb_rtnp())(ho.cb_datap()); + called = true; } if (was_last) break; } From 128186ea68fc05d084669af2375b99d693bd04bb Mon Sep 17 00:00:00 2001 From: github action Date: Tue, 2 May 2023 11:29:45 +0000 Subject: [PATCH 003/129] Apply 'make format' --- include/verilated_vpi.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index 2d2e00664..083137c95 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -645,14 +645,13 @@ public: continue; } VerilatedVpiCbHolder& ho = *it++; - VerilatedVpioVar* const varop = reinterpret_cast(ho.cb_datap()->obj); + VerilatedVpioVar* const varop + = reinterpret_cast(ho.cb_datap()->obj); void* const newDatap = varop->varDatap(); - void* const prevDatap - = varop->prevDatap(); // Was malloced when we added the callback + void* const prevDatap = varop->prevDatap(); // Was malloced when we added the callback VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: value_test %s v[0]=%d/%d %p %p\n", varop->fullname(), *(static_cast(newDatap)), - *(static_cast(prevDatap)), newDatap, - prevDatap);); + *(static_cast(prevDatap)), newDatap, prevDatap);); if (std::memcmp(prevDatap, newDatap, varop->entSize()) != 0) { VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: value_callback %" PRId64 " %s v[0]=%d\n", ho.id(), varop->fullname(), From 49d2eb9a088ace2c274db49cd0e23007500d2353 Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Tue, 2 May 2023 17:50:57 +0200 Subject: [PATCH 004/129] Fix initialization order of initial static after function/task (#4159) --- src/V3Begin.cpp | 54 +++++++++++++++++++++------------- test_regress/t/t_var_static.pl | 1 + test_regress/t/t_var_static.v | 7 +++++ 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index b7707754d..960d2e780 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -40,6 +40,39 @@ VL_DEFINE_DEBUG_FUNCTIONS; //###################################################################### +class RenameStaticVisitor final : public VNVisitor { +private: + // STATE + const std::set& m_staticFuncVarsr; // Static variables from m_ftaskp + AstNodeFTask* const m_ftaskp; // Current function/task + + // VISITORS + void visit(AstVarRef* nodep) override { + const auto it = m_staticFuncVarsr.find(nodep->varp()); + if (it != m_staticFuncVarsr.end()) nodep->name((*it)->name()); + iterateChildren(nodep); + } + + void visit(AstInitialStatic* nodep) override { + iterateChildren(nodep); + nodep->unlinkFrBack(); + m_ftaskp->addHereThisAsNext(nodep); + } + + void visit(AstNode* nodep) override { iterateChildren(nodep); } + +public: + // CONSTRUCTORS + RenameStaticVisitor(std::set& staticFuncVars, AstNodeFTask* ftaskp, AstNode* nodep) + : m_staticFuncVarsr(staticFuncVars) + , m_ftaskp(ftaskp) { + iterateChildren(nodep); + } + ~RenameStaticVisitor() override = default; +}; + +//###################################################################### + class BeginState final { private: // NODE STATE @@ -123,25 +156,6 @@ private: } } - void renameAndStaticsRecurse(AstNode* const nodep) { - // Rename references and move InitialStatic items - if (AstVarRef* const varrefp = VN_CAST(nodep, VarRef)) { - const auto it = m_staticFuncVars.find(varrefp->varp()); - if (it != m_staticFuncVars.end()) varrefp->name((*it)->name()); - } - - if (nodep->op1p()) renameAndStaticsRecurse(nodep->op1p()); - if (nodep->op2p()) renameAndStaticsRecurse(nodep->op2p()); - if (nodep->op3p()) renameAndStaticsRecurse(nodep->op3p()); - if (nodep->op4p()) renameAndStaticsRecurse(nodep->op4p()); - if (nodep->nextp()) renameAndStaticsRecurse(nodep->nextp()); - - if (VN_IS(nodep, InitialStatic)) { - nodep->unlinkFrBack(); - m_ftaskp->addHereThisAsNext(nodep); - } - } - // VISITORS void visit(AstFork* nodep) override { // Keep begins in forks to group their statements together @@ -197,7 +211,7 @@ private: m_ftaskp = nodep; m_liftedp = nullptr; iterateChildren(nodep); - renameAndStaticsRecurse(nodep); + RenameStaticVisitor{m_staticFuncVars, m_ftaskp, nodep}; if (m_liftedp) { // Place lifted nodes at beginning of stmtsp, so Var nodes appear before referenced if (AstNode* const stmtsp = nodep->stmtsp()) { diff --git a/test_regress/t/t_var_static.pl b/test_regress/t/t_var_static.pl index 93a3a1be3..efb3d2dfc 100755 --- a/test_regress/t/t_var_static.pl +++ b/test_regress/t/t_var_static.pl @@ -16,6 +16,7 @@ compile( execute( check_finished => 1, + all_run_flags => ['+plusarg=value'], ); ok(1); diff --git a/test_regress/t/t_var_static.v b/test_regress/t/t_var_static.v index cb54f6a0c..7eec192a5 100644 --- a/test_regress/t/t_var_static.v +++ b/test_regress/t/t_var_static.v @@ -52,10 +52,17 @@ module t (/*AUTOARG*/ function automatic int f_au_au (); automatic int au = 2; au++; return au; endfunction + string plusarg = ""; + bit has_plusarg = |($value$plusargs("plusarg=%s", plusarg)); int v; initial begin + if (has_plusarg) begin + if (plusarg == "") begin + $fatal(1, "%m: +plusarg must not be empty"); + end + end v = f_no_no(); `checkh(v, 3); v = f_no_no(); `checkh(v, 4); v = f_no_st(); `checkh(v, 3); From 707f2303536f33661dbaa4ac1084a6eae8c3c6f5 Mon Sep 17 00:00:00 2001 From: february cozzocrea <91439207+f-cozzocrea@users.noreply.github.com> Date: Tue, 2 May 2023 11:32:24 -0700 Subject: [PATCH 005/129] Commentary: Update install.rst help2man dependency (#4161) --- docs/CONTRIBUTORS | 1 + docs/guide/install.rst | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 103cd554d..9ca29b828 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -31,6 +31,7 @@ Edgar E. Iglesias Eric Rippey Eyck Jentzsch Fan Shupei +february cozzocrea Felix Neumärker Felix Yan Garrett Smith diff --git a/docs/guide/install.rst b/docs/guide/install.rst index b6e50d16b..681eaeba9 100644 --- a/docs/guide/install.rst +++ b/docs/guide/install.rst @@ -39,7 +39,7 @@ In brief, to install from git: :: # Prerequisites: - #sudo apt-get install git perl python3 make autoconf g++ flex bison ccache + #sudo apt-get install git help2man perl python3 make autoconf g++ flex bison ccache #sudo apt-get install libgoogle-perftools-dev numactl perl-doc #sudo apt-get install libfl2 # Ubuntu only (ignore if gives error) #sudo apt-get install libfl-dev # Ubuntu only (ignore if gives error) From 7708c88e3231c91d4a8fe21a8bd2b07e7d7b3ef4 Mon Sep 17 00:00:00 2001 From: Stefan Wallentowitz Date: Wed, 3 May 2023 02:24:44 +0200 Subject: [PATCH 006/129] Fix duplicate static names in blocks in functions (#4144) (#4160) Static variables of functions are created in the function. When blocks in a function use identical names for static variables, we need to name those variables properly. --- src/V3Begin.cpp | 4 +++- test_regress/t/t_static_dup_name.pl | 23 +++++++++++++++++++ test_regress/t/t_static_dup_name.v | 34 +++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) create mode 100755 test_regress/t/t_static_dup_name.pl create mode 100644 test_regress/t/t_static_dup_name.v diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index 960d2e780..43f062bcd 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -111,6 +111,7 @@ private: string dot(const string& a, const string& b) { if (a == "") return b; + if (b == "") return a; return a + "__DOT__" + b; } @@ -260,7 +261,8 @@ private: void visit(AstVar* nodep) override { // If static variable, move it outside a function. if (nodep->lifetime().isStatic() && m_ftaskp) { - const std::string newName = m_ftaskp->name() + "__Vstatic__" + nodep->name(); + const std::string newName + = m_ftaskp->name() + "__Vstatic__" + dot(m_unnamedScope, nodep->name()); nodep->name(newName); nodep->unlinkFrBack(); m_ftaskp->addHereThisAsNext(nodep); diff --git a/test_regress/t/t_static_dup_name.pl b/test_regress/t/t_static_dup_name.pl new file mode 100755 index 000000000..db885e46d --- /dev/null +++ b/test_regress/t/t_static_dup_name.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +$Self->{verilated_randReset} = 1; + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_static_dup_name.v b/test_regress/t/t_static_dup_name.v new file mode 100644 index 000000000..9d3765238 --- /dev/null +++ b/test_regress/t/t_static_dup_name.v @@ -0,0 +1,34 @@ +// DESCRIPTION: Verilator: Verilog Test module +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + + function do_stuff(); + static int some_int; + begin: block0 + static int some_int; + end + begin: block1 + static int some_int; + end + begin + static int some_int; + end + begin: block2 + begin: block3 + static int some_int; + end + begin + static int some_int; + end + end + endfunction + + initial begin + $write("*-* All Finished *-*\n"); + $finish(); + end + +endmodule From dc25be536cddb60f8b4680916036038f066dc16a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 2 May 2023 21:21:10 -0400 Subject: [PATCH 007/129] Internals: Deprecate VL_ATTR_ALIGNED, use alignas instead. --- include/verilatedos.h | 5 +---- src/V3EmitCHeaders.cpp | 7 ++----- src/V3EmitCModel.cpp | 4 ++-- src/V3EmitCSyms.cpp | 5 +++-- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/include/verilatedos.h b/include/verilatedos.h index 625552d4f..6a24ea36f 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -38,7 +38,6 @@ // Compiler pragma abstraction #ifdef __GNUC__ -# define VL_ATTR_ALIGNED(alignment) __attribute__((aligned(alignment))) # define VL_ATTR_ALWINLINE __attribute__((always_inline)) inline # define VL_ATTR_NOINLINE __attribute__((noinline)) # define VL_ATTR_COLD __attribute__((cold)) @@ -78,9 +77,6 @@ #endif // Defaults for unsupported compiler features -#ifndef VL_ATTR_ALIGNED -# define VL_ATTR_ALIGNED(alignment) ///< Attribute to align structure to byte alignment -#endif #ifndef VL_ATTR_ALWINLINE # define VL_ATTR_ALWINLINE ///< Attribute to inline, even when not optimizing #endif @@ -142,6 +138,7 @@ #ifndef VL_NO_LEGACY +# define VL_ATTR_ALIGNED(alignment) // Deprecated # define VL_FUNC __func__ // Deprecated # define VL_THREAD // Deprecated # define VL_THREAD_LOCAL thread_local // Deprecated diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp index 63a06a956..798006653 100644 --- a/src/V3EmitCHeaders.cpp +++ b/src/V3EmitCHeaders.cpp @@ -300,6 +300,7 @@ class EmitCHeader final : public EmitCConstInit { // Open class body {{{ puts("\nclass "); + if (!VN_IS(modp, Class)) puts("alignas(VL_CACHE_LINE_BYTES) "); puts(prefixNameProtect(modp)); if (const AstClass* const classp = VN_CAST(modp, Class)) { puts(" : public "); @@ -329,11 +330,7 @@ class EmitCHeader final : public EmitCConstInit { emitTextSection(modp, VNType::atScInt); // Close class body - if (!VN_IS(modp, Class)) { - puts("} VL_ATTR_ALIGNED(VL_CACHE_LINE_BYTES);\n"); - } else { - puts("};\n"); - } + puts("};\n"); // }}} // Emit out of class function declarations diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp index e7debc3cd..d63708828 100644 --- a/src/V3EmitCModel.cpp +++ b/src/V3EmitCModel.cpp @@ -89,7 +89,7 @@ class EmitCModel final : public EmitCFunc { puts("\n"); puts("// This class is the main interface to the Verilated model\n"); - puts("class " + topClassName() + " VL_NOT_FINAL : "); + puts("class alignas(VL_CACHE_LINE_BYTES) " + topClassName() + " VL_NOT_FINAL : "); if (optSystemC()) { // SC_MODULE, but with multiple-inheritance of VerilatedModel puts("public ::sc_core::sc_module, "); @@ -238,7 +238,7 @@ class EmitCModel final : public EmitCFunc { puts("std::unique_ptr traceConfig() const override final;\n"); } - puts("} VL_ATTR_ALIGNED(VL_CACHE_LINE_BYTES);\n"); + puts("};\n"); ofp()->putsEndGuard(); diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 59b299d7b..04ea78814 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -440,7 +440,8 @@ void EmitCSyms::emitSymHdr() { } puts("\n// SYMS CLASS (contains all model state)\n"); - puts("class " + symClassName() + " final : public VerilatedSyms {\n"); + puts("class alignas(VL_CACHE_LINE_BYTES)" + symClassName() + + " final : public VerilatedSyms {\n"); ofp()->putsPrivate(false); // public: puts("// INTERNAL STATE\n"); @@ -554,7 +555,7 @@ void EmitCSyms::emitSymHdr() { puts("void " + protect("__Vserialize") + "(VerilatedSerialize& os);\n"); puts("void " + protect("__Vdeserialize") + "(VerilatedDeserialize& os);\n"); } - puts("} VL_ATTR_ALIGNED(VL_CACHE_LINE_BYTES);\n"); + puts("};\n"); ofp()->putsEndGuard(); VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); From d9b5680a4596d55265ef57acfae2606880a2996c Mon Sep 17 00:00:00 2001 From: Tudor Timi Date: Wed, 3 May 2023 23:04:18 +0200 Subject: [PATCH 008/129] Fix crash caused by $display() optimization (#4165) (#4166) --- docs/CONTRIBUTORS | 1 + src/V3Const.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 9ca29b828..85fcb791f 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -146,6 +146,7 @@ Todd Strader Tomasz Gorochowik Topa Topino Toru Niina +Tudor Timi Tymoteusz Blazejczyk Udi Finkelstein Unai Martinez-Corral diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 47f1a4b05..934307192 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -3064,7 +3064,7 @@ private: && nodep->displayType() == VDisplayType::DT_WRITE))) return false; if ((prevp->filep() && !nodep->filep()) || (!prevp->filep() && nodep->filep()) - || !prevp->filep()->sameTree(nodep->filep())) + || (prevp->filep() && nodep->filep() && !prevp->filep()->sameTree(nodep->filep()))) return false; if (!prevp->fmtp() || prevp->fmtp()->nextp() || !nodep->fmtp() || nodep->fmtp()->nextp()) return false; From add68130b811d3cde94544714397248ba36381ff Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 3 May 2023 18:04:10 -0400 Subject: [PATCH 009/129] Internals: Rename to dumpLevel(), to avoid confusion with make-a-dump() --- src/V3Active.cpp | 4 ++-- src/V3ActiveTop.cpp | 2 +- src/V3Assert.cpp | 2 +- src/V3AssertPre.cpp | 2 +- src/V3Ast.cpp | 4 ++-- src/V3Begin.cpp | 2 +- src/V3CCtors.cpp | 2 +- src/V3CUse.cpp | 2 +- src/V3Case.cpp | 2 +- src/V3Cast.cpp | 2 +- src/V3Class.cpp | 2 +- src/V3Clean.cpp | 2 +- src/V3Clock.cpp | 2 +- src/V3Combine.cpp | 2 +- src/V3Common.cpp | 2 +- src/V3Const.cpp | 8 ++++---- src/V3Coverage.cpp | 2 +- src/V3CoverageJoin.cpp | 2 +- src/V3Dead.cpp | 10 +++++----- src/V3Delayed.cpp | 2 +- src/V3Depth.cpp | 2 +- src/V3DepthBlock.cpp | 2 +- src/V3Descope.cpp | 2 +- src/V3DfgOptimizer.cpp | 12 ++++++------ src/V3DfgPasses.cpp | 6 +++--- src/V3DupFinder.cpp | 2 +- src/V3Error.cpp | 4 ++-- src/V3Error.h | 16 +++++++--------- src/V3Expand.cpp | 2 +- src/V3Force.cpp | 2 +- src/V3Gate.cpp | 12 ++++++------ src/V3GraphAcyc.cpp | 12 ++++++------ src/V3GraphTest.cpp | 2 +- src/V3Inline.cpp | 2 +- src/V3Inst.cpp | 4 ++-- src/V3Life.cpp | 2 +- src/V3LifePost.cpp | 2 +- src/V3LinkCells.cpp | 2 +- src/V3LinkDot.cpp | 20 ++++++++++---------- src/V3LinkInc.cpp | 2 +- src/V3LinkJump.cpp | 2 +- src/V3LinkLValue.cpp | 2 +- src/V3LinkLevel.cpp | 4 ++-- src/V3LinkParse.cpp | 2 +- src/V3LinkResolve.cpp | 2 +- src/V3Localize.cpp | 2 +- src/V3MergeCond.cpp | 2 +- src/V3Name.cpp | 2 +- src/V3Order.cpp | 16 ++++++++-------- src/V3Param.cpp | 2 +- src/V3Partition.cpp | 8 ++++---- src/V3Premit.cpp | 2 +- src/V3Randomize.cpp | 2 +- src/V3Reloop.cpp | 2 +- src/V3Sched.cpp | 2 +- src/V3SchedAcyclic.cpp | 2 +- src/V3SchedPartition.cpp | 4 ++-- src/V3SchedReplicate.cpp | 4 ++-- src/V3SchedTiming.cpp | 2 +- src/V3Scope.cpp | 2 +- src/V3Slice.cpp | 2 +- src/V3Split.cpp | 14 +++++++------- src/V3SplitAs.cpp | 2 +- src/V3SplitVar.cpp | 4 ++-- src/V3Subst.cpp | 2 +- src/V3SymTable.h | 2 +- src/V3TSP.cpp | 12 ++++++------ src/V3Table.cpp | 2 +- src/V3Task.cpp | 4 ++-- src/V3Timing.cpp | 4 ++-- src/V3Trace.cpp | 8 ++++---- src/V3TraceDecl.cpp | 2 +- src/V3Tristate.cpp | 4 ++-- src/V3Unknown.cpp | 2 +- src/V3Unroll.cpp | 2 +- src/V3VariableOrder.cpp | 2 +- src/V3Width.cpp | 4 ++-- src/Verilator.cpp | 2 +- 78 files changed, 153 insertions(+), 155 deletions(-) diff --git a/src/V3Active.cpp b/src/V3Active.cpp index 87194907f..e7029790a 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -183,7 +183,7 @@ public: << " (not all control paths of combinational always assign a value)\n" << nodep->warnMore() << "... Suggest use of always_latch for intentional latches"); - if (dumpGraph() >= 9) dumpDotFilePrefixed("latch_" + vrp->name()); + if (dumpGraphLevel() >= 9) dumpDotFilePrefixed("latch_" + vrp->name()); } vertp->user(false); // Clear again (see above) vrp->varp()->isLatched(latch_detected); @@ -652,5 +652,5 @@ public: void V3Active::activeAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { ActiveVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("active", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("active", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3ActiveTop.cpp b/src/V3ActiveTop.cpp index 29d9df091..16cfe6e95 100644 --- a/src/V3ActiveTop.cpp +++ b/src/V3ActiveTop.cpp @@ -145,5 +145,5 @@ public: void V3ActiveTop::activeTopAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { ActiveTopVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("activetop", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("activetop", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 15969106a..91ae114ca 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -544,5 +544,5 @@ public: void V3Assert::assertAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { AssertVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("assert", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("assert", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp index 51a12ad14..341204593 100644 --- a/src/V3AssertPre.cpp +++ b/src/V3AssertPre.cpp @@ -496,5 +496,5 @@ public: void V3AssertPre::assertPreAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { AssertPreVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("assertpre", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("assertpre", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index dcc43148c..0be9e89a5 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -1217,7 +1217,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump, boo if (logsp->fail()) v3fatal("Can't write " << filename); *logsp << "Verilator Tree Dump (format 0x3900) from to \n"; - if (editCountGbl() == editCountLast() && ::dumpTree() < 9) { + if (editCountGbl() == editCountLast() && ::dumpTreeLevel() < 9) { *logsp << '\n'; *logsp << "No changes since last dump!\n"; } else { @@ -1227,7 +1227,7 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump, boo } } if (doDump && v3Global.opt.debugEmitV()) V3EmitV::debugEmitV(filename + ".v"); - if (doCheck && (v3Global.opt.debugCheck() || ::dumpTree())) { + if (doCheck && (v3Global.opt.debugCheck() || ::dumpTreeLevel())) { // Error check checkTree(); // Broken isn't part of check tree because it can munge iterp's diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index 43f062bcd..d18f4be1d 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -408,5 +408,5 @@ void V3Begin::debeginAll(AstNetlist* nodep) { { BeginVisitor{nodep, &state}; } if (state.anyFuncInBegin()) { BeginRelinkVisitor{nodep, &state}; } } // Destruct before checking - V3Global::dumpCheckGlobalTree("begin", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("begin", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3CCtors.cpp b/src/V3CCtors.cpp index a079006ec..3c1265c67 100644 --- a/src/V3CCtors.cpp +++ b/src/V3CCtors.cpp @@ -257,5 +257,5 @@ void V3CCtors::cctorsAll() { UINFO(2, __FUNCTION__ << ": " << endl); evalAsserts(); { CCtorsVisitor{v3Global.rootp()}; } - V3Global::dumpCheckGlobalTree("cctors", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("cctors", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3CUse.cpp b/src/V3CUse.cpp index 9085ba8d9..d9de9a10d 100644 --- a/src/V3CUse.cpp +++ b/src/V3CUse.cpp @@ -115,5 +115,5 @@ void V3CUse::cUseAll() { // for each output file and put under that CUseVisitor{modp}; } - V3Global::dumpCheckGlobalTree("cuse", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("cuse", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Case.cpp b/src/V3Case.cpp index 4ae5969ad..c8cd473c2 100644 --- a/src/V3Case.cpp +++ b/src/V3Case.cpp @@ -566,7 +566,7 @@ public: void V3Case::caseAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { CaseVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("case", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("case", 0, dumpTreeLevel() >= 3); } void V3Case::caseLint(AstNodeCase* nodep) { UINFO(4, __FUNCTION__ << ": " << endl); diff --git a/src/V3Cast.cpp b/src/V3Cast.cpp index 4f253beed..7c3d47c53 100644 --- a/src/V3Cast.cpp +++ b/src/V3Cast.cpp @@ -208,5 +208,5 @@ public: void V3Cast::castAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { CastVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("cast", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("cast", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Class.cpp b/src/V3Class.cpp index 3c726a3a6..71cd260d3 100644 --- a/src/V3Class.cpp +++ b/src/V3Class.cpp @@ -244,5 +244,5 @@ public: void V3Class::classAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { ClassVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("class", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("class", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Clean.cpp b/src/V3Clean.cpp index 8d0718700..218517aa0 100644 --- a/src/V3Clean.cpp +++ b/src/V3Clean.cpp @@ -325,5 +325,5 @@ public: void V3Clean::cleanAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { CleanVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("clean", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("clean", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Clock.cpp b/src/V3Clock.cpp index bf374d2a3..c72730ffb 100644 --- a/src/V3Clock.cpp +++ b/src/V3Clock.cpp @@ -224,5 +224,5 @@ public: void V3Clock::clockAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { ClockVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("clock", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("clock", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Combine.cpp b/src/V3Combine.cpp index 44e9b2954..a4d425229 100644 --- a/src/V3Combine.cpp +++ b/src/V3Combine.cpp @@ -238,5 +238,5 @@ public: void V3Combine::combineAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); CombineVisitor::apply(nodep); - V3Global::dumpCheckGlobalTree("combine", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("combine", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Common.cpp b/src/V3Common.cpp index b5f5a4c8c..ed1570c51 100644 --- a/src/V3Common.cpp +++ b/src/V3Common.cpp @@ -172,5 +172,5 @@ void V3Common::commonAll() { if (!dtypep->packed()) makeVlToString(dtypep); } } - V3Global::dumpCheckGlobalTree("common", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("common", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 934307192..a5413c1ec 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -3759,7 +3759,7 @@ void V3Const::constifyAllLint(AstNetlist* nodep) { ConstVisitor visitor{ConstVisitor::PROC_V_WARN, /* globalPass: */ true}; (void)visitor.mainAcceptEdit(nodep); } // Destruct before checking - V3Global::dumpCheckGlobalTree("const", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("const", 0, dumpTreeLevel() >= 3); } void V3Const::constifyCpp(AstNetlist* nodep) { @@ -3768,7 +3768,7 @@ void V3Const::constifyCpp(AstNetlist* nodep) { ConstVisitor visitor{ConstVisitor::PROC_CPP, /* globalPass: */ true}; (void)visitor.mainAcceptEdit(nodep); } // Destruct before checking - V3Global::dumpCheckGlobalTree("const_cpp", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("const_cpp", 0, dumpTreeLevel() >= 3); } AstNode* V3Const::constifyEdit(AstNode* nodep) { @@ -3792,7 +3792,7 @@ void V3Const::constifyAllLive(AstNetlist* nodep) { ConstVisitor visitor{ConstVisitor::PROC_LIVE, /* globalPass: */ true}; (void)visitor.mainAcceptEdit(nodep); } // Destruct before checking - V3Global::dumpCheckGlobalTree("const", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("const", 0, dumpTreeLevel() >= 3); } void V3Const::constifyAll(AstNetlist* nodep) { @@ -3802,7 +3802,7 @@ void V3Const::constifyAll(AstNetlist* nodep) { ConstVisitor visitor{ConstVisitor::PROC_V_EXPENSIVE, /* globalPass: */ true}; (void)visitor.mainAcceptEdit(nodep); } // Destruct before checking - V3Global::dumpCheckGlobalTree("const", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("const", 0, dumpTreeLevel() >= 3); } AstNode* V3Const::constifyExpensiveEdit(AstNode* nodep) { diff --git a/src/V3Coverage.cpp b/src/V3Coverage.cpp index 340668e71..280e652cc 100644 --- a/src/V3Coverage.cpp +++ b/src/V3Coverage.cpp @@ -567,5 +567,5 @@ public: void V3Coverage::coverage(AstNetlist* rootp) { UINFO(2, __FUNCTION__ << ": " << endl); { CoverageVisitor{rootp}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("coverage", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("coverage", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3CoverageJoin.cpp b/src/V3CoverageJoin.cpp index 8b087f09f..dbfc26862 100644 --- a/src/V3CoverageJoin.cpp +++ b/src/V3CoverageJoin.cpp @@ -117,5 +117,5 @@ public: void V3CoverageJoin::coverageJoin(AstNetlist* rootp) { UINFO(2, __FUNCTION__ << ": " << endl); { CoverageJoinVisitor{rootp}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("coveragejoin", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("coveragejoin", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index 5faad31e1..b0d798ab1 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -539,29 +539,29 @@ void V3Dead::deadifyModules(AstNetlist* nodep) { { DeadVisitor{nodep, false, false, false, false, !v3Global.opt.topIfacesSupported()}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("deadModules", 0, dumpTree() >= 6); + V3Global::dumpCheckGlobalTree("deadModules", 0, dumpTreeLevel() >= 6); } void V3Dead::deadifyDTypes(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DeadVisitor{nodep, false, true, false, false, false}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("deadDtypes", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("deadDtypes", 0, dumpTreeLevel() >= 3); } void V3Dead::deadifyDTypesScoped(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DeadVisitor{nodep, false, true, true, false, false}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0, dumpTreeLevel() >= 3); } void V3Dead::deadifyAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DeadVisitor{nodep, true, true, false, true, false}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("deadAll", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("deadAll", 0, dumpTreeLevel() >= 3); } void V3Dead::deadifyAllScoped(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DeadVisitor{nodep, true, true, true, true, false}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("deadAllScoped", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("deadAllScoped", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index 1a491422d..2fec08043 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -641,5 +641,5 @@ public: void V3Delayed::delayedAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DelayedVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("delayed", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("delayed", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Depth.cpp b/src/V3Depth.cpp index 2ca383362..32797e069 100644 --- a/src/V3Depth.cpp +++ b/src/V3Depth.cpp @@ -166,5 +166,5 @@ public: void V3Depth::depthAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DepthVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("depth", 0, dumpTree() >= 6); + V3Global::dumpCheckGlobalTree("depth", 0, dumpTreeLevel() >= 6); } diff --git a/src/V3DepthBlock.cpp b/src/V3DepthBlock.cpp index 889601de2..4adebda13 100644 --- a/src/V3DepthBlock.cpp +++ b/src/V3DepthBlock.cpp @@ -127,5 +127,5 @@ public: void V3DepthBlock::depthBlockAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DepthBlockVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("deepblock", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("deepblock", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Descope.cpp b/src/V3Descope.cpp index 3c1eeb518..1d4866faf 100644 --- a/src/V3Descope.cpp +++ b/src/V3Descope.cpp @@ -285,5 +285,5 @@ public: void V3Descope::descopeAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DescopeVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("descope", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("descope", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3DfgOptimizer.cpp b/src/V3DfgOptimizer.cpp index d3b361bf6..a299cae0e 100644 --- a/src/V3DfgOptimizer.cpp +++ b/src/V3DfgOptimizer.cpp @@ -237,7 +237,7 @@ void V3DfgOptimizer::extract(AstNetlist* netlistp) { UINFO(2, __FUNCTION__ << ": " << endl); // Extract more optimization candidates DataflowExtractVisitor::apply(netlistp); - V3Global::dumpCheckGlobalTree("dfg-extract", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("dfg-extract", 0, dumpTreeLevel() >= 3); } void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) { @@ -267,7 +267,7 @@ void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) { // Build the DFG of this module const std::unique_ptr dfg{V3DfgPasses::astToDfg(*modp, ctx)}; - if (dumpDfg() >= 8) dfg->dumpDotFilePrefixed(ctx.prefix() + "whole-input"); + if (dumpDfgLevel() >= 8) dfg->dumpDotFilePrefixed(ctx.prefix() + "whole-input"); // Extract the cyclic sub-graphs. We do this because a lot of the optimizations assume a // DAG, and large, mostly acyclic graphs could not be optimized due to the presence of @@ -284,7 +284,7 @@ void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) { // For each cyclic component for (auto& component : cyclicComponents) { - if (dumpDfg() >= 7) component->dumpDotFilePrefixed(ctx.prefix() + "source"); + if (dumpDfgLevel() >= 7) component->dumpDotFilePrefixed(ctx.prefix() + "source"); // TODO: Apply optimizations safe for cyclic graphs // Add back under the main DFG (we will convert everything back in one go) dfg->addGraph(*component); @@ -292,7 +292,7 @@ void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) { // For each acyclic component for (auto& component : acyclicComponents) { - if (dumpDfg() >= 7) component->dumpDotFilePrefixed(ctx.prefix() + "source"); + if (dumpDfgLevel() >= 7) component->dumpDotFilePrefixed(ctx.prefix() + "source"); // Optimize the component V3DfgPasses::optimize(*component, ctx); // Add back under the main DFG (we will convert everything back in one go) @@ -300,9 +300,9 @@ void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) { } // Convert back to Ast - if (dumpDfg() >= 8) dfg->dumpDotFilePrefixed(ctx.prefix() + "whole-optimized"); + if (dumpDfgLevel() >= 8) dfg->dumpDotFilePrefixed(ctx.prefix() + "whole-optimized"); AstModule* const resultModp = V3DfgPasses::dfgToAst(*dfg, ctx); UASSERT_OBJ(resultModp == modp, modp, "Should be the same module"); } - V3Global::dumpCheckGlobalTree("dfg-optimize", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("dfg-optimize", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3DfgPasses.cpp b/src/V3DfgPasses.cpp index edeb007dd..3edfe5a88 100644 --- a/src/V3DfgPasses.cpp +++ b/src/V3DfgPasses.cpp @@ -285,7 +285,7 @@ void V3DfgPasses::optimize(DfgGraph& dfg, V3DfgOptimizationContext& ctx) { const auto apply = [&](int dumpLevel, const string& name, std::function pass) { pass(); - if (dumpDfg() >= dumpLevel) { + if (dumpDfgLevel() >= dumpLevel) { const string strippedName = VString::removeWhitespace(name); const string label = ctx.prefix() + "pass-" + cvtToStr(passNumber) + "-" + strippedName; @@ -294,7 +294,7 @@ void V3DfgPasses::optimize(DfgGraph& dfg, V3DfgOptimizationContext& ctx) { ++passNumber; }; - if (dumpDfg() >= 8) dfg.dumpDotAllVarConesPrefixed(ctx.prefix() + "input"); + if (dumpDfgLevel() >= 8) dfg.dumpDotAllVarConesPrefixed(ctx.prefix() + "input"); apply(3, "input ", [&]() {}); apply(4, "inlineVars ", [&]() { inlineVars(dfg); }); apply(4, "cse0 ", [&]() { cse(dfg, ctx.m_cseContext0); }); @@ -304,5 +304,5 @@ void V3DfgPasses::optimize(DfgGraph& dfg, V3DfgOptimizationContext& ctx) { apply(4, "cse1 ", [&]() { cse(dfg, ctx.m_cseContext1); }); } apply(4, "removeVars ", [&]() { removeVars(dfg, ctx.m_removeVarsContext); }); - if (dumpDfg() >= 8) dfg.dumpDotAllVarConesPrefixed(ctx.prefix() + "optimized"); + if (dumpDfgLevel() >= 8) dfg.dumpDotAllVarConesPrefixed(ctx.prefix() + "optimized"); } diff --git a/src/V3DupFinder.cpp b/src/V3DupFinder.cpp index 49fcf2808..f41d9b1df 100644 --- a/src/V3DupFinder.cpp +++ b/src/V3DupFinder.cpp @@ -100,5 +100,5 @@ void V3DupFinder::dumpFile(const string& filename, bool tree) { } void V3DupFinder::dumpFilePrefixed(const string& nameComment, bool tree) { - if (dump()) dumpFile(v3Global.debugFilename(nameComment) + ".hash", tree); + if (dumpLevel()) dumpFile(v3Global.debugFilename(nameComment) + ".hash", tree); } diff --git a/src/V3Error.cpp b/src/V3Error.cpp index 6fc051edc..a0fa7a3d3 100644 --- a/src/V3Error.cpp +++ b/src/V3Error.cpp @@ -220,10 +220,10 @@ void V3ErrorGuarded::v3errorEnd(std::ostringstream& sstr, const string& extra) tellManual(2); } #ifndef V3ERROR_NO_GLOBAL_ - if (dumpTree() || debug()) { + if (dumpTreeLevel() || debug()) { V3Broken::allowMidvisitorCheck(true); V3ThreadPool::s().requestExclusiveAccess([&]() VL_REQUIRES(m_mutex) { - if (dumpTree()) { + if (dumpTreeLevel()) { v3Global.rootp()->dumpTreeFile( v3Global.debugFilename("final.tree", 990)); } diff --git a/src/V3Error.h b/src/V3Error.h index 01578fa0e..8d0f784b3 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -666,12 +666,10 @@ inline void v3errorEndFatal(std::ostringstream& sstr) static_assert(true, "") // Takes an optional "name" (as __VA_ARGS__) -#define VL_DEFINE_DUMP(...) \ - VL_ATTR_UNUSED static int dump##__VA_ARGS__() { \ +#define VL_DEFINE_DUMP(func, tag) \ + VL_ATTR_UNUSED static int dump##func() { \ static int level = -1; \ if (VL_UNLIKELY(level < 0)) { \ - std::string tag{VL_STRINGIFY(__VA_ARGS__)}; \ - tag[0] = std::tolower(tag[0]); \ const unsigned dumpTag = v3Global.opt.dumpLevel(tag); \ const unsigned dumpSrc = v3Global.opt.dumpSrcLevel(__FILE__); \ const unsigned dumpLevel = dumpTag >= dumpSrc ? dumpTag : dumpSrc; \ @@ -685,11 +683,11 @@ inline void v3errorEndFatal(std::ostringstream& sstr) // Define debug*() and dump*() routines. This needs to be added to every compilation unit so that // --debugi- and --dumpi- can be used to control debug prints and dumping #define VL_DEFINE_DEBUG_FUNCTIONS \ - VL_DEFINE_DEBUG(); /* Define 'int debug()' */ \ - VL_DEFINE_DUMP(); /* Define 'int dump()' */ \ - VL_DEFINE_DUMP(Dfg); /* Define 'int dumpDfg()' */ \ - VL_DEFINE_DUMP(Graph); /* Define 'int dumpGraph()' */ \ - VL_DEFINE_DUMP(Tree); /* Define 'int dumpTree()' */ \ + VL_DEFINE_DEBUG(); /* Define 'int debug()' for --debugi */ \ + VL_DEFINE_DUMP(Level, ""); /* Define 'int dumpLevel()' for --dumpi */ \ + VL_DEFINE_DUMP(DfgLevel, "dfg"); /* Define 'int dumpDfgLevel()' for --dumpi-level */ \ + VL_DEFINE_DUMP(GraphLevel, "graph"); /* Define 'int dumpGraphLevel()' for dumpi-graph */ \ + VL_DEFINE_DUMP(TreeLevel, "tree"); /* Define 'int dumpTreeLevel()' for dumpi-tree */ \ static_assert(true, "") //---------------------------------------------------------------------- diff --git a/src/V3Expand.cpp b/src/V3Expand.cpp index a34660a7d..5f3cf6fb7 100644 --- a/src/V3Expand.cpp +++ b/src/V3Expand.cpp @@ -915,5 +915,5 @@ public: void V3Expand::expandAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { ExpandVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("expand", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("expand", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Force.cpp b/src/V3Force.cpp index 1073f1c8c..9d563a687 100644 --- a/src/V3Force.cpp +++ b/src/V3Force.cpp @@ -314,5 +314,5 @@ void V3Force::forceAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); if (!v3Global.hasForceableSignals()) return; ForceConvertVisitor::apply(nodep); - V3Global::dumpCheckGlobalTree("force", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("force", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 640cade21..2c6497cb9 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -421,12 +421,12 @@ private: // VISITORS void visit(AstNetlist* nodep) override { iterateChildren(nodep); - if (dumpGraph() >= 3) m_graph.dumpDotFilePrefixed("gate_pre"); + if (dumpGraphLevel() >= 3) m_graph.dumpDotFilePrefixed("gate_pre"); warnSignals(); // Before loss of sync/async pointers // Decompose clock vectors -- need to do this before removing redundant edges decomposeClkVectors(); m_graph.removeRedundantEdgesSum(&V3GraphEdge::followAlwaysTrue); - if (dumpGraph() >= 6) m_graph.dumpDotFilePrefixed("gate_simp"); + if (dumpGraphLevel() >= 6) m_graph.dumpDotFilePrefixed("gate_simp"); // Find gate interconnect and optimize m_graph.userClearVertices(); // vertex->user(): bool. Indicates we've set it as consumed // Get rid of buffers first, @@ -438,15 +438,15 @@ private: // Remove redundant logic if (v3Global.opt.fDedupe()) { dedupe(); - if (dumpGraph() >= 6) m_graph.dumpDotFilePrefixed("gate_dedup"); + if (dumpGraphLevel() >= 6) m_graph.dumpDotFilePrefixed("gate_dedup"); } if (v3Global.opt.fAssemble()) { mergeAssigns(); - if (dumpGraph() >= 6) m_graph.dumpDotFilePrefixed("gate_assm"); + if (dumpGraphLevel() >= 6) m_graph.dumpDotFilePrefixed("gate_assm"); } // Consumption warnings consumedMark(); - if (dumpGraph() >= 3) m_graph.dumpDotFilePrefixed("gate_opt"); + if (dumpGraphLevel() >= 3) m_graph.dumpDotFilePrefixed("gate_opt"); // Rewrite assignments consumedMove(); } @@ -1488,5 +1488,5 @@ void GateVisitor::decomposeClkVectors() { void V3Gate::gateAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { const GateVisitor visitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("gate", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("gate", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3GraphAcyc.cpp b/src/V3GraphAcyc.cpp index c31485d26..ddae8c48b 100644 --- a/src/V3GraphAcyc.cpp +++ b/src/V3GraphAcyc.cpp @@ -544,28 +544,28 @@ void GraphAcyc::main() { // edges (and thus can't represent loops - if we did the unbreakable // marking right, anyways) buildGraph(m_origGraphp); - if (dumpGraph() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_pre"); + if (dumpGraphLevel() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_pre"); // Perform simple optimizations before any cuttings simplify(false); - if (dumpGraph() >= 5) m_breakGraph.dumpDotFilePrefixed("acyc_simp"); + if (dumpGraphLevel() >= 5) m_breakGraph.dumpDotFilePrefixed("acyc_simp"); UINFO(4, " Cutting trivial loops\n"); simplify(true); - if (dumpGraph() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_mid"); + if (dumpGraphLevel() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_mid"); UINFO(4, " Ranking\n"); m_breakGraph.rank(&V3GraphEdge::followNotCutable); - if (dumpGraph() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_rank"); + if (dumpGraphLevel() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_rank"); UINFO(4, " Placement\n"); place(); - if (dumpGraph() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_place"); + if (dumpGraphLevel() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_place"); UINFO(4, " Final Ranking\n"); // Only needed to assert there are no loops in completed graph m_breakGraph.rank(&V3GraphEdge::followAlwaysTrue); - if (dumpGraph() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_done"); + if (dumpGraphLevel() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_done"); } void V3Graph::acyclic(V3EdgeFuncP edgeFuncp) { diff --git a/src/V3GraphTest.cpp b/src/V3GraphTest.cpp index 8a9637cdf..e90251a58 100644 --- a/src/V3GraphTest.cpp +++ b/src/V3GraphTest.cpp @@ -37,7 +37,7 @@ protected: // Utilities void dumpSelf() { - if (dumpGraph() >= 9) m_graph.dumpDotFilePrefixed("v3graphtest_" + name()); + if (dumpGraphLevel() >= 9) m_graph.dumpDotFilePrefixed("v3graphtest_" + name()); } public: diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index b2774b60e..43aac0fa4 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -727,5 +727,5 @@ void V3Inline::inlineAll(AstNetlist* nodep) { } { InlineIntfRefVisitor{nodep}; } - V3Global::dumpCheckGlobalTree("inline", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("inline", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index 061e5caeb..f451f8b54 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -616,11 +616,11 @@ void V3Inst::checkOutputShort(AstPin* nodep) { void V3Inst::instAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { InstVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("inst", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("inst", 0, dumpTreeLevel() >= 3); } void V3Inst::dearrayAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { InstDeVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("dearray", 0, dumpTree() >= 6); + V3Global::dumpCheckGlobalTree("dearray", 0, dumpTreeLevel() >= 6); } diff --git a/src/V3Life.cpp b/src/V3Life.cpp index 7ba66e97b..c3ff35eba 100644 --- a/src/V3Life.cpp +++ b/src/V3Life.cpp @@ -515,5 +515,5 @@ void V3Life::lifeAll(AstNetlist* nodep) { LifeState state; LifeTopVisitor{nodep, &state}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("life", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("life", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3LifePost.cpp b/src/V3LifePost.cpp index b3bd4234c..56121b68e 100644 --- a/src/V3LifePost.cpp +++ b/src/V3LifePost.cpp @@ -369,5 +369,5 @@ void V3LifePost::lifepostAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); // Mark redundant AssignPost { LifePostDlyVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("life_post", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("life_post", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp index f30bb9601..04639e6ad 100644 --- a/src/V3LinkCells.cpp +++ b/src/V3LinkCells.cpp @@ -167,7 +167,7 @@ private: iterateChildren(nodep); // Find levels in graph m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue); - if (dumpGraph()) m_graph.dumpDotFilePrefixed("linkcells"); + if (dumpGraphLevel()) m_graph.dumpDotFilePrefixed("linkcells"); m_graph.rank(); for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { if (const LinkCellsVertex* const vvertexp = dynamic_cast(itp)) { diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 498763fac..28861f3ca 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -166,7 +166,7 @@ public: // METHODS void dumpSelf(const string& nameComment = "linkdot", bool force = false) { - if (dump() >= 6 || force) { + if (dumpLevel() >= 6 || force) { const string filename = v3Global.debugFilename(nameComment) + ".txt"; const std::unique_ptr logp{V3File::new_ofstream(filename)}; if (logp->fail()) v3fatal("Can't write " << filename); @@ -193,7 +193,7 @@ public: } void preErrorDump() { static bool diddump = false; - if (!diddump && dumpTree()) { + if (!diddump && dumpTreeLevel()) { diddump = true; dumpSelf("linkdot-preerr", true); v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkdot-preerr.tree")); @@ -3555,18 +3555,18 @@ public: // Link class functions void V3LinkDot::linkDotGuts(AstNetlist* rootp, VLinkDotStep step) { - if (debug() >= 5 || dumpTree() >= 9) { + if (debug() >= 5 || dumpTreeLevel() >= 9) { v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot.tree")); } LinkDotState state(rootp, step); const LinkDotFindVisitor visitor{rootp, &state}; - if (debug() >= 5 || dumpTree() >= 9) { + if (debug() >= 5 || dumpTreeLevel() >= 9) { v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-find.tree")); } if (step == LDS_PRIMARY || step == LDS_PARAMED) { // Initial link stage, resolve parameters const LinkDotParamVisitor visitors{rootp, &state}; - if (debug() >= 5 || dumpTree() >= 9) { + if (debug() >= 5 || dumpTreeLevel() >= 9) { v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-param.tree")); } } else if (step == LDS_ARRAYED) { @@ -3575,7 +3575,7 @@ void V3LinkDot::linkDotGuts(AstNetlist* rootp, VLinkDotStep step) { // process AstScope's. This needs to be separate pass after whole hierarchy graph created. const LinkDotScopeVisitor visitors{rootp, &state}; v3Global.assertScoped(true); - if (debug() >= 5 || dumpTree() >= 9) { + if (debug() >= 5 || dumpTreeLevel() >= 9) { v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-scoped.tree")); } } else { @@ -3592,23 +3592,23 @@ void V3LinkDot::linkDotGuts(AstNetlist* rootp, VLinkDotStep step) { void V3LinkDot::linkDotPrimary(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); linkDotGuts(nodep, LDS_PRIMARY); - V3Global::dumpCheckGlobalTree("linkdot", 0, dumpTree() >= 6); + V3Global::dumpCheckGlobalTree("linkdot", 0, dumpTreeLevel() >= 6); } void V3LinkDot::linkDotParamed(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); linkDotGuts(nodep, LDS_PARAMED); - V3Global::dumpCheckGlobalTree("linkdotparam", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("linkdotparam", 0, dumpTreeLevel() >= 3); } void V3LinkDot::linkDotArrayed(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); linkDotGuts(nodep, LDS_ARRAYED); - V3Global::dumpCheckGlobalTree("linkdot", 0, dumpTree() >= 6); + V3Global::dumpCheckGlobalTree("linkdot", 0, dumpTreeLevel() >= 6); } void V3LinkDot::linkDotScope(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); linkDotGuts(nodep, LDS_SCOPED); - V3Global::dumpCheckGlobalTree("linkdot", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("linkdot", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp index e420d1276..8c71d6bb2 100644 --- a/src/V3LinkInc.cpp +++ b/src/V3LinkInc.cpp @@ -310,5 +310,5 @@ public: void V3LinkInc::linkIncrements(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { LinkIncVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("linkinc", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("linkinc", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp index 7ac37ade3..de4c1230e 100644 --- a/src/V3LinkJump.cpp +++ b/src/V3LinkJump.cpp @@ -351,5 +351,5 @@ public: void V3LinkJump::linkJump(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { LinkJumpVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("linkjump", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("linkjump", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp index ca0f07574..e8648fd6a 100644 --- a/src/V3LinkLValue.cpp +++ b/src/V3LinkLValue.cpp @@ -319,7 +319,7 @@ public: void V3LinkLValue::linkLValue(AstNetlist* nodep) { UINFO(4, __FUNCTION__ << ": " << endl); { LinkLValueVisitor{nodep, VAccess::NOCHANGE}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("linklvalue", 0, dumpTree() >= 6); + V3Global::dumpCheckGlobalTree("linklvalue", 0, dumpTreeLevel() >= 6); } void V3LinkLValue::linkLValueSet(AstNode* nodep) { // Called by later link functions when it is known a node needs diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index 11fffed29..609563b99 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -88,7 +88,7 @@ void V3LinkLevel::modSortByLevel() { UASSERT_OBJ(!v3Global.rootp()->modulesp(), v3Global.rootp(), "Unlink didn't work"); for (AstNodeModule* nodep : mods) v3Global.rootp()->addModulesp(nodep); UINFO(9, "modSortByLevel() done\n"); // Comment required for gcc4.6.3 / bug666 - V3Global::dumpCheckGlobalTree("cells", false, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("cells", false, dumpTreeLevel() >= 3); } void V3LinkLevel::timescaling(const ModVec& mods) { @@ -184,7 +184,7 @@ void V3LinkLevel::wrapTop(AstNetlist* rootp) { } } - V3Global::dumpCheckGlobalTree("wraptop", 0, dumpTree() >= 6); + V3Global::dumpCheckGlobalTree("wraptop", 0, dumpTreeLevel() >= 6); } void V3LinkLevel::wrapTopCell(AstNetlist* rootp) { diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 3b7d8eb0a..e1ed27590 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -775,5 +775,5 @@ public: void V3LinkParse::linkParse(AstNetlist* rootp) { UINFO(4, __FUNCTION__ << ": " << endl); { LinkParseVisitor{rootp}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("linkparse", 0, dumpTree() >= 6); + V3Global::dumpCheckGlobalTree("linkparse", 0, dumpTreeLevel() >= 6); } diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index df1872d19..3a917eb02 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -484,5 +484,5 @@ void V3LinkResolve::linkResolve(AstNetlist* rootp) { const LinkResolveVisitor visitor{rootp}; LinkBotupVisitor{rootp}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("linkresolve", 0, dumpTree() >= 6); + V3Global::dumpCheckGlobalTree("linkresolve", 0, dumpTreeLevel() >= 6); } diff --git a/src/V3Localize.cpp b/src/V3Localize.cpp index 1cf60339d..a6f30963c 100644 --- a/src/V3Localize.cpp +++ b/src/V3Localize.cpp @@ -223,5 +223,5 @@ public: void V3Localize::localizeAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { LocalizeVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("localize", 0, dumpTree() >= 6); + V3Global::dumpCheckGlobalTree("localize", 0, dumpTreeLevel() >= 6); } diff --git a/src/V3MergeCond.cpp b/src/V3MergeCond.cpp index d5756cc67..5f57e82c5 100644 --- a/src/V3MergeCond.cpp +++ b/src/V3MergeCond.cpp @@ -888,5 +888,5 @@ public: void V3MergeCond::mergeAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { MergeCondVisitor{nodep}; } - V3Global::dumpCheckGlobalTree("merge_cond", 0, dumpTree() >= 6); + V3Global::dumpCheckGlobalTree("merge_cond", 0, dumpTreeLevel() >= 6); } diff --git a/src/V3Name.cpp b/src/V3Name.cpp index bec3dd9cc..c6b9b6c68 100644 --- a/src/V3Name.cpp +++ b/src/V3Name.cpp @@ -150,5 +150,5 @@ public: void V3Name::nameAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { NameVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("name", 0, dumpTree() >= 6); + V3Global::dumpCheckGlobalTree("name", 0, dumpTreeLevel() >= 6); } diff --git a/src/V3Order.cpp b/src/V3Order.cpp index dc1905f97..13f1490a2 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -1416,7 +1416,7 @@ void OrderProcess::processMTasks() { void OrderProcess::process(bool multiThreaded) { // Dump data - if (dumpGraph()) m_graph.dumpDotFilePrefixed(m_tag + "_orderg_pre"); + if (dumpGraphLevel()) m_graph.dumpDotFilePrefixed(m_tag + "_orderg_pre"); // Break cycles. Each strongly connected subgraph (including cutable // edges) will have its own color, and corresponds to a loop in the @@ -1424,27 +1424,27 @@ void OrderProcess::process(bool multiThreaded) { // edges are actually still there, just with weight 0). UINFO(2, " Acyclic & Order...\n"); m_graph.acyclic(&V3GraphEdge::followAlwaysTrue); - if (dumpGraph()) m_graph.dumpDotFilePrefixed(m_tag + "_orderg_acyc"); + if (dumpGraphLevel()) m_graph.dumpDotFilePrefixed(m_tag + "_orderg_acyc"); // Assign ranks so we know what to follow // Then, sort vertices and edges by that ordering m_graph.order(); - if (dumpGraph()) m_graph.dumpDotFilePrefixed(m_tag + "_orderg_order"); + if (dumpGraphLevel()) m_graph.dumpDotFilePrefixed(m_tag + "_orderg_order"); // Assign logic vertices to new domains UINFO(2, " Domains...\n"); processDomains(); - if (dumpGraph()) m_graph.dumpDotFilePrefixed(m_tag + "_orderg_domain"); + if (dumpGraphLevel()) m_graph.dumpDotFilePrefixed(m_tag + "_orderg_domain"); - if (dump()) processEdgeReport(); + if (dumpLevel()) processEdgeReport(); if (!multiThreaded) { UINFO(2, " Construct Move Graph...\n"); processMoveBuildGraph(); // Different prefix (ordermv) as it's not the same graph - if (dumpGraph() >= 4) m_pomGraph.dumpDotFilePrefixed(m_tag + "_ordermv_start"); + if (dumpGraphLevel() >= 4) m_pomGraph.dumpDotFilePrefixed(m_tag + "_ordermv_start"); m_pomGraph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue); - if (dumpGraph() >= 4) m_pomGraph.dumpDotFilePrefixed(m_tag + "_ordermv_simpl"); + if (dumpGraphLevel() >= 4) m_pomGraph.dumpDotFilePrefixed(m_tag + "_ordermv_simpl"); UINFO(2, " Move...\n"); processMove(); @@ -1454,7 +1454,7 @@ void OrderProcess::process(bool multiThreaded) { } // Dump data - if (dumpGraph()) m_graph.dumpDotFilePrefixed(m_tag + "_orderg_done"); + if (dumpGraphLevel()) m_graph.dumpDotFilePrefixed(m_tag + "_orderg_done"); } //###################################################################### diff --git a/src/V3Param.cpp b/src/V3Param.cpp index e15d38834..fab0a077e 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -1399,5 +1399,5 @@ public: void V3Param::param(AstNetlist* rootp) { UINFO(2, __FUNCTION__ << ": " << endl); { ParamVisitor{rootp}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("param", 0, dumpTree() >= 6); + V3Global::dumpCheckGlobalTree("param", 0, dumpTreeLevel() >= 6); } diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index a10ffec1c..ed8b67a3a 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -2463,7 +2463,7 @@ public: } } - if (dumpGraph() >= 4) schedule.dumpDotFilePrefixedAlways(mtaskGraph, "schedule"); + if (dumpGraphLevel() >= 4) schedule.dumpDotFilePrefixedAlways(mtaskGraph, "schedule"); return schedule; } @@ -2528,7 +2528,7 @@ private: // V3Partition implementation void V3Partition::debugMTaskGraphStats(const V3Graph* graphp, const string& stage) { - if (!debug() && !dump() && !dumpGraph()) return; + if (!debug() && !dumpLevel() && !dumpGraphLevel()) return; UINFO(4, "\n"); UINFO(4, " Stats for " << stage << endl); @@ -2565,7 +2565,7 @@ void V3Partition::debugMTaskGraphStats(const V3Graph* graphp, const string& stag if (mtaskCount < 1000) { string filePrefix("ordermv_"); filePrefix += stage; - if (dumpGraph() >= 4) graphp->dumpDotFilePrefixedAlways(filePrefix); + if (dumpGraphLevel() >= 4) graphp->dumpDotFilePrefixedAlways(filePrefix); } // Look only at the cost of each mtask, neglect communication cost. @@ -2740,7 +2740,7 @@ void V3Partition::go(V3Graph* mtasksp) { // For debug: print out the longest critical path. This allows us to // verify that the costs look reasonable, that we aren't combining // nodes that should probably be split, etc. - if (dump() >= 3) LogicMTask::dumpCpFilePrefixed(mtasksp, "cp"); + if (dumpLevel() >= 3) LogicMTask::dumpCpFilePrefixed(mtasksp, "cp"); // Merge nodes that could present data hazards; see comment within. { diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 5cc257f7e..233b7bf1d 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -400,5 +400,5 @@ public: void V3Premit::premitAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { PremitVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("premit", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("premit", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 34c90bf9a..409f09740 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -368,7 +368,7 @@ void V3Randomize::randomizeNetlist(AstNetlist* nodep) { const RandomizeMarkVisitor markVisitor{nodep}; RandomizeVisitor{nodep}; } - V3Global::dumpCheckGlobalTree("randomize", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("randomize", 0, dumpTreeLevel() >= 3); } AstFunc* V3Randomize::newRandomizeFunc(AstClass* nodep) { diff --git a/src/V3Reloop.cpp b/src/V3Reloop.cpp index bd2d110c0..f71d8913b 100644 --- a/src/V3Reloop.cpp +++ b/src/V3Reloop.cpp @@ -273,5 +273,5 @@ public: void V3Reloop::reloopAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { ReloopVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("reloop", 0, dumpTree() >= 6); + V3Global::dumpCheckGlobalTree("reloop", 0, dumpTreeLevel() >= 6); } diff --git a/src/V3Sched.cpp b/src/V3Sched.cpp index f9ac9cc8e..fc26a192d 100644 --- a/src/V3Sched.cpp +++ b/src/V3Sched.cpp @@ -1225,7 +1225,7 @@ void schedule(AstNetlist* netlistp) { netlistp->dpiExportTriggerp(nullptr); - V3Global::dumpCheckGlobalTree("sched", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("sched", 0, dumpTreeLevel() >= 3); } } // namespace V3Sched diff --git a/src/V3SchedAcyclic.cpp b/src/V3SchedAcyclic.cpp index ac9bec353..20cfc4c7b 100644 --- a/src/V3SchedAcyclic.cpp +++ b/src/V3SchedAcyclic.cpp @@ -403,7 +403,7 @@ LogicByScope breakCycles(AstNetlist* netlistp, LogicByScope& combinationalLogic) if (graphp->empty()) return LogicByScope{}; // Dump for debug - if (dumpGraph() >= 6) graphp->dumpDotFilePrefixed("sched-comb-cycles"); + if (dumpGraphLevel() >= 6) graphp->dumpDotFilePrefixed("sched-comb-cycles"); // Make graph acyclic by cutting some edges. Note: This also colors strongly connected // components which reportCycles uses to print each SCCs separately. diff --git a/src/V3SchedPartition.cpp b/src/V3SchedPartition.cpp index 849ff16e7..1f3a0075b 100644 --- a/src/V3SchedPartition.cpp +++ b/src/V3SchedPartition.cpp @@ -341,11 +341,11 @@ LogicRegions partition(LogicByScope& clockedLogic, LogicByScope& combinationalLo // Build the graph const std::unique_ptr graphp = SchedGraphBuilder::build(clockedLogic, combinationalLogic, hybridLogic); - if (dumpGraph() >= 6) graphp->dumpDotFilePrefixed("sched"); + if (dumpGraphLevel() >= 6) graphp->dumpDotFilePrefixed("sched"); // Partition into Active and NBA regions colorActiveRegion(*(graphp.get())); - if (dumpGraph() >= 6) graphp->dumpDotFilePrefixed("sched-partitioned", true); + if (dumpGraphLevel() >= 6) graphp->dumpDotFilePrefixed("sched-partitioned", true); LogicRegions result; diff --git a/src/V3SchedReplicate.cpp b/src/V3SchedReplicate.cpp index 7db10cabf..961f0e29f 100644 --- a/src/V3SchedReplicate.cpp +++ b/src/V3SchedReplicate.cpp @@ -261,13 +261,13 @@ LogicReplicas replicateLogic(LogicRegions& logicRegionsRegions) { // Build the dataflow (dependency) graph const std::unique_ptr graphp = buildGraph(logicRegionsRegions); // Dump for debug - if (dumpGraph() >= 6) graphp->dumpDotFilePrefixed("sched-replicate"); + if (dumpGraphLevel() >= 6) graphp->dumpDotFilePrefixed("sched-replicate"); // Propagate driving region flags for (V3GraphVertex* vtxp = graphp->verticesBeginp(); vtxp; vtxp = vtxp->verticesNextp()) { propagateDrivingRegions(static_cast(vtxp)); } // Dump for debug - if (dumpGraph() >= 6) graphp->dumpDotFilePrefixed("sched-replicate-propagated"); + if (dumpGraphLevel() >= 6) graphp->dumpDotFilePrefixed("sched-replicate-propagated"); // Replicate the necessary logic return replicate(graphp.get()); } diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp index 0b3da2451..cc5eba6b9 100644 --- a/src/V3SchedTiming.cpp +++ b/src/V3SchedTiming.cpp @@ -388,7 +388,7 @@ void transformForks(AstNetlist* const netlistp) { ~ForkVisitor() override = default; }; ForkVisitor{netlistp}; - V3Global::dumpCheckGlobalTree("sched_forks", 0, dumpTree() >= 6); + V3Global::dumpCheckGlobalTree("sched_forks", 0, dumpTreeLevel() >= 6); } } // namespace V3Sched diff --git a/src/V3Scope.cpp b/src/V3Scope.cpp index 2dd807015..b5a31ea51 100644 --- a/src/V3Scope.cpp +++ b/src/V3Scope.cpp @@ -423,5 +423,5 @@ void V3Scope::scopeAll(AstNetlist* nodep) { const ScopeVisitor visitor{nodep}; ScopeCleanupVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("scope", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("scope", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp index 4c5a392cd..0546bff76 100644 --- a/src/V3Slice.cpp +++ b/src/V3Slice.cpp @@ -247,5 +247,5 @@ public: void V3Slice::sliceAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { SliceVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("slice", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("slice", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Split.cpp b/src/V3Split.cpp index 88cd94652..c937deb08 100644 --- a/src/V3Split.cpp +++ b/src/V3Split.cpp @@ -456,7 +456,7 @@ protected: UINFO(5, "ReorderBlock " << nodep << endl); m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue); - if (dumpGraph() >= 9) m_graph.dumpDotFilePrefixed("reorderg_nodup", false); + if (dumpGraphLevel() >= 9) m_graph.dumpDotFilePrefixed("reorderg_nodup", false); // Mark all the logic for this step // Vertex::m_user begin: true indicates logic for this step @@ -513,10 +513,10 @@ protected: // And a real ordering to get the statements into something reasonable // We don't care if there's cutable violations here... // Non-cutable violations should be impossible; as those edges are program-order - if (dumpGraph() >= 9) m_graph.dumpDotFilePrefixed("splitg_preo", false); + if (dumpGraphLevel() >= 9) m_graph.dumpDotFilePrefixed("splitg_preo", false); m_graph.acyclic(&SplitEdge::followCyclic); m_graph.rank(&SplitEdge::followCyclic); // Or order(), but that's more expensive - if (dumpGraph() >= 9) m_graph.dumpDotFilePrefixed("splitg_opt", false); + if (dumpGraphLevel() >= 9) m_graph.dumpDotFilePrefixed("splitg_opt", false); } void reorderBlock(AstNode* nodep) { @@ -942,14 +942,14 @@ protected: } } - if (dumpGraph() >= 9) m_graph.dumpDotFilePrefixed("splitg_nodup", false); + if (dumpGraphLevel() >= 9) m_graph.dumpDotFilePrefixed("splitg_nodup", false); // Weak coloring to determine what needs to remain grouped // in a single always. This follows all edges excluding: // - those we pruned above // - PostEdges, which are done later m_graph.weaklyConnected(&SplitEdge::followScoreboard); - if (dumpGraph() >= 9) m_graph.dumpDotFilePrefixed("splitg_colored", false); + if (dumpGraphLevel() >= 9) m_graph.dumpDotFilePrefixed("splitg_colored", false); } void visit(AstAlways* nodep) override { @@ -1003,10 +1003,10 @@ private: void V3Split::splitReorderAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { ReorderVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("reorder", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("reorder", 0, dumpTreeLevel() >= 3); } void V3Split::splitAlwaysAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { SplitVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("split", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("split", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3SplitAs.cpp b/src/V3SplitAs.cpp index b8c82f80d..f5faf37f2 100644 --- a/src/V3SplitAs.cpp +++ b/src/V3SplitAs.cpp @@ -192,5 +192,5 @@ public: void V3SplitAs::splitAsAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { SplitAsVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("splitas", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("splitas", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index 4550ee310..dc62dc823 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -1249,9 +1249,9 @@ void V3SplitVar::splitVariable(AstNetlist* nodep) { const SplitUnpackedVarVisitor visitor{nodep}; refs = visitor.getPackedVarRefs(); } - V3Global::dumpCheckGlobalTree("split_var", 0, dumpTree() >= 9); + V3Global::dumpCheckGlobalTree("split_var", 0, dumpTreeLevel() >= 9); { SplitPackedVarVisitor{nodep, refs}; } - V3Global::dumpCheckGlobalTree("split_var", 0, dumpTree() >= 9); + V3Global::dumpCheckGlobalTree("split_var", 0, dumpTreeLevel() >= 9); } bool V3SplitVar::canSplitVar(const AstVar* varp) { diff --git a/src/V3Subst.cpp b/src/V3Subst.cpp index 05dec8dba..a83a4cf93 100644 --- a/src/V3Subst.cpp +++ b/src/V3Subst.cpp @@ -384,5 +384,5 @@ public: void V3Subst::substituteAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { SubstVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("subst", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("subst", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3SymTable.h b/src/V3SymTable.h index 9d723a15e..482753a5c 100644 --- a/src/V3SymTable.h +++ b/src/V3SymTable.h @@ -314,7 +314,7 @@ public: } } void dumpFilePrefixed(const string& nameComment) { - if (dumpTree()) { + if (dumpTreeLevel()) { const string filename = v3Global.debugFilename(nameComment) + ".txt"; UINFO(2, "Dumping " << filename << endl); const std::unique_ptr logp{V3File::new_ofstream(filename)}; diff --git a/src/V3TSP.cpp b/src/V3TSP.cpp index 2ee4a27ca..f8961e5eb 100644 --- a/src/V3TSP.cpp +++ b/src/V3TSP.cpp @@ -396,7 +396,7 @@ public: } } void dumpGraphFilePrefixed(const string& nameComment) const { - if (::dump()) { + if (dumpLevel()) { const string filename = v3Global.debugFilename(nameComment) + ".txt"; const std::unique_ptr logp{V3File::new_ofstream(filename)}; if (logp->fail()) v3fatal("Can't write " << filename); @@ -406,7 +406,7 @@ public: void findEulerTour(std::vector* sortedOutp) { UASSERT(sortedOutp->empty(), "Output graph must start empty"); - if (::dumpGraph() >= 6) dumpDotFilePrefixed("findEulerTour"); + if (::dumpGraphLevel() >= 6) dumpDotFilePrefixed("findEulerTour"); std::unordered_set markedEdges; // Pick a start node Vertex* const start_vertexp = castVertexp(verticesBeginp()); @@ -464,12 +464,12 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) { // Create the minimum spanning tree Graph minGraph; graph.makeMinSpanningTree(&minGraph); - if (dumpGraph() >= 6) minGraph.dumpGraphFilePrefixed("minGraph"); + if (dumpGraphLevel() >= 6) minGraph.dumpGraphFilePrefixed("minGraph"); const std::vector oddDegree = minGraph.getOddDegreeKeys(); Graph matching; graph.perfectMatching(oddDegree, &matching); - if (dumpGraph() >= 6) matching.dumpGraphFilePrefixed("matching"); + if (dumpGraphLevel() >= 6) matching.dumpGraphFilePrefixed("matching"); // Adds edges to minGraph, the resulting graph will have even number of // edge counts at every vertex: @@ -670,12 +670,12 @@ void V3TSP::selfTestString() { Graph minGraph; graph.makeMinSpanningTree(&minGraph); - if (dumpGraph() >= 6) minGraph.dumpGraphFilePrefixed("minGraph"); + if (dumpGraphLevel() >= 6) minGraph.dumpGraphFilePrefixed("minGraph"); const std::vector oddDegree = minGraph.getOddDegreeKeys(); Graph matching; graph.perfectMatching(oddDegree, &matching); - if (dumpGraph() >= 6) matching.dumpGraphFilePrefixed("matching"); + if (dumpGraphLevel() >= 6) matching.dumpGraphFilePrefixed("matching"); minGraph.combineGraph(matching); diff --git a/src/V3Table.cpp b/src/V3Table.cpp index 56b754b04..26f37f970 100644 --- a/src/V3Table.cpp +++ b/src/V3Table.cpp @@ -431,5 +431,5 @@ void TableSimulateVisitor::varRefCb(AstVarRef* nodep) { void V3Table::tableAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { TableVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("table", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("table", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 94c45b035..e7ef1e0f7 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -283,7 +283,7 @@ public: iterate(nodep); // m_callGraph.removeRedundantEdgesSum(&TaskEdge::followAlwaysTrue); - if (dumpGraph()) m_callGraph.dumpDotFilePrefixed("task_call"); + if (dumpGraphLevel()) m_callGraph.dumpDotFilePrefixed("task_call"); } ~TaskStateVisitor() override = default; VL_UNCOPYABLE(TaskStateVisitor); @@ -1820,5 +1820,5 @@ void V3Task::taskAll(AstNetlist* nodep) { TaskStateVisitor visitors{nodep}; const TaskVisitor visitor{nodep, &visitors}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("task", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("task", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index a71ad592e..cc0232d54 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -792,7 +792,7 @@ public: explicit TimingVisitor(AstNetlist* nodep) : m_netlistp{nodep} { iterate(nodep); - if (dumpGraph() >= 6) m_depGraph.dumpDotFilePrefixed("timing_deps"); + if (dumpGraphLevel() >= 6) m_depGraph.dumpDotFilePrefixed("timing_deps"); } ~TimingVisitor() override = default; }; @@ -803,5 +803,5 @@ public: void V3Timing::timingAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); TimingVisitor{nodep}; - V3Global::dumpCheckGlobalTree("timing", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("timing", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index 44a12ba59..ced3fc9fd 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -734,11 +734,11 @@ private: detectDuplicates(); // Simplify & optimize the graph - if (dumpGraph() >= 6) m_graph.dumpDotFilePrefixed("trace_pre"); + if (dumpGraphLevel() >= 6) m_graph.dumpDotFilePrefixed("trace_pre"); graphSimplify(true); - if (dumpGraph() >= 6) m_graph.dumpDotFilePrefixed("trace_simplified"); + if (dumpGraphLevel() >= 6) m_graph.dumpDotFilePrefixed("trace_simplified"); graphOptimize(); - if (dumpGraph() >= 6) m_graph.dumpDotFilePrefixed("trace_optimized"); + if (dumpGraphLevel() >= 6) m_graph.dumpDotFilePrefixed("trace_optimized"); // Create the fine grained activity flags createActivityFlags(); @@ -924,5 +924,5 @@ public: void V3Trace::traceAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { TraceVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("trace", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("trace", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index 704d1d4b4..55bf02720 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -550,5 +550,5 @@ public: void V3TraceDecl::traceDeclAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { TraceDeclVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("tracedecl", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("tracedecl", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index 61720c2a4..ee0eeb271 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -294,7 +294,7 @@ public: for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { graphWalkRecurseBack(static_cast(itp), 0); } - if (dumpGraph() >= 9) m_graph.dumpDotFilePrefixed("tri_pos__" + nodep->name()); + if (dumpGraphLevel() >= 9) m_graph.dumpDotFilePrefixed("tri_pos__" + nodep->name()); } void associate(AstNode* fromp, AstNode* top) { new V3GraphEdge{&m_graph, makeVertex(fromp), makeVertex(top), 1}; @@ -1818,5 +1818,5 @@ public: void V3Tristate::tristateAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { TristateVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("tristate", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("tristate", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp index 2f0eabfb0..bf597e4e3 100644 --- a/src/V3Unknown.cpp +++ b/src/V3Unknown.cpp @@ -519,5 +519,5 @@ public: void V3Unknown::unknownAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { UnknownVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("unknown", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("unknown", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Unroll.cpp b/src/V3Unroll.cpp index 5e94255a3..6655001d1 100644 --- a/src/V3Unroll.cpp +++ b/src/V3Unroll.cpp @@ -518,5 +518,5 @@ void V3Unroll::unrollAll(AstNetlist* nodep) { UnrollStateful unroller; unroller.unrollAll(nodep); } // Destruct before checking - V3Global::dumpCheckGlobalTree("unroll", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("unroll", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3VariableOrder.cpp b/src/V3VariableOrder.cpp index 6f19fe113..e108e1605 100644 --- a/src/V3VariableOrder.cpp +++ b/src/V3VariableOrder.cpp @@ -207,5 +207,5 @@ void V3VariableOrder::orderAll() { modp = VN_AS(modp->nextp(), NodeModule)) { VariableOrder::processModule(modp); } - V3Global::dumpCheckGlobalTree("variableorder", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("variableorder", 0, dumpTreeLevel() >= 3); } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index d1583e1c4..50c7c9af7 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -7441,7 +7441,7 @@ void V3Width::width(AstNetlist* nodep) { WidthRemoveVisitor rvisitor; (void)rvisitor.mainAcceptEdit(nodep); } // Destruct before checking - V3Global::dumpCheckGlobalTree("width", 0, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("width", 0, dumpTreeLevel() >= 3); } //! Single node parameter propagation @@ -7477,5 +7477,5 @@ AstNode* V3Width::widthGenerateParamsEdit( void V3Width::widthCommit(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { WidthCommitVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("widthcommit", 0, dumpTree() >= 6); + V3Global::dumpCheckGlobalTree("widthcommit", 0, dumpTreeLevel() >= 6); } diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 6c6940b0c..79a38fce4 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -635,7 +635,7 @@ static void verilate(const string& argString) { } // Final steps - V3Global::dumpCheckGlobalTree("final", 990, dumpTree() >= 3); + V3Global::dumpCheckGlobalTree("final", 990, dumpTreeLevel() >= 3); V3Error::abortIfErrors(); From d693dc85e4cb046dcfa57f80561fd69190f01132 Mon Sep 17 00:00:00 2001 From: Jose Loyola Date: Thu, 4 May 2023 06:44:55 -0500 Subject: [PATCH 010/129] Add Github action to build and push docker images (#4163) --- .github/workflows/docker.yml | 84 ++++++++++++++++++++++++++++++++++++ README.rst | 2 + ci/docker/run/Dockerfile | 8 +++- docs/CONTRIBUTORS | 1 + 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/docker.yml diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 000000000..312b59474 --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,84 @@ +# Build and push verilator docker image when tags are pushed to the repository. +# The following secrets must be configured in the github repository: +# DOCKER_HUB_NAMESPACE: docker hub namespace. +# DOCKER_HUB_USER: user name for logging into docker hub +# DOCKER_HUB_ACCESS_TOKEN: docker hub access token. +name: Build Verilator Container + +on: + push: + tags: [ 'v*' ] + workflow_dispatch: + inputs: + manual_tag: + description: 'Git tag to use for image build' + required: true + type: string + add_latest_tag: + description: 'Tag workflow_dispatch docker image as "latest"' + required: true + type: boolean + default: false + +jobs: + + build: + + runs-on: ubuntu-22.04 + + strategy: + matrix: + contexts: + - "ci/docker/run:verilator" + # - "ci/docker/buildenv:verilator-buildenv" + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Extract context variables + run: | + echo "${{ matrix.contexts }}" | sed -r 's/(.*):.*/build_context=\1/' >> "$GITHUB_ENV" + echo "${{ matrix.contexts }}" | sed -r 's/.*:(.*)/image_name=\1/' >> "$GITHUB_ENV" + echo "git_tag=${GITHUB_REF#refs/*/}" >> "$GITHUB_ENV" + + - name: Use manual tag + if: ${{ inputs.manual_tag }} + run: | + echo "git_tag=${{ inputs.manual_tag }}" >> "$GITHUB_ENV" + + - name: Docker meta + id: docker_meta + uses: docker/metadata-action@v4 + with: + images: | + ${{ secrets.DOCKER_HUB_NAMESPACE }}/${{ env.image_name }} + tags: | + type=match,pattern=(v.*),group=1,enable=${{ startsWith(github.ref, 'refs/tags/v') }} + type=raw,value=${{ inputs.manual_tag }},enable=${{ inputs.manual_tag != '' }} + type=raw,value=latest,enable=${{ inputs.add_latest_tag == true }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + with: + buildkitd-flags: --debug + + - name: Login to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.DOCKER_HUB_USER }} + password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} + + - name: Build and Push to Docker + uses: docker/build-push-action@v4 + if: startsWith(github.ref, 'refs/tags/v') + with: + context: ${{ env.build_context }} + build-args: SOURCE_COMMIT=${{ env.git_tag }} + platforms: linux/arm64,linux/amd64 + push: ${{ !env.ACT && startsWith(github.ref, 'refs/tags/v') }} + tags: ${{ steps.docker_meta.outputs.tags }} + labels: ${{ steps.docker_meta.outputs.labels }} diff --git a/README.rst b/README.rst index 8e8e57bb8..e45c73fb9 100644 --- a/README.rst +++ b/README.rst @@ -13,6 +13,8 @@ :target: https://codecov.io/gh/verilator/verilator .. image:: https://github.com/verilator/verilator/workflows/build/badge.svg :target: https://github.com/verilator/verilator/actions?query=workflow%3Abuild +.. image:: https://img.shields.io/docker/pulls/verilator/verilator + :target: https://hub.docker.com/r/verilator/verilator Welcome to Verilator diff --git a/ci/docker/run/Dockerfile b/ci/docker/run/Dockerfile index fa5c98519..24128ccc9 100644 --- a/ci/docker/run/Dockerfile +++ b/ci/docker/run/Dockerfile @@ -19,10 +19,16 @@ RUN apt-get update \ ccache \ flex \ git \ + help2man \ + libfl2 \ libfl-dev \ libgoogle-perftools-dev \ + numactl \ perl \ + perl-doc \ python3 \ + zlib1g \ + zlib1g-dev \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* @@ -39,7 +45,7 @@ RUN git clone "${REPO}" verilator && \ git checkout "${SOURCE_COMMIT}" && \ autoconf && \ ./configure && \ - make -j "$(nproc)" && \ + make && \ make install && \ cd .. && \ rm -r verilator diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 85fcb791f..35cdff8d7 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -72,6 +72,7 @@ Joey Liu John Coiner John Demme Jonathan Drolet +Jose Loyola Joseph Nwabueze Josep Sans Josh Redford From 266dc7679a6cf952eaa3d39362027f4568b962c7 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Thu, 4 May 2023 15:09:01 +0200 Subject: [PATCH 011/129] Don't link AstRefDType if it has parameterized class ref (#4164) (#4170) --- src/V3LinkDot.cpp | 6 +++ test_regress/t/t_class_param_func_return.pl | 21 ++++++++++ test_regress/t/t_class_param_func_return.v | 45 +++++++++++++++++++++ test_regress/t/t_class_typedef.v | 27 ++++++++++++- 4 files changed, 97 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_class_param_func_return.pl create mode 100644 test_regress/t/t_class_param_func_return.v diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 28861f3ca..251022043 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -3424,6 +3424,12 @@ private: if (nodep->user3SetOnce()) return; if (AstNode* const cpackagep = nodep->classOrPackageOpp()) { if (AstClassOrPackageRef* const cpackagerefp = VN_CAST(cpackagep, ClassOrPackageRef)) { + if (cpackagerefp->paramsp()) { + // Unable to link before the instantiation of parameter classes. + // The class reference node has to be visited to properly link parameters. + iterate(cpackagep); + return; + } nodep->classOrPackagep(cpackagerefp->classOrPackagep()); if (!VN_IS(nodep->classOrPackagep(), Class) && !VN_IS(nodep->classOrPackagep(), Package)) { diff --git a/test_regress/t/t_class_param_func_return.pl b/test_regress/t/t_class_param_func_return.pl new file mode 100755 index 000000000..1aa73f80a --- /dev/null +++ b/test_regress/t/t_class_param_func_return.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 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_param_func_return.v b/test_regress/t/t_class_param_func_return.v new file mode 100644 index 000000000..9f3185d7c --- /dev/null +++ b/test_regress/t/t_class_param_func_return.v @@ -0,0 +1,45 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Foo #(type T=int); + typedef Foo default_type; + typedef Foo#(T) this_type; + + T x; + + function default_type get_default(); + default_type o = new; + return o; + endfunction + + function this_type get_this(); + this_type o = new; + return o; + endfunction +endclass + +module t (/*AUTOARG*/); + + Foo f_def1, f_def2; + Foo#(bit) f_bit1, f_bit2; + initial begin + f_def1 = new; + f_bit1 = new; + + f_def2 = f_def1.get_default(); + if ($bits(f_def2.x) != 32) $stop; + f_def2 = f_def1.get_this(); + if ($bits(f_def2.x) != 32) $stop; + + f_def2 = f_bit1.get_default(); + if ($bits(f_def2.x) != 32) $stop; + f_bit2 = f_bit1.get_this(); + if ($bits(f_bit2.x) != 1) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_typedef.v b/test_regress/t/t_class_typedef.v index ef6c86744..e5034a601 100644 --- a/test_regress/t/t_class_typedef.v +++ b/test_regress/t/t_class_typedef.v @@ -4,18 +4,41 @@ // any use, without warranty, 2020 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 -// Parse check class uvm_resource_types; typedef int rsrc_q_t; endclass + class uvm_resource_pool; uvm_resource_types::rsrc_q_t rtab [string]; +endclass - uvm_resource_types#(1,2,3)::rsrc_q_t rtab_paramed [string]; +virtual class C#(parameter type T = logic, parameter SIZE = 1); + typedef logic [SIZE-1:0] t_vector; + typedef T t_array [SIZE-1:0]; + typedef struct { + t_vector m0 [2*SIZE-1:0]; + t_array m1; + } t_struct; endclass module t (/*AUTOARG*/); initial begin + uvm_resource_pool pool = new; + typedef logic [7:0] t_t0; + C#(t_t0,3)::t_vector v0; + C#(t_t0,3)::t_array a0; + C#(bit,4)::t_struct s0; + + pool.rtab["a"] = 1; + if ($bits(pool.rtab["a"]) != 32) $stop; + + if ($bits(v0) != 3) $stop; + if ($size(a0) != 3) $stop; + if ($bits(a0[0]) != 8) $stop; + if ($size(s0.m0) != 8) $stop; + if ($size(s0.m1) != 4) $stop; + if ($bits(s0.m1[2]) != 1) $stop; + $write("*-* All Finished *-*\n"); $finish; end From 76c5875912af7fbb2e7292e3a43806936594d11f Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Thu, 4 May 2023 15:27:45 +0200 Subject: [PATCH 012/129] Fix marking overridden methods as coroutines (#4120) (#4169) This patch fixes two cases where methods in base classes were not being marked as coroutines, even though they were being overridden by coroutines. - One case is the class member cache not getting refreshed for searched classes. - The other is when the overriding methods are not declared as `virtual`. In that case, the `isVirtual()` getter on such a method returns false, which led to `V3Timing` skipping the step of searching for overridden methods. Signed-off-by: Krzysztof Bieganski --- src/V3Timing.cpp | 8 +- test_regress/t/t_timing_class.v | 14 +- test_regress/t/t_timing_debug2.out | 355 +++++++++++++++-------------- 3 files changed, 200 insertions(+), 177 deletions(-) diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index cc0232d54..8d520a413 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -433,12 +433,16 @@ private: m_procp = nodep; iterateChildren(nodep); DependencyVertex* const vxp = getDependencyVertex(nodep); - if (m_classp && nodep->isVirtual() - && !nodep->user1SetOnce()) { // If virtual (only visit once) + if (m_classp && !nodep->user1SetOnce()) { // If class method (possibly overrides another + // method); only visit once // Go over overridden functions m_classp->repairCache(); for (auto* cextp = m_classp->extendsp(); cextp; cextp = VN_AS(cextp->nextp(), ClassExtends)) { + if (!cextp->classp()->user1SetOnce()) { + // Repair class cache if it's not repaired already + cextp->classp()->repairCache(); + } if (auto* const overriddenp = VN_CAST(cextp->classp()->findMember(nodep->name()), CFunc)) { if (overriddenp->user2()) { // If suspendable diff --git a/test_regress/t/t_timing_class.v b/test_regress/t/t_timing_class.v index 263b2e44f..fbd4136c2 100644 --- a/test_regress/t/t_timing_class.v +++ b/test_regress/t/t_timing_class.v @@ -10,10 +10,18 @@ `define WRITE_VERBOSE(args) `endif +class BaseClass; + virtual task sleep; + endtask + + virtual task await; + endtask +endclass + module t; // ============================================= // EVENTS - class EventClass; + class EventClass extends BaseClass; event e; int trig_count; @@ -35,7 +43,7 @@ module t; endtask endclass - class WaitClass; + class WaitClass extends BaseClass; int a; int b; logic ok; @@ -53,7 +61,7 @@ module t; endtask endclass - class LocalWaitClass; + class LocalWaitClass extends BaseClass; logic ok; function new; diff --git a/test_regress/t/t_timing_debug2.out b/test_regress/t/t_timing_debug2.out index 3a4ac0ecb..fb5698b73 100644 --- a/test_regress/t/t_timing_debug2.out +++ b/test_regress/t/t_timing_debug2.out @@ -1,5 +1,7 @@ -V{t#,#}- Verilated::debug is on. Message prefix indicates {,}. -V{t#,#}+ Vt_timing_debug2___024root___ctor_var_reset +-V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass__Vclpkg___ctor_var_reset +-V{t#,#}+ Vt_timing_debug2___024unit___ctor_var_reset -V{t#,#}+ Vt_timing_debug2_t___ctor_var_reset -V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass__Vclpkg___ctor_var_reset -V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay10__Vclpkg___ctor_var_reset @@ -17,15 +19,21 @@ -V{t#,#}+ Initial -V{t#,#}+ Vt_timing_debug2___024root___eval_static -V{t#,#}+ Vt_timing_debug2_t___eval_static__TOP__t +-V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass::new +-V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass::_ctor_var_reset -V{t#,#}+ Vt_timing_debug2_t__03a__03aEventClass::new -V{t#,#}+ Vt_timing_debug2_t__03a__03aEventClass::_ctor_var_reset +-V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass::new +-V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass::_ctor_var_reset -V{t#,#}+ Vt_timing_debug2_t__03a__03aWaitClass::new -V{t#,#}+ Vt_timing_debug2_t__03a__03aWaitClass::_ctor_var_reset +-V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass::new +-V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass::_ctor_var_reset -V{t#,#}+ Vt_timing_debug2_t__03a__03aLocalWaitClass::new -V{t#,#}+ Vt_timing_debug2_t__03a__03aLocalWaitClass::_ctor_var_reset -V{t#,#}+ Vt_timing_debug2___024root___eval_initial -V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__0 --V{t#,#} Suspending process waiting for @([event] t.ec.e) at t/t_timing_class.v:80 +-V{t#,#} Suspending process waiting for @([event] t.ec.e) at t/t_timing_class.v:88 -V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__1 -V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__2 -V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__3 @@ -57,7 +65,7 @@ -V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::__Vfork_h########__0__0 -V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::__Vfork_h########__0__1 -V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::__Vfork_h########__0__2 --V{t#,#} Awaiting join of fork at: t/t_timing_class.v:209 +-V{t#,#} Awaiting join of fork at: t/t_timing_class.v:217 -V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__7 -V{t#,#}+ Vt_timing_debug2___024root___eval_settle -V{t#,#}MTask0 starting @@ -69,7 +77,7 @@ -V{t#,#} No triggers active -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#} Committing processes waiting for @([event] t.ec.e): --V{t#,#} - Process waiting at t/t_timing_class.v:80 +-V{t#,#} - Process waiting at t/t_timing_class.v:88 -V{t#,#}End-of-eval cleanup -V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step -V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions @@ -83,21 +91,21 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 10: Process waiting at t/t_timing_class.v:88 --V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:89 --V{t#,#} Awaiting time 10: Process waiting at t/t_timing_class.v:91 --V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:101 --V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:137 --V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:211 --V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:215 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:220 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:236 +-V{t#,#} Awaiting time 10: Process waiting at t/t_timing_class.v:96 +-V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:97 +-V{t#,#} Awaiting time 10: Process waiting at t/t_timing_class.v:99 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:109 +-V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:145 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:219 +-V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:223 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:228 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:244 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:236 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:244 -V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay10::__VnoInFunc_do_sth_else -V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay20::__VnoInFunc_do_delay --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:138 --V{t#,#} Process forked at t/t_timing_class.v:210 finished +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:146 +-V{t#,#} Process forked at t/t_timing_class.v:218 finished -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} No suspended processes waiting for dynamic trigger evaluation @@ -123,20 +131,20 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:88 --V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:89 --V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:91 --V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:101 --V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:137 --V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:211 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:215 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:220 +-V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:96 +-V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:97 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:99 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:109 +-V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:145 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:219 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:223 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:228 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:220 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:228 -V{t#,#}+ Vt_timing_debug2_t__03a__03aForkDelayClass::new -V{t#,#}+ Vt_timing_debug2_t__03a__03aForkDelayClass::_ctor_var_reset --V{t#,#} Process forked at t/t_timing_class.v:214 finished --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:215 +-V{t#,#} Process forked at t/t_timing_class.v:222 finished +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:223 -V{t#,#}+ Vt_timing_debug2_t__03a__03aEventClass::__VnoInFunc_wake -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act @@ -146,38 +154,38 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Ready processes waiting for @([event] t.ec.e): --V{t#,#} - Process waiting at t/t_timing_class.v:80 +-V{t#,#} - Process waiting at t/t_timing_class.v:88 -V{t#,#} Resuming processes waiting for @([event] t.ec.e) --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:80 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:88 -V{t#,#}+ Vt_timing_debug2_t__03a__03aEventClass::__VnoInFunc_sleep --V{t#,#} Suspending process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:29 +-V{t#,#} Suspending process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:29 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:29 --V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:29 awaiting the post update step +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting the post update step -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} No triggers active -V{t#,#} Doing post updates for processes: --V{t#,#} - Process waiting at t/t_timing_class.v:29 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:29 --V{t#,#} Suspending process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:29 +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Suspending process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___eval_nba -V{t#,#}+ Vt_timing_debug2_t___nba_sequent__TOP__t__0 -V{t#,#}+ Vt_timing_debug2_t__03a__03aEventClass::__VnoInFunc_inc_trig_count -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:29 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:29 --V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:29 awaiting the post update step +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting the post update step -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} No triggers active -V{t#,#} Doing post updates for processes: --V{t#,#} - Process waiting at t/t_timing_class.v:29 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:29 --V{t#,#} Suspending process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:29 +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Suspending process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}End-of-eval cleanup -V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step @@ -187,55 +195,55 @@ -V{t#,#}+ Vt_timing_debug2___024root___eval -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:29 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:29 --V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:29 awaiting the post update step +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting the post update step -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime()) -V{t#,#} Doing post updates for processes: --V{t#,#} - Process waiting at t/t_timing_class.v:29 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:29 --V{t#,#} Suspending process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:29 +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Suspending process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:88 --V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:89 --V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:91 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:101 --V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:137 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:211 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:96 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:97 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:99 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:109 +-V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:145 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:219 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:211 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:219 -V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay20::__VnoInFunc_do_sth_else -V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay40::__VnoInFunc_do_delay --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:139 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:147 -V{t#,#}+ Vt_timing_debug2_t__03a__03aForkDelayClass::__VnoInFunc_do_delay -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:29 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:29 --V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:29 awaiting the post update step +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting the post update step -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} No triggers active -V{t#,#} Doing post updates for processes: --V{t#,#} - Process waiting at t/t_timing_class.v:29 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:29 --V{t#,#} Suspending process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:29 +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Suspending process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___eval_nba -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:29 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:29 --V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:29 awaiting the post update step +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting the post update step -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} No triggers active -V{t#,#} Doing post updates for processes: --V{t#,#} - Process waiting at t/t_timing_class.v:29 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:29 --V{t#,#} Suspending process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:29 +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Suspending process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}End-of-eval cleanup -V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step @@ -245,38 +253,38 @@ -V{t#,#}+ Vt_timing_debug2___024root___eval -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:29 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:29 --V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:29 awaiting the post update step +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting the post update step -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime()) -V{t#,#} Doing post updates for processes: --V{t#,#} - Process waiting at t/t_timing_class.v:29 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:29 --V{t#,#} Suspending process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:29 +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Suspending process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:88 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:89 --V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:91 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:101 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:137 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:202 +-V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:96 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:97 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:99 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:109 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:145 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:210 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:202 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:210 -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:29 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:29 --V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:29 awaiting the post update step +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting the post update step -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 0 is active: @([event] t.ec.e) -V{t#,#} Doing post updates for processes: --V{t#,#} - Process waiting at t/t_timing_class.v:29 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:29 --V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:29 awaiting resumption +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting resumption -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} No ready processes waiting for @([event] t.ec.e) @@ -289,17 +297,17 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Resuming processes: --V{t#,#} - Process waiting at t/t_timing_class.v:29 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:29 +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 -V{t#,#}+ Vt_timing_debug2_t__03a__03aEventClass::__VnoInFunc_inc_trig_count -V{t#,#}+ Vt_timing_debug2_t__03a__03aWaitClass::__VnoInFunc_await --V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:50 +-V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:50 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:50 --V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:50 +-V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 +-V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} No triggers active -V{t#,#}+ Vt_timing_debug2___024root___timing_commit @@ -308,9 +316,9 @@ -V{t#,#}+ Vt_timing_debug2_t__03a__03aEventClass::__VnoInFunc_inc_trig_count -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:50 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:50 --V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:50 +-V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 +-V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} No triggers active -V{t#,#}+ Vt_timing_debug2___024root___timing_commit @@ -322,36 +330,36 @@ -V{t#,#}+ Vt_timing_debug2___024root___eval -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:50 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:50 --V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:50 +-V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 +-V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime()) -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:88 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:89 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:91 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:101 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:137 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:96 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:97 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:99 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:109 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:145 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:137 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:145 -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:50 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:50 --V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:50 +-V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 +-V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} No triggers active -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___eval_nba -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:50 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:50 --V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:50 +-V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 +-V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} No triggers active -V{t#,#}+ Vt_timing_debug2___024root___timing_commit @@ -363,54 +371,54 @@ -V{t#,#}+ Vt_timing_debug2___024root___eval -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:50 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:50 --V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:50 +-V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 +-V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime()) -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 60: Process waiting at t/t_timing_class.v:88 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:89 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:91 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:101 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:92 +-V{t#,#} Awaiting time 60: Process waiting at t/t_timing_class.v:96 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:97 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:99 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:109 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:100 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:92 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:100 -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:50 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:50 --V{t#,#} Process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:50 awaiting resumption +-V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 +-V{t#,#} Process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 awaiting resumption -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 2 is active: @([true] __VdynSched.evaluate()) -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Resuming processes: --V{t#,#} - Process waiting at t/t_timing_class.v:50 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:50 +-V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 -V{t#,#}+ Vt_timing_debug2_t__03a__03aLocalWaitClass::__VnoInFunc_await -V{t#,#}+ Vt_timing_debug2_t__03a__03aLocalWaitClass::__Vfork_h########__0__0 --V{t#,#} Suspending process waiting for @([true] ((32'sh2a == t::LocalWaitClass.a) | (32'sh64 != t::LocalWaitClass.b))) at t/t_timing_class.v:67 +-V{t#,#} Suspending process waiting for @([true] ((32'sh2a == t::LocalWaitClass.a) | (32'sh64 != t::LocalWaitClass.b))) at t/t_timing_class.v:75 -V{t#,#}+ Vt_timing_debug2_t__03a__03aLocalWaitClass::__Vfork_h########__0__1 --V{t#,#} Awaiting join of fork at: t/t_timing_class.v:66 +-V{t#,#} Awaiting join of fork at: t/t_timing_class.v:74 -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:67 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:67 --V{t#,#} Suspending process waiting for @([true] ((32'sh2a == t::LocalWaitClass.a) | (32'sh64 != t::LocalWaitClass.b))) at t/t_timing_class.v:67 +-V{t#,#} - Process waiting at t/t_timing_class.v:75 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:75 +-V{t#,#} Suspending process waiting for @([true] ((32'sh2a == t::LocalWaitClass.a) | (32'sh64 != t::LocalWaitClass.b))) at t/t_timing_class.v:75 -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} No triggers active -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___eval_nba -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:67 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:67 --V{t#,#} Suspending process waiting for @([true] ((32'sh2a == t::LocalWaitClass.a) | (32'sh64 != t::LocalWaitClass.b))) at t/t_timing_class.v:67 +-V{t#,#} - Process waiting at t/t_timing_class.v:75 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:75 +-V{t#,#} Suspending process waiting for @([true] ((32'sh2a == t::LocalWaitClass.a) | (32'sh64 != t::LocalWaitClass.b))) at t/t_timing_class.v:75 -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} No triggers active -V{t#,#}+ Vt_timing_debug2___024root___timing_commit @@ -422,45 +430,45 @@ -V{t#,#}+ Vt_timing_debug2___024root___eval -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:67 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:67 --V{t#,#} Suspending process waiting for @([true] ((32'sh2a == t::LocalWaitClass.a) | (32'sh64 != t::LocalWaitClass.b))) at t/t_timing_class.v:67 +-V{t#,#} - Process waiting at t/t_timing_class.v:75 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:75 +-V{t#,#} Suspending process waiting for @([true] ((32'sh2a == t::LocalWaitClass.a) | (32'sh64 != t::LocalWaitClass.b))) at t/t_timing_class.v:75 -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime()) -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:88 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:89 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:91 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:101 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:68 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:96 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:97 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:99 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:109 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:76 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:68 --V{t#,#} Process forked at t/t_timing_class.v:219 finished +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:76 +-V{t#,#} Process forked at t/t_timing_class.v:227 finished -V{t#,#} Resuming: Process waiting at (null):0 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:101 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:109 -V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay40::__VnoInFunc_do_sth_else -V{t#,#}+ Vt_timing_debug2_t__03a__03aNoDelay::__VnoInFunc_do_delay -V{t#,#}+ Vt_timing_debug2_t__03a__03aNoDelay::__VnoInFunc_do_sth_else -V{t#,#}+ Vt_timing_debug2_t____Vfork_h########__0__0 -V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass::__VnoInFunc_do_assign --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:154 --V{t#,#} Process forked at t/t_timing_class.v:68 finished +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:162 +-V{t#,#} Process forked at t/t_timing_class.v:76 finished -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: --V{t#,#} - Process waiting at t/t_timing_class.v:67 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:67 --V{t#,#} Process waiting for @([true] ((32'sh2a == t::LocalWaitClass.a) | (32'sh64 != t::LocalWaitClass.b))) at t/t_timing_class.v:67 awaiting resumption +-V{t#,#} - Process waiting at t/t_timing_class.v:75 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:75 +-V{t#,#} Process waiting for @([true] ((32'sh2a == t::LocalWaitClass.a) | (32'sh64 != t::LocalWaitClass.b))) at t/t_timing_class.v:75 awaiting resumption -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 2 is active: @([true] __VdynSched.evaluate()) -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Resuming processes: --V{t#,#} - Process waiting at t/t_timing_class.v:67 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:67 --V{t#,#} Process forked at t/t_timing_class.v:67 finished +-V{t#,#} - Process waiting at t/t_timing_class.v:75 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:75 +-V{t#,#} Process forked at t/t_timing_class.v:75 finished -V{t#,#} Resuming: Process waiting at (null):0 -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act @@ -489,12 +497,12 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 75: Process waiting at t/t_timing_class.v:88 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:89 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:91 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:188 +-V{t#,#} Awaiting time 75: Process waiting at t/t_timing_class.v:96 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:97 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:99 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:196 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:188 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:196 -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} No suspended processes waiting for dynamic trigger evaluation @@ -520,12 +528,12 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:88 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:89 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:91 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:96 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:97 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:99 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:91 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:89 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:99 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:97 -V{t#,#}+ Vt_timing_debug2_t____Vfork_h########__0__0 -V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass::__VnoInFunc_do_assign -V{t#,#}+ Vt_timing_debug2___024root___eval_act @@ -553,11 +561,11 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 85: Process waiting at t/t_timing_class.v:88 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:154 --V{t#,#} Awaiting time 90: Process waiting at t/t_timing_class.v:194 +-V{t#,#} Awaiting time 85: Process waiting at t/t_timing_class.v:96 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:162 +-V{t#,#} Awaiting time 90: Process waiting at t/t_timing_class.v:202 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:194 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:202 -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} No suspended processes waiting for dynamic trigger evaluation @@ -583,11 +591,11 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 90: Process waiting at t/t_timing_class.v:88 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:154 --V{t#,#} Awaiting time 100: Process waiting at t/t_timing_class.v:195 +-V{t#,#} Awaiting time 90: Process waiting at t/t_timing_class.v:96 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:162 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_class.v:203 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:195 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:203 -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} No suspended processes waiting for dynamic trigger evaluation @@ -614,10 +622,10 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 100: Process waiting at t/t_timing_class.v:88 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:154 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_class.v:96 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:162 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:154 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:162 *-* All Finished *-* -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act @@ -642,5 +650,8 @@ -V{t#,#}+ Vt_timing_debug2_t__03a__03aNoDelay::~ -V{t#,#}+ Vt_timing_debug2_t__03a__03aDelayClass::~ -V{t#,#}+ Vt_timing_debug2_t__03a__03aLocalWaitClass::~ +-V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass::~ -V{t#,#}+ Vt_timing_debug2_t__03a__03aWaitClass::~ +-V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass::~ -V{t#,#}+ Vt_timing_debug2_t__03a__03aEventClass::~ +-V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass::~ From 832b17d4d295965f04a3bd848e5f7e1428284219 Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Thu, 4 May 2023 20:00:30 +0200 Subject: [PATCH 013/129] clang_check_attributes: fix mt-safe checks for global objects in constructor context (#4171) --- nodist/clang_check_attributes | 81 +++++++++++++++++++----- test_regress/t/t_dist_attributes_bad.h | 27 ++++++++ test_regress/t/t_dist_attributes_bad.out | 24 ++++--- 3 files changed, 107 insertions(+), 25 deletions(-) diff --git a/nodist/clang_check_attributes b/nodist/clang_check_attributes index 36c5be05f..50409714a 100755 --- a/nodist/clang_check_attributes +++ b/nodist/clang_check_attributes @@ -33,6 +33,26 @@ def fully_qualified_name(node): return [node.displayname] if node.displayname else [] +# Returns True, if `class_node` contains node +# that matches `member` spelling +def check_class_member_exists(class_node, member): + for child in class_node.get_children(): + if member.spelling == child.spelling: + return True + return False + + +# Returns Base class (if found) of `class_node` +# that is of type `base_type` +def get_base_class(class_node, base_type): + for child in class_node.get_children(): + if child.kind is CursorKind.CXX_BASE_SPECIFIER: + base_class = child.type + if base_type.spelling == base_class.spelling: + return base_class + return None + + @dataclass class VlAnnotations: mt_start: bool = False @@ -251,7 +271,10 @@ class CallAnnotationsValidator: self._call_location: Optional[FunctionInfo] = None self._caller: Optional[FunctionInfo] = None self._level: int = 0 - self._constructor_context: int = 0 + self._constructor_context: list[clang.cindex.Cursor] = [] + + def is_constructor_context(self): + return len(self._constructor_context) > 0 def compile_and_analyze_file(self, source_file: str, compiler_args: list[str], @@ -341,7 +364,7 @@ class CallAnnotationsValidator: return None refn = find_object_ref(node) - if self._constructor_context and not refn: + if self.is_constructor_context() and not refn: # we are in constructor and no object reference means # we are calling local method. It is MT safe # only if this method is also only calling local methods or @@ -353,20 +376,44 @@ class CallAnnotationsValidator: elif refn and refn.kind == CursorKind.MEMBER_REF_EXPR and refn.referenced: refn = refn.referenced refna = VlAnnotations.from_nodes_list(refn.get_children()) - if refna.guarded or self._constructor_context: + if refna.guarded: is_mt_safe = True + if self.is_constructor_context() and refn.semantic_parent: + # we are in constructor, so calling local members is MT_SAFE, + # make sure object that we are calling is local to the constructor + constructor_class = self._constructor_context[ + -1].semantic_parent + if refn.semantic_parent.spelling == constructor_class.spelling: + if check_class_member_exists(constructor_class, refn): + is_mt_safe = True + else: + # check if this class inherits from some base class + base_class = get_base_class(constructor_class, + refn.semantic_parent) + if base_class: + if check_class_member_exists( + base_class.get_declaration(), refn): + is_mt_safe = True # variable elif refn and refn.kind == CursorKind.DECL_REF_EXPR and refn.referenced: - # This is probably a local or an argument. - # Calling methods on local pointers or references is MT-safe, - # but on argument pointers or references is not. - if "*" not in refn.type.spelling and "&" not in refn.type.spelling: - is_mt_safe = True - # local variable - if refn.referenced.kind == CursorKind.VAR_DECL: - is_mt_safe = True + if refn.get_definition(): + if refn.referenced.semantic_parent: + if refn.referenced.semantic_parent.kind in [ + CursorKind.FUNCTION_DECL, CursorKind.CXX_METHOD + ]: + # This is a local or an argument. + # Calling methods on local pointers or references is MT-safe, + # but on argument pointers or references is not. + if "*" not in refn.type.spelling and "&" not in refn.type.spelling: + is_mt_safe = True + # local variable + if refn.referenced.kind == CursorKind.VAR_DECL: + is_mt_safe = True + else: + # Global variable in different translation unit, unsafe + pass elif refn and refn.kind == CursorKind.CALL_EXPR: - if self._constructor_context: + if self.is_constructor_context(): # call to local function from constructor context # safe if this function also calling local methods or # MT-safe methods @@ -442,18 +489,18 @@ class CallAnnotationsValidator: # Constructors are OK in MT-safe context # only if they call local methods or MT-safe functions. - if ctx.is_mt_safe_context() or self._constructor_context: - self._constructor_context += 1 + if ctx.is_mt_safe_context() or self.is_constructor_context(): + self._constructor_context.append(refd) self.iterate_children(refd.get_children(), self.dispatch_node_inside_definition) - self._constructor_context -= 1 + self._constructor_context.pop() # stable tree context if ctx.is_stabe_tree_context(): - self._constructor_context += 1 + self._constructor_context.append(refd) self.iterate_children(refd.get_children(), self.dispatch_node_inside_definition) - self._constructor_context -= 1 + self._constructor_context.pop() # pure context if ctx.is_pure_context(): diff --git a/test_regress/t/t_dist_attributes_bad.h b/test_regress/t/t_dist_attributes_bad.h index 5b9ed95b7..7473d57ff 100644 --- a/test_regress/t/t_dist_attributes_bad.h +++ b/test_regress/t/t_dist_attributes_bad.h @@ -345,6 +345,27 @@ class ConstructorCallsLocalCallsClassGlobal { public: ConstructorCallsLocalCallsClassGlobal() { local_function(); } }; +class DummyClass2 { +public: + void dummy_function2() {} +}; +class DummyClass { +public: + DummyClass2 d; + void dummy_function() {} +}; +DummyClass dummyGlobalVar; +class ConstructorCallsGlobalObject { + +public: + ConstructorCallsGlobalObject() { dummyGlobalVar.dummy_function(); } +}; + +class ConstructorCallsGlobalObjectMember { + +public: + ConstructorCallsGlobalObjectMember() { dummyGlobalVar.d.dummy_function2(); } +}; class TestClassConstructor { void safe_function_unsafe_constructor_bad() VL_MT_SAFE { @@ -381,6 +402,12 @@ class TestClassConstructor { void safe_function_calls_constructor_local_calls_class_global_bad() VL_MT_SAFE { ConstructorCallsLocalCallsClassGlobal f{}; } + void safe_function_calls_constructor_global_object_bad() VL_MT_STABLE { + ConstructorCallsGlobalObject f{}; + } + void safe_function_calls_constructor_global_object_member_bad() VL_MT_STABLE { + ConstructorCallsGlobalObjectMember f{}; + } }; #endif // T_DIST_ATTRIBUTES_BAD_H_ diff --git a/test_regress/t/t_dist_attributes_bad.out b/test_regress/t/t_dist_attributes_bad.out index fea14b7b0..f302da187 100644 --- a/test_regress/t/t_dist_attributes_bad.out +++ b/test_regress/t/t_dist_attributes_bad.out @@ -724,32 +724,40 @@ t/t_dist_attributes_bad.cpp:75: [release] TestClass t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &) [declaration] t/t_dist_attributes_bad.cpp:75: [requires] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &) +%Error: "TestClassConstructor::safe_function_calls_constructor_global_object_bad()" is stable_tree but calls non-stable_tree or non-mtsafe +t/t_dist_attributes_bad.h:405: [stable_tree] TestClassConstructor::safe_function_calls_constructor_global_object_bad() +t/t_dist_attributes_bad.h:355: [] DummyClass::dummy_function() + +%Error: "TestClassConstructor::safe_function_calls_constructor_global_object_member_bad()" is stable_tree but calls non-stable_tree or non-mtsafe +t/t_dist_attributes_bad.h:408: [stable_tree] TestClassConstructor::safe_function_calls_constructor_global_object_member_bad() +t/t_dist_attributes_bad.h:350: [] DummyClass2::dummy_function2() + %Error: "TestClassConstructor::safe_function_calls_constructor_local_calls_class_global_bad()" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.h:381: [mt_safe] TestClassConstructor::safe_function_calls_constructor_local_calls_class_global_bad() +t/t_dist_attributes_bad.h:402: [mt_safe] TestClassConstructor::safe_function_calls_constructor_local_calls_class_global_bad() t/t_dist_attributes_bad.h:280: [] StaticClass::static_class_function() %Error: "TestClassConstructor::safe_function_calls_constructor_local_calls_global_bad()" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.h:378: [mt_safe] TestClassConstructor::safe_function_calls_constructor_local_calls_global_bad() +t/t_dist_attributes_bad.h:399: [mt_safe] TestClassConstructor::safe_function_calls_constructor_local_calls_global_bad() t/t_dist_attributes_bad.h:276: [] static_function() %Error: "TestClassConstructor::safe_function_calls_constructor_with_unsafepointer_bad()" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.h:370: [mt_safe] TestClassConstructor::safe_function_calls_constructor_with_unsafepointer_bad() +t/t_dist_attributes_bad.h:391: [mt_safe] TestClassConstructor::safe_function_calls_constructor_with_unsafepointer_bad() t/t_dist_attributes_bad.h:311: [mt_unsafe] UnsafeFunction::unsafe_function() %Error: "TestClassConstructor::safe_function_calls_constructor_with_unsafereference_bad()" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.h:374: [mt_safe] TestClassConstructor::safe_function_calls_constructor_with_unsafereference_bad() +t/t_dist_attributes_bad.h:395: [mt_safe] TestClassConstructor::safe_function_calls_constructor_with_unsafereference_bad() t/t_dist_attributes_bad.h:311: [mt_unsafe] UnsafeFunction::unsafe_function() %Error: "TestClassConstructor::safe_function_local_function_global_bad()" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.h:356: [mt_safe] TestClassConstructor::safe_function_local_function_global_bad() +t/t_dist_attributes_bad.h:377: [mt_safe] TestClassConstructor::safe_function_local_function_global_bad() t/t_dist_attributes_bad.h:276: [] static_function() %Error: "TestClassConstructor::safe_function_static_constructor_bad()" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.h:353: [mt_safe] TestClassConstructor::safe_function_static_constructor_bad() +t/t_dist_attributes_bad.h:374: [mt_safe] TestClassConstructor::safe_function_static_constructor_bad() t/t_dist_attributes_bad.h:276: [] static_function() %Error: "TestClassConstructor::safe_function_unsafe_constructor_bad()" is mtsafe but calls non-mtsafe function(s) -t/t_dist_attributes_bad.h:350: [mt_safe] TestClassConstructor::safe_function_unsafe_constructor_bad() +t/t_dist_attributes_bad.h:371: [mt_safe] TestClassConstructor::safe_function_unsafe_constructor_bad() t/t_dist_attributes_bad.h:285: [mt_unsafe] ConstructorCallsUnsafeLocalFunction::unsafe_function() %Error: "ifh_test_caller_func_VL_MT_SAFE(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) @@ -1185,4 +1193,4 @@ t/t_dist_attributes_bad.cpp:60: [mt_unsafe_one] sfc_VL_ t/t_dist_attributes_bad.cpp:60: [release] sfc_VL_RELEASE(VerilatedMutex &) t/t_dist_attributes_bad.cpp:60: [release] sfc_VL_RELEASE_SHARED(VerilatedMutex &) t/t_dist_attributes_bad.cpp:60: [requires] sfc_VL_REQUIRES(VerilatedMutex &) -Number of functions reported unsafe: 224 +Number of functions reported unsafe: 226 From 3bb4e34044d7fde17bea675cdbc1e6e26a1f0723 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 4 May 2023 19:04:38 -0400 Subject: [PATCH 014/129] Commentary --- README.rst | 13 ++++++------- docs/guide/faq.rst | 4 ++-- docs/spelling.txt | 1 + 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.rst b/README.rst index e45c73fb9..1b8cc8435 100644 --- a/README.rst +++ b/README.rst @@ -59,17 +59,16 @@ files, the "Verilated" code. 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. +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 a closed-source Verilog simulator, needs 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. +designs, Verilator is the tool for you. Performance @@ -85,11 +84,11 @@ as `Icarus Verilog`_. Another 2-10x speedup might be gained from 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, +closed-source Verilog simulators (e.g., Carbon Design Systems Carbonator, 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. +simulation cycles/dollar. Installation & Documentation diff --git a/docs/guide/faq.rst b/docs/guide/faq.rst index 4b161bc2d..621b0e3b5 100644 --- a/docs/guide/faq.rst +++ b/docs/guide/faq.rst @@ -356,8 +356,8 @@ Why do I get "undefined reference to \`VL_RAND_RESET_I' or \`Verilated::...'"? You need to link your compiled Verilated code against the :code:`verilated.cpp` file found in the include directory of the Verilator kit. This is one target in the ``$(VK_GLOBAL_OBJS)`` make variable, which -should be part of your Makefile's link rule. If you use :vlopt:`--exe`, -this is done for you. +should be part of your Makefile's link rule. If you use :vlopt:`--exe` or +:vlopt:`--binary`, this is done for you. Is the PLI supported? diff --git a/docs/spelling.txt b/docs/spelling.txt index f4660bed4..85817af63 100644 --- a/docs/spelling.txt +++ b/docs/spelling.txt @@ -602,6 +602,7 @@ genvar genvars getenv getline +ggdb gmake gmon gotFinish From 61e1483b74da8511ccc4eef4d9b1c7de2ef680a0 Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Fri, 5 May 2023 14:36:20 +0200 Subject: [PATCH 015/129] Add multi-threaded Verilating at emit stage (#3608) --- src/V3EmitCImp.cpp | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index 679f392ce..5574613d6 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -22,6 +22,7 @@ #include "V3EmitCFunc.h" #include "V3Global.h" #include "V3String.h" +#include "V3ThreadPool.h" #include "V3UniqueNames.h" #include @@ -145,7 +146,7 @@ class EmitCGatherDependencies final : VNVisitorConst { } public: - static const std::set gather(AstCFunc* cfuncp) { + static const std::set gather(AstCFunc* cfuncp) VL_MT_STABLE { const EmitCGatherDependencies visitor{cfuncp}; return std::move(visitor.m_dependencies); } @@ -564,7 +565,8 @@ class EmitCImp final : EmitCFunc { ~EmitCImp() override = default; public: - static void main(const AstNodeModule* modp, bool slow, std::deque& cfilesr) { + static void main(const AstNodeModule* modp, bool slow, + std::deque& cfilesr) VL_MT_STABLE { EmitCImp{modp, slow, cfilesr}; } }; @@ -908,7 +910,7 @@ class EmitCTrace final : EmitCFunc { ~EmitCTrace() override = default; public: - static void main(AstNodeModule* modp, bool slow, std::deque& cfilesr) { + static void main(AstNodeModule* modp, bool slow, std::deque& cfilesr) VL_MT_STABLE { EmitCTrace{modp, slow, cfilesr}; } }; @@ -921,24 +923,37 @@ void V3EmitC::emitcImp() { // Make parent module pointers available. const EmitCParentModule emitCParentModule; std::list> cfiles; + std::list> futures; // 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); cfiles.emplace_back(); - EmitCImp::main(modp, /* slow: */ true, cfiles.back()); + auto& slowCfilesr = cfiles.back(); + futures.push_back(V3ThreadPool::s().enqueue( + [modp, &slowCfilesr]() { EmitCImp::main(modp, /* slow: */ true, slowCfilesr); })); cfiles.emplace_back(); - EmitCImp::main(modp, /* slow: */ false, cfiles.back()); + auto& fastCfilesr = cfiles.back(); + futures.push_back(V3ThreadPool::s().enqueue( + [modp, &fastCfilesr]() { EmitCImp::main(modp, /* slow: */ false, fastCfilesr); })); } // Emit trace routines (currently they can only exist in the top module) if (v3Global.opt.trace() && !v3Global.opt.lintOnly()) { cfiles.emplace_back(); - EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ true, cfiles.back()); + auto& slowCfilesr = cfiles.back(); + futures.push_back(V3ThreadPool::s().enqueue([&slowCfilesr]() { + EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ true, slowCfilesr); + })); cfiles.emplace_back(); - EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ false, cfiles.back()); + auto& fastCfilesr = cfiles.back(); + futures.push_back(V3ThreadPool::s().enqueue([&fastCfilesr]() { + EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ false, fastCfilesr); + })); } + // Wait for futures + V3ThreadPool::waitForFutures(futures); for (const auto& collr : cfiles) { for (const auto cfilep : collr) v3Global.rootp()->addFilesp(cfilep); } From 584f8cc9e7f09c88bba1d771d29cd59b3f9a8860 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 5 May 2023 13:47:34 -0400 Subject: [PATCH 016/129] Internal: With --xml-only support --debug-exit-uvm --- src/V3AstNodes.cpp | 4 +++- src/V3EmitXml.cpp | 8 ++++---- src/Verilator.cpp | 1 + test_regress/t/t_process_parse.pl | 11 +++++++++-- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 6c300058f..e0b2f1b4f 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -391,8 +391,10 @@ string AstVar::verilogKwd() const { return "wreal"; } else if (varType() == VVarType::IFACEREF) { return "ifaceref"; - } else { + } else if (dtypep()) { return dtypep()->name(); + } else { + return "UNKNOWN"; } } diff --git a/src/V3EmitXml.cpp b/src/V3EmitXml.cpp index 5dc1ed39e..5466bf2f4 100644 --- a/src/V3EmitXml.cpp +++ b/src/V3EmitXml.cpp @@ -188,7 +188,7 @@ class EmitXmlFileVisitor final : public VNVisitorConst { void visit(AstVar* nodep) override { const VVarType typ = nodep->varType(); const string kw = nodep->verilogKwd(); - const string vt = nodep->dtypep()->name(); + const string vt = nodep->dtypep() ? nodep->dtypep()->name() : ""; outputTag(nodep, ""); if (nodep->isIO()) { puts(" dir="); @@ -225,7 +225,7 @@ class EmitXmlFileVisitor final : public VNVisitorConst { void visit(AstPin* nodep) override { // What we call a pin in verilator is a port in the IEEE spec. outputTag(nodep, "port"); // IEEE: vpiPort - if (nodep->modVarp()->isIO()) { + if (nodep->modVarp() && nodep->modVarp()->isIO()) { puts(" direction=\"" + nodep->modVarp()->direction().xmlKwd() + "\""); } puts(" portIndex=\"" + cvtToStr(nodep->pinNum()) + "\""); // IEEE: vpiPortIndex @@ -254,7 +254,7 @@ class EmitXmlFileVisitor final : public VNVisitorConst { void visit(AstNodeCCall* nodep) override { outputTag(nodep, ""); puts(" func="); - putsQuoted(nodep->funcp()->name()); + putsQuoted(nodep->funcp() ? nodep->funcp()->name() : nodep->name()); outputChildrenEnd(nodep, ""); } @@ -401,7 +401,7 @@ private: } } void visit(AstCell* nodep) override { - if (nodep->modp()->dead()) return; + if (nodep->modp() && nodep->modp()->dead()) return; if (!m_hasChildren) m_os << ">\n"; m_os << "fileline()->xmlDetailedLocation() << " name=\"" << nodep->name() << "\"" diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 79a38fce4..6737b8f40 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -144,6 +144,7 @@ static void process() { if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "Link"); if (v3Global.opt.debugExitUvm()) { V3Error::abortIfErrors(); + if (v3Global.opt.xmlOnly()) V3EmitXml::emitxml(); cout << "--debug-exit-uvm: Exiting after UVM-supported pass\n"; std::exit(0); } diff --git a/test_regress/t/t_process_parse.pl b/test_regress/t/t_process_parse.pl index 71e0db056..0023276e1 100755 --- a/test_regress/t/t_process_parse.pl +++ b/test_regress/t/t_process_parse.pl @@ -12,9 +12,16 @@ scenarios(vlt => 1); top_filename("t_process.v"); -lint( - verilator_flags2 => ["--debug-exit-uvm"], +my $out_filename = "$Self->{obj_dir}/V$Self->{name}.xml"; + +compile( + verilator_flags2 => ["--debug-exit-uvm", "--xml-only"], + make_main => 0, + make_top_shell => 0, + verilator_make_gmake => 0, ); +file_grep($out_filename, qr/./); # Exists + ok(1); 1; From d308a561e44f1fda8e66e658aec0358d520b4076 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 5 May 2023 20:16:27 -0400 Subject: [PATCH 017/129] Fix detection of wire/reg duplicates --- src/V3LinkDot.cpp | 3 ++- test_regress/t/t_const_opt.v | 3 +-- test_regress/t/t_var_dup2_bad.out | 12 ++++++++++++ test_regress/t/t_var_dup2_bad.v | 7 +++++++ test_regress/t/t_var_dup_bad.out | 1 - 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 251022043..0aa867324 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1211,7 +1211,8 @@ class LinkDotFindVisitor final : public VNVisitor { return; } const bool nansiBad - = ((findvarp->isDeclTyped() && nodep->isDeclTyped()) + = (((findvarp->isDeclTyped() || findvarp->isNet()) + && (nodep->isDeclTyped() || nodep->isNet())) || (findvarp->isIO() && nodep->isIO())); // e.g. !(output && output) const bool ansiBad = findvarp->isAnsi() || nodep->isAnsi(); // dup illegal with ANSI diff --git a/test_regress/t/t_const_opt.v b/test_regress/t/t_const_opt.v index 843bd8870..cfdcc3917 100644 --- a/test_regress/t/t_const_opt.v +++ b/test_regress/t/t_const_opt.v @@ -152,7 +152,7 @@ module bug3182(in, out); bit_source = c_fake_dependency() | in; wire [5:0] tmp = bit_source; // V3Gate should inline this - wire out = ~(tmp >> 5) & (bit_source == 5'd10); + assign out = ~(tmp >> 5) & (bit_source == 5'd10); /* verilator lint_on WIDTH */ endmodule @@ -374,7 +374,6 @@ endmodule // total polarity. This bug was introduced when fixing #3445. module bug4059(input wire clk, input wire [31:0] in, output wire out); wire [127:0] words_i; - logic [127:0] words_i; for (genvar i = 0; i < $bits(in); ++i) begin always_ff @(posedge clk) words_i[4 * i +: 4] <= {4{in[i]}}; diff --git a/test_regress/t/t_var_dup2_bad.out b/test_regress/t/t_var_dup2_bad.out index 347ba1095..79d73749b 100644 --- a/test_regress/t/t_var_dup2_bad.out +++ b/test_regress/t/t_var_dup2_bad.out @@ -11,4 +11,16 @@ t/t_var_dup2_bad.v:11:11: ... Location of original declaration 11 | output bad_o_r); | ^~~~~~~ +%Error: t/t_var_dup2_bad.v:17:9: Duplicate declaration of signal: 'bad_w_r' + 17 | reg bad_w_r; + | ^~~~~~~ + t/t_var_dup2_bad.v:16:9: ... Location of original declaration + 16 | wire bad_w_r; + | ^~~~~~~ +%Error: t/t_var_dup2_bad.v:20:9: Duplicate declaration of signal: 'bad_r_w' + 20 | reg bad_r_w; + | ^~~~~~~ + t/t_var_dup2_bad.v:19:9: ... Location of original declaration + 19 | wire bad_r_w; + | ^~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_var_dup2_bad.v b/test_regress/t/t_var_dup2_bad.v index 21eb3cb4b..3d762be23 100644 --- a/test_regress/t/t_var_dup2_bad.v +++ b/test_regress/t/t_var_dup2_bad.v @@ -12,4 +12,11 @@ module t wire bad_o_w; reg bad_o_r; + + wire bad_w_r; + reg bad_w_r; + + wire bad_r_w; + reg bad_r_w; + endmodule diff --git a/test_regress/t/t_var_dup_bad.out b/test_regress/t/t_var_dup_bad.out index 4f86e876a..b029c5809 100644 --- a/test_regress/t/t_var_dup_bad.out +++ b/test_regress/t/t_var_dup_bad.out @@ -47,7 +47,6 @@ 64 | output bad_reout_port | ^~~~~~~~~~~~~~ %Error: t/t_var_dup_bad.v:73:9: Duplicate declaration of signal: 'bad_rewire' - : ... note: ANSI ports must have type declared with the I/O (IEEE 1800-2017 23.2.2.2) 73 | wire bad_rewire; | ^~~~~~~~~~ t/t_var_dup_bad.v:70:16: ... Location of original declaration From 3250ee57074d7f930f5089b0c9dceef83be6da84 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 5 May 2023 20:24:45 -0400 Subject: [PATCH 018/129] Commentary: Changes update --- Changes | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Changes b/Changes index 86fef83fe..bc034ee96 100644 --- a/Changes +++ b/Changes @@ -11,8 +11,20 @@ contributors that suggested a given feature are shown in []. Thanks! Verilator 5.011 devel ========================== +**Major:** + +* With -j or --build-jobs, multithread Verilator's emit phase of Verilation. [Kamil Rakoczy, Antmicro Ltd] + Additional Verilator-internal stages will become multithreaded over time. + **Minor:** +* Optimize VPI callValueCbs (#4155). [Hennadii Chernyshchyk] +* Fix marking overridden methods as coroutines (#4120) (#4169). [Krzysztof Bieganski, Antmicro Ltd] +* Fix duplicate static names in blocks in functions (#4144) (#4160). [Stefan Wallentowitz] +* Fix initialization order of initial static after function/task (#4159). [Kamil Rakoczy, Antmicro Ltd] +* Fix linking AstRefDType if it has parameterized class ref (#4164) (#4170). [Ryszard Rozak, Antmicro Ltd] +* Fix crash caused by $display() optimization (#4165) (#4166). [Tudor Timi] +* Fix detection of wire/reg duplicates. Verilator 5.010 2023-04-30 From 28944ed862aea49566950ca7aa3d7b741e71914f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 5 May 2023 20:31:48 -0400 Subject: [PATCH 019/129] Fix crash on duplicate imported modules (#3231). --- Changes | 1 + src/V3LinkCells.cpp | 10 +++++++-- test_regress/t/t_package_dup_bad.out | 21 +++++++++++++++++++ test_regress/t/t_package_dup_bad.pl | 19 +++++++++++++++++ test_regress/t/t_package_dup_bad.v | 31 ++++++++++++++++++++++++++++ 5 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 test_regress/t/t_package_dup_bad.out create mode 100755 test_regress/t/t_package_dup_bad.pl create mode 100644 test_regress/t/t_package_dup_bad.v diff --git a/Changes b/Changes index bc034ee96..e88a895d6 100644 --- a/Changes +++ b/Changes @@ -24,6 +24,7 @@ Verilator 5.011 devel * Fix initialization order of initial static after function/task (#4159). [Kamil Rakoczy, Antmicro Ltd] * Fix linking AstRefDType if it has parameterized class ref (#4164) (#4170). [Ryszard Rozak, Antmicro Ltd] * Fix crash caused by $display() optimization (#4165) (#4166). [Tudor Timi] +* Fix crash on duplicate imported modules (#3231). [Robert Balas] * Fix detection of wire/reg duplicates. diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp index 04639e6ad..d44ae8361 100644 --- a/src/V3LinkCells.cpp +++ b/src/V3LinkCells.cpp @@ -116,6 +116,7 @@ private: VSymGraph m_mods; // Symbol table of all module names LinkCellsGraph m_graph; // Linked graph of all cell interconnects LibraryVertex* m_libVertexp = nullptr; // Vertex at root of all libraries + int m_dedupNum = 0; // Package dedup number const V3GraphVertex* m_topVertexp = nullptr; // Vertex of top module std::unordered_set m_declfnWarned; // Files we issued DECLFILENAME on string m_origTopModuleName; // original name of the top module @@ -504,8 +505,13 @@ private: << "... Location of original declaration\n" << foundp->warnContextSecondary()); } - nodep->unlinkFrBack(); - VL_DO_DANGLING(pushDeletep(nodep), nodep); + if (VN_IS(nodep, Package)) { + // Packages may be imported, we instead rename to be unique + nodep->name(nodep->name() + "__Vdedup" + cvtToStr(m_dedupNum++)); + } else { + nodep->unlinkFrBack(); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } } else if (!foundp) { m_mods.rootp()->insert(nodep->name(), new VSymEnt{&m_mods, nodep}); } diff --git a/test_regress/t/t_package_dup_bad.out b/test_regress/t/t_package_dup_bad.out new file mode 100644 index 000000000..7cc93102e --- /dev/null +++ b/test_regress/t/t_package_dup_bad.out @@ -0,0 +1,21 @@ +%Warning-MODDUP: t/t_package_dup_bad.v:11:9: Duplicate declaration of module: 'pkg' + 11 | package pkg; + | ^~~ + t/t_package_dup_bad.v:7:9: ... Location of original declaration + 7 | package pkg; + | ^~~ + ... For warning description see https://verilator.org/warn/MODDUP?v=latest + ... Use "/* verilator lint_off MODDUP */" and lint_on around source to disable this message. +%Warning-MODDUP: t/t_package_dup_bad.v:19:9: Duplicate declaration of module: 'pkg' + 19 | package pkg; + | ^~~ + t/t_package_dup_bad.v:7:9: ... Location of original declaration + 7 | package pkg; + | ^~~ +%Warning-MODDUP: t/t_package_dup_bad.v:22:9: Duplicate declaration of module: 'pkg' + 22 | package pkg; + | ^~~ + t/t_package_dup_bad.v:7:9: ... Location of original declaration + 7 | package pkg; + | ^~~ +%Error: Exiting due to diff --git a/test_regress/t/t_package_dup_bad.pl b/test_regress/t/t_package_dup_bad.pl new file mode 100755 index 000000000..c35c8bc93 --- /dev/null +++ b/test_regress/t/t_package_dup_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 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); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_package_dup_bad.v b/test_regress/t/t_package_dup_bad.v new file mode 100644 index 000000000..7a118fa59 --- /dev/null +++ b/test_regress/t/t_package_dup_bad.v @@ -0,0 +1,31 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +package pkg; + localparam PARAM = 10; +endpackage + +package pkg; + localparam PARAM = 10; +endpackage + +module sub import pkg::*; + #( ) (); +endmodule + +package pkg; +endpackage + +package pkg; +endpackage + +module t (/*AUTOARG*/); + sub sub (); + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From fdea386727cfa9ccfb1c421514bac2eab5bc491c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 5 May 2023 22:05:19 -0400 Subject: [PATCH 020/129] Fix false WIDTHEXPAND on array declarations (#3959). --- Changes | 3 ++- src/V3Width.cpp | 8 ++++++-- test_regress/t/t_lint_width_arraydecl.pl | 17 +++++++++++++++++ test_regress/t/t_lint_width_arraydecl.v | 21 +++++++++++++++++++++ 4 files changed, 46 insertions(+), 3 deletions(-) create mode 100755 test_regress/t/t_lint_width_arraydecl.pl create mode 100644 test_regress/t/t_lint_width_arraydecl.v diff --git a/Changes b/Changes index e88a895d6..cd1c4dee6 100644 --- a/Changes +++ b/Changes @@ -19,12 +19,13 @@ Verilator 5.011 devel **Minor:** * Optimize VPI callValueCbs (#4155). [Hennadii Chernyshchyk] +* Fix crash on duplicate imported modules (#3231). [Robert Balas] +* Fix false WIDTHEXPAND on array declarations (#3959). [JOTEGO] * Fix marking overridden methods as coroutines (#4120) (#4169). [Krzysztof Bieganski, Antmicro Ltd] * Fix duplicate static names in blocks in functions (#4144) (#4160). [Stefan Wallentowitz] * Fix initialization order of initial static after function/task (#4159). [Kamil Rakoczy, Antmicro Ltd] * Fix linking AstRefDType if it has parameterized class ref (#4164) (#4170). [Ryszard Rozak, Antmicro Ltd] * Fix crash caused by $display() optimization (#4165) (#4166). [Tudor Timi] -* Fix crash on duplicate imported modules (#3231). [Robert Balas] * Fix detection of wire/reg duplicates. diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 50c7c9af7..0d02e36a0 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1658,12 +1658,16 @@ private: } else if (AstNodeDType* const keyp = VN_CAST(elementsp, NodeDType)) { newp = new AstAssocArrayDType{nodep->fileline(), VFlagChildDType{}, childp, keyp}; } else { + // The subtract in the range may confuse users; as the array + // size is self determined there's no reason to warn about widths + FileLine* const elementsNewFl = elementsp->fileline(); + elementsNewFl->warnOff(V3ErrorCode::WIDTHEXPAND, true); // Must be expression that is constant, but we'll determine that later newp = new AstUnpackArrayDType{ nodep->fileline(), VFlagChildDType{}, childp, new AstRange{nodep->fileline(), new AstConst(elementsp->fileline(), 0), - new AstSub{elementsp->fileline(), VN_AS(elementsp, NodeExpr), - new AstConst(elementsp->fileline(), 1)}}}; + new AstSub{elementsNewFl, VN_AS(elementsp, NodeExpr), + new AstConst(elementsNewFl, 1)}}}; } nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); diff --git a/test_regress/t/t_lint_width_arraydecl.pl b/test_regress/t/t_lint_width_arraydecl.pl new file mode 100755 index 000000000..629a44bbb --- /dev/null +++ b/test_regress/t/t_lint_width_arraydecl.pl @@ -0,0 +1,17 @@ +#!/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 => 1); + +lint( + ); + +ok(1); +1; diff --git a/test_regress/t/t_lint_width_arraydecl.v b/test_regress/t/t_lint_width_arraydecl.v new file mode 100644 index 000000000..5de0ecc50 --- /dev/null +++ b/test_regress/t/t_lint_width_arraydecl.v @@ -0,0 +1,21 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2009 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +localparam UADDR_WIDTH = 4'd10; +localparam UROM_WIDTH = 5'd17; +localparam UROM_DEPTH = 11'd1024; + + +module t( + input clk, + input [UADDR_WIDTH-1:0] mAddr, + output logic [UROM_WIDTH-1:0] mOutput); + + reg [UROM_WIDTH-1:0] uRam[UROM_DEPTH]; + + always @(posedge clk) mOutput <= uRam[mAddr]; + +endmodule From 64ab537b688059257d96cb9af8ba019092832696 Mon Sep 17 00:00:00 2001 From: Ethan Sifferman Date: Fri, 5 May 2023 19:36:51 -0700 Subject: [PATCH 021/129] Add NEWERSTD warning when using feature in newer language standard (#4168) (#4172). --- docs/CONTRIBUTORS | 1 + docs/guide/warnings.rst | 15 +++++++++++++ src/V3AstNodeExpr.h | 14 ++++++++++++ src/V3Error.h | 9 ++++---- src/V3Inst.cpp | 4 ++-- src/V3LinkDot.cpp | 3 +-- src/V3LinkParse.cpp | 14 +++++++++++- src/V3ParseGrammar.cpp | 3 ++- test_regress/t/t_gate_fdup.pl | 4 ++++ test_regress/t/t_number_v_bad.out | 21 ++++++++++++++++++ test_regress/t/t_number_v_bad.pl | 20 +++++++++++++++++ test_regress/t/t_number_v_bad.v | 18 +++++++++++++++ test_regress/t/t_param_default_presv_bad.out | 8 ++++++- .../t/t_strength_assignments_constants.pl | 4 ++++ .../t/t_strength_assignments_constants.v | 10 ++++----- test_regress/t/t_strength_highz.pl | 1 + test_regress/t/t_wire_beh1364_bad.out | 20 ++++++++--------- test_regress/t/t_wire_beh1364_bad.v | 22 ++++++++++--------- test_regress/t/t_wire_behp1364_bad.out | 12 +++++----- test_regress/t/t_wire_behp1364_bad.v | 22 ++++++++++--------- 20 files changed, 173 insertions(+), 52 deletions(-) create mode 100644 test_regress/t/t_number_v_bad.out create mode 100755 test_regress/t/t_number_v_bad.pl create mode 100644 test_regress/t/t_number_v_bad.v diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 35cdff8d7..54a3058fd 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -29,6 +29,7 @@ Drew Taussig Driss Hafdi Edgar E. Iglesias Eric Rippey +Ethan Sifferman Eyck Jentzsch Fan Shupei february cozzocrea diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst index b88f2ce20..fa131af70 100644 --- a/docs/guide/warnings.rst +++ b/docs/guide/warnings.rst @@ -972,6 +972,21 @@ List Of Warnings (neither :vlopt:`--timing` nor :vlopt:`--no-timing` option was provided). +.. option:: NEWERSTD + + Warns that a feature requires a newer standard of Verilog or SystemVerilog + than the one specified by the :vlopt:`--language` option. For example, unsized + unbased literals (`'0`, `'1`, `'z`, `'x`) require 1800-2005 or later. + + To avoid this warning, use a Verilog or SystemVerilog standard that + supports the feature. Alternatively, modify your code to use a different + syntax that is supported by the Verilog/SystemVerilog standard specified + by the :vlopt:`--language` option. + + Ignoring this warning will only suppress the lint check; it will + simulate correctly. + + .. option:: NOLATCH .. TODO better example diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 635b9edb4..bd54322c2 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -975,6 +975,20 @@ public: , m_num(this, 1, on) { dtypeSetBit(); } + class All0 {}; + AstConst(FileLine* fl, All0) + : ASTGEN_SUPER_Const(fl) + , m_num(this, "'0") { + initWithNumber(); + fl->warnOff(V3ErrorCode::NEWERSTD, true); + } + class All1 {}; + AstConst(FileLine* fl, All1) + : ASTGEN_SUPER_Const(fl) + , m_num(this, "'1") { + initWithNumber(); + fl->warnOff(V3ErrorCode::NEWERSTD, true); + } class Null {}; AstConst(FileLine* fl, Null) : ASTGEN_SUPER_Const(fl) diff --git a/src/V3Error.h b/src/V3Error.h index 8d0f784b3..8a7902e01 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -116,6 +116,7 @@ public: MODDUP, // Duplicate module MULTIDRIVEN, // Driven from multiple blocks MULTITOP, // Multiple top level modules + NEWERSTD, // Newer language standard required NOLATCH, // No latch detected in always_latch block NULLPORT, // Null port detected in module definition PINCONNECTEMPTY,// Cell pin connected by name with empty reference @@ -195,7 +196,7 @@ public: "IMPERFECTSCH", "IMPLICIT", "IMPLICITSTATIC", "IMPORTSTAR", "IMPURE", "INCABSPATH", "INFINITELOOP", "INITIALDLY", "INSECURE", "LATCH", "LITENDIAN", "MINTYPMAXDLY", "MODDUP", - "MULTIDRIVEN", "MULTITOP", "NOLATCH", "NULLPORT", "PINCONNECTEMPTY", + "MULTIDRIVEN", "MULTITOP", "NEWERSTD", "NOLATCH", "NULLPORT", "PINCONNECTEMPTY", "PINMISSING", "PINNOCONNECT", "PINNOTFOUND", "PKGNODECL", "PROCASSWIRE", "PROFOUTOFDATE", "PROTECTED", "RANDC", "REALCVT", "REDEFMACRO", "RISEFALLDLY", "SELRANGE", "SHORTREAL", "SPLITVAR", "STATICVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET", @@ -233,9 +234,9 @@ public: return (m_e == ALWCOMBORDER || m_e == ASCRANGE || m_e == BSSPACE || m_e == CASEINCOMPLETE || m_e == CASEOVERLAP || m_e == CASEWITHX || m_e == CASEX || m_e == CASTCONST || m_e == CMPCONST || m_e == COLONPLUS || m_e == IMPLICIT || m_e == IMPLICITSTATIC - || m_e == LATCH || m_e == PINMISSING || m_e == REALCVT || m_e == STATICVAR - || m_e == UNSIGNED || m_e == WIDTH || m_e == WIDTHTRUNC || m_e == WIDTHEXPAND - || m_e == WIDTHXZEXPAND); + || m_e == LATCH || m_e == NEWERSTD || m_e == PINMISSING || m_e == REALCVT + || m_e == STATICVAR || m_e == UNSIGNED || m_e == WIDTH || m_e == WIDTHTRUNC + || m_e == WIDTHEXPAND || m_e == WIDTHXZEXPAND); } // Warnings that are style only bool styleError() const VL_MT_SAFE { diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index f451f8b54..0b96463e5 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -517,10 +517,10 @@ public: // otherwise done if (pinVarp->direction() == VDirection::INPUT && cellp->modp()->unconnectedDrive().isSetTrue()) { - pinp->exprp(new AstConst{pinp->fileline(), AstConst::StringToParse{}, "'1"}); + pinp->exprp(new AstConst{pinp->fileline(), AstConst::All1{}}); } else if (pinVarp->direction() == VDirection::INPUT && cellp->modp()->unconnectedDrive().isSetFalse()) { - pinp->exprp(new AstConst{pinp->fileline(), AstConst::StringToParse{}, "'0"}); + pinp->exprp(new AstConst{pinp->fileline(), AstConst::All0{}}); } else { return nullptr; } diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 0aa867324..dabe702a0 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -3117,8 +3117,7 @@ private: if (v3Global.opt.bboxSys()) { AstNode* newp; if (VN_IS(nodep, FuncRef)) { - newp = new AstConst{nodep->fileline(), AstConst::StringToParse{}, - "'0"}; + newp = new AstConst{nodep->fileline(), AstConst::All0{}}; } else { AstNode* outp = nullptr; while (nodep->pinsp()) { diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index e1ed27590..907bf988b 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -240,7 +240,10 @@ private: if (nodep->isGParam() && m_modp) m_modp->hasGParam(true); if (nodep->isParam() && !nodep->valuep() && nodep->fileline()->language() < V3LangCode::L1800_2009) { - nodep->v3error("Parameter requires default value, or use IEEE 1800-2009 or later."); + nodep->v3warn( + NEWERSTD, + "Parameter requires default value, or use IEEE 1800-2009 or later." + ); } if (VN_IS(nodep->subDTypep(), ParseTypeDType)) { // It's a parameter type. Use a different node type for this. @@ -329,6 +332,15 @@ private: } } } + void visit(AstConst* nodep) override { + if (nodep->num().autoExtend() + && nodep->fileline()->language() < V3LangCode::L1800_2005) { + nodep->v3warn( + NEWERSTD, + "Unbased unsized literals require IEEE 1800-2005 or later." + ); + } + } void visit(AstAttrOf* nodep) override { cleanFileline(nodep); diff --git a/src/V3ParseGrammar.cpp b/src/V3ParseGrammar.cpp index b60e6bb07..9e63bd229 100644 --- a/src/V3ParseGrammar.cpp +++ b/src/V3ParseGrammar.cpp @@ -87,7 +87,8 @@ AstArg* V3ParseGrammar::argWrapList(AstNodeExpr* nodep) { AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, const string& name, int value) { AstAssignW* assignp = new AstAssignW{fileline, new AstVarRef{fileline, name, VAccess::WRITE}, - new AstConst{fileline, AstConst::StringToParse{}, (value ? "'1" : "'0")}}; + value ? new AstConst{fileline, AstConst::All1{}} + : new AstConst{fileline, AstConst::All0{}} }; AstStrengthSpec* strengthSpecp = new AstStrengthSpec{fileline, VStrength::SUPPLY, VStrength::SUPPLY}; assignp->strengthSpecp(strengthSpecp); diff --git a/test_regress/t/t_gate_fdup.pl b/test_regress/t/t_gate_fdup.pl index 2eb6a63bc..d2f13f637 100755 --- a/test_regress/t/t_gate_fdup.pl +++ b/test_regress/t/t_gate_fdup.pl @@ -13,5 +13,9 @@ scenarios(simulator => 1); compile( ); +lint( + verilator_flags2 => ["--language 1364-2005"] + ); + ok(1); 1; diff --git a/test_regress/t/t_number_v_bad.out b/test_regress/t/t_number_v_bad.out new file mode 100644 index 000000000..af57029f9 --- /dev/null +++ b/test_regress/t/t_number_v_bad.out @@ -0,0 +1,21 @@ +%Warning-NEWERSTD: t/t_number_v_bad.v:11:25: Unbased unsized literals require IEEE 1800-2005 or later. + 11 | wire [127:0] FOO1 = '0; + | ^~ + ... For warning description see https://verilator.org/warn/NEWERSTD?v=latest + ... Use "/* verilator lint_off NEWERSTD */" and lint_on around source to disable this message. +%Warning-NEWERSTD: t/t_number_v_bad.v:12:25: Unbased unsized literals require IEEE 1800-2005 or later. + 12 | wire [127:0] FOO2 = '1; + | ^~ +%Warning-NEWERSTD: t/t_number_v_bad.v:13:25: Unbased unsized literals require IEEE 1800-2005 or later. + 13 | wire [127:0] FOO3 = 'x; + | ^~ +%Warning-NEWERSTD: t/t_number_v_bad.v:14:25: Unbased unsized literals require IEEE 1800-2005 or later. + 14 | wire [127:0] FOO4 = 'X; + | ^~ +%Warning-NEWERSTD: t/t_number_v_bad.v:15:25: Unbased unsized literals require IEEE 1800-2005 or later. + 15 | wire [127:0] FOO5 = 'z; + | ^~ +%Warning-NEWERSTD: t/t_number_v_bad.v:16:25: Unbased unsized literals require IEEE 1800-2005 or later. + 16 | wire [127:0] FOO6 = 'Z; + | ^~ +%Error: Exiting due to diff --git a/test_regress/t/t_number_v_bad.pl b/test_regress/t/t_number_v_bad.pl new file mode 100755 index 000000000..24b1e474d --- /dev/null +++ b/test_regress/t/t_number_v_bad.pl @@ -0,0 +1,20 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Ethan Sifferman and Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + verilator_flags2 => ["--language 1364-2005"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_number_v_bad.v b/test_regress/t/t_number_v_bad.v new file mode 100644 index 000000000..d8b503ba8 --- /dev/null +++ b/test_regress/t/t_number_v_bad.v @@ -0,0 +1,18 @@ +// DESCRIPTION: Verilator: Test of Verilog and SystemVerilog integer literal differences +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Ethan Sifferman. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + + // "unbased_unsized_literal" is SystemVerilog only + // Should fail with "NEWERSTD" + wire [127:0] FOO1 = '0; + wire [127:0] FOO2 = '1; + wire [127:0] FOO3 = 'x; + wire [127:0] FOO4 = 'X; + wire [127:0] FOO5 = 'z; + wire [127:0] FOO6 = 'Z; + +endmodule diff --git a/test_regress/t/t_param_default_presv_bad.out b/test_regress/t/t_param_default_presv_bad.out index b491e2719..1e86bff74 100644 --- a/test_regress/t/t_param_default_presv_bad.out +++ b/test_regress/t/t_param_default_presv_bad.out @@ -1,4 +1,10 @@ -%Error: t/t_param_default_bad.v:7:26: Parameter requires default value, or use IEEE 1800-2009 or later. +%Warning-NEWERSTD: t/t_param_default_bad.v:7:26: Parameter requires default value, or use IEEE 1800-2009 or later. + 7 | module m #(parameter int Foo); + | ^~~ + ... For warning description see https://verilator.org/warn/NEWERSTD?v=latest + ... Use "/* verilator lint_off NEWERSTD */" and lint_on around source to disable this message. +%Error: t/t_param_default_bad.v:7:26: Parameter without initial value is never given value (IEEE 1800-2017 6.20.1): 'Foo' + : ... In instance t.foo 7 | module m #(parameter int Foo); | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_strength_assignments_constants.pl b/test_regress/t/t_strength_assignments_constants.pl index 1aa73f80a..85ac7d5bc 100755 --- a/test_regress/t/t_strength_assignments_constants.pl +++ b/test_regress/t/t_strength_assignments_constants.pl @@ -17,5 +17,9 @@ execute( check_finished => 1, ); +lint( + verilator_flags2 => ["--language 1364-2005"] + ); + ok(1); 1; diff --git a/test_regress/t/t_strength_assignments_constants.v b/test_regress/t/t_strength_assignments_constants.v index 8344adbdd..c91b7104f 100644 --- a/test_regress/t/t_strength_assignments_constants.v +++ b/test_regress/t/t_strength_assignments_constants.v @@ -14,18 +14,18 @@ module t (/*AUTOARG*/); assign (strong0, strong1) b = 0; wire [1:0] c; - assign (weak0, supply1) c = '1; - assign (supply0, pull1) c = '1; - assign (strong0, strong1) c = '0; + assign (weak0, supply1) c = 2'b11; + assign (supply0, pull1) c = 2'b11; + assign (strong0, strong1) c = 0; supply0 d; assign (strong0, strong1) d = 1; - wire (supply0, supply1) e = 'z; + wire (supply0, supply1) e = 1'bz; assign (weak0, weak1) e = 1; always begin - if (a && !b && c === '1 && !d && e) begin + if (a && !b && c === 2'b11 && !d && e) begin $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_strength_highz.pl b/test_regress/t/t_strength_highz.pl index 48bf31461..6537d741c 100755 --- a/test_regress/t/t_strength_highz.pl +++ b/test_regress/t/t_strength_highz.pl @@ -11,6 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); lint( + verilator_flags2 => ["--language 1364-2005"], fails => $Self->{vlt_all}, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_wire_beh1364_bad.out b/test_regress/t/t_wire_beh1364_bad.out index e9ff7ee3d..4667a07f9 100644 --- a/test_regress/t/t_wire_beh1364_bad.out +++ b/test_regress/t/t_wire_beh1364_bad.out @@ -1,22 +1,22 @@ -%Error-PROCASSWIRE: t/t_wire_beh1364_bad.v:25:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'w' +%Error-PROCASSWIRE: t/t_wire_beh1364_bad.v:26:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'w' : ... In instance t - 25 | w = '0; + 26 | w = 0; | ^ ... For error description see https://verilator.org/warn/PROCASSWIRE?v=latest -%Error-PROCASSWIRE: t/t_wire_beh1364_bad.v:26:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'o' +%Error-PROCASSWIRE: t/t_wire_beh1364_bad.v:27:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'o' : ... In instance t - 26 | o = '0; + 27 | o = 0; | ^ -%Error-PROCASSWIRE: t/t_wire_beh1364_bad.v:27:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'oa' +%Error-PROCASSWIRE: t/t_wire_beh1364_bad.v:28:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'oa' : ... In instance t - 27 | oa = '0; + 28 | oa = 0; | ^~ -%Error-PROCASSWIRE: t/t_wire_beh1364_bad.v:28:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'wo' +%Error-PROCASSWIRE: t/t_wire_beh1364_bad.v:29:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'wo' : ... In instance t - 28 | wo = '0; + 29 | wo = 0; | ^~ -%Error-PROCASSWIRE: t/t_wire_beh1364_bad.v:29:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'woa' +%Error-PROCASSWIRE: t/t_wire_beh1364_bad.v:30:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'woa' : ... In instance t - 29 | woa = '0; + 30 | woa = 0; | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_wire_beh1364_bad.v b/test_regress/t/t_wire_beh1364_bad.v index e8ca5744c..d983139f8 100644 --- a/test_regress/t/t_wire_beh1364_bad.v +++ b/test_regress/t/t_wire_beh1364_bad.v @@ -22,16 +22,18 @@ module t (/*AUTOARG*/ //output var [1:0] voa; initial begin - w = '0; // Error - o = '0; // Error - oa = '0; // Error - wo = '0; // Error - woa = '0; // Error - r = '0; // Not an error - ro = '0; // Not an error - roa = '0; // Not an error - //vo = '0; // Not an error - //voa = '0; // Not an error + // Error + w = 0; + o = 0; + oa = 0; + wo = 0; + woa = 0; + // Not an error + r = 0; + ro = 0; + roa = 0; + //vo = 0; + //voa = 0; end endmodule diff --git a/test_regress/t/t_wire_behp1364_bad.out b/test_regress/t/t_wire_behp1364_bad.out index 68b6db330..9fbbf0f6c 100644 --- a/test_regress/t/t_wire_behp1364_bad.out +++ b/test_regress/t/t_wire_behp1364_bad.out @@ -1,14 +1,14 @@ -%Error-PROCASSWIRE: t/t_wire_behp1364_bad.v:23:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'w' +%Error-PROCASSWIRE: t/t_wire_behp1364_bad.v:24:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'w' : ... In instance t - 23 | w = '0; + 24 | w = 0; | ^ ... For error description see https://verilator.org/warn/PROCASSWIRE?v=latest -%Error-PROCASSWIRE: t/t_wire_behp1364_bad.v:24:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'o' +%Error-PROCASSWIRE: t/t_wire_behp1364_bad.v:25:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'o' : ... In instance t - 24 | o = '0; + 25 | o = 0; | ^ -%Error-PROCASSWIRE: t/t_wire_behp1364_bad.v:25:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'oa' +%Error-PROCASSWIRE: t/t_wire_behp1364_bad.v:26:7: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'oa' : ... In instance t - 25 | oa = '0; + 26 | oa = 0; | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_wire_behp1364_bad.v b/test_regress/t/t_wire_behp1364_bad.v index 42a67c340..e88ea744d 100644 --- a/test_regress/t/t_wire_behp1364_bad.v +++ b/test_regress/t/t_wire_behp1364_bad.v @@ -20,16 +20,18 @@ module t ( reg r; initial begin - w = '0; // Error - o = '0; // Error - oa = '0; // Error - wo = '0; // Error - woa = '0; // Error - r = '0; // Not an error - ro = '0; // Not an error - roa = '0; // Not an error - //vo = '0; // Not an error - //voa = '0; // Not an error + // Error + w = 0; + o = 0; + oa = 0; + wo = 0; + woa = 0; + // Not an error + r = 0; + ro = 0; + roa = 0; + //vo = 0; + //voa = 0; end endmodule From 8a3cb8daa84a575a317de1c0baebd76a1a8e9665 Mon Sep 17 00:00:00 2001 From: github action Date: Sat, 6 May 2023 02:37:42 +0000 Subject: [PATCH 022/129] Apply 'make format' --- src/V3LinkParse.cpp | 14 ++++---------- src/V3ParseGrammar.cpp | 7 +++---- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 907bf988b..bc4af9391 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -240,10 +240,8 @@ private: if (nodep->isGParam() && m_modp) m_modp->hasGParam(true); if (nodep->isParam() && !nodep->valuep() && nodep->fileline()->language() < V3LangCode::L1800_2009) { - nodep->v3warn( - NEWERSTD, - "Parameter requires default value, or use IEEE 1800-2009 or later." - ); + nodep->v3warn(NEWERSTD, + "Parameter requires default value, or use IEEE 1800-2009 or later."); } if (VN_IS(nodep->subDTypep(), ParseTypeDType)) { // It's a parameter type. Use a different node type for this. @@ -333,12 +331,8 @@ private: } } void visit(AstConst* nodep) override { - if (nodep->num().autoExtend() - && nodep->fileline()->language() < V3LangCode::L1800_2005) { - nodep->v3warn( - NEWERSTD, - "Unbased unsized literals require IEEE 1800-2005 or later." - ); + if (nodep->num().autoExtend() && nodep->fileline()->language() < V3LangCode::L1800_2005) { + nodep->v3warn(NEWERSTD, "Unbased unsized literals require IEEE 1800-2005 or later."); } } diff --git a/src/V3ParseGrammar.cpp b/src/V3ParseGrammar.cpp index 9e63bd229..f2f7f7949 100644 --- a/src/V3ParseGrammar.cpp +++ b/src/V3ParseGrammar.cpp @@ -85,10 +85,9 @@ AstArg* V3ParseGrammar::argWrapList(AstNodeExpr* nodep) { } AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, const string& name, int value) { - AstAssignW* assignp - = new AstAssignW{fileline, new AstVarRef{fileline, name, VAccess::WRITE}, - value ? new AstConst{fileline, AstConst::All1{}} - : new AstConst{fileline, AstConst::All0{}} }; + AstAssignW* assignp = new AstAssignW{fileline, new AstVarRef{fileline, name, VAccess::WRITE}, + value ? new AstConst{fileline, AstConst::All1{}} + : new AstConst{fileline, AstConst::All0{}}}; AstStrengthSpec* strengthSpecp = new AstStrengthSpec{fileline, VStrength::SUPPLY, VStrength::SUPPLY}; assignp->strengthSpecp(strengthSpecp); From 4ae80f9a9fda292e1c0bd15c260f379496895f50 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 5 May 2023 22:50:28 -0400 Subject: [PATCH 023/129] Commentary --- src/V3Partition.cpp | 1 + src/V3ThreadPool.cpp | 2 ++ src/Verilator.cpp | 1 + 3 files changed, 4 insertions(+) diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index ed8b67a3a..41b41ba51 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -3227,6 +3227,7 @@ void V3Partition::finalize(AstNetlist* netlistp) { } void V3Partition::selfTest() { + UINFO(2, __FUNCTION__ << ": " << endl); PartPropagateCpSelfTest::selfTest(); PartPackMTasks::selfTest(); PartContraction::selfTest(); diff --git a/src/V3ThreadPool.cpp b/src/V3ThreadPool.cpp index 47750a093..71ca0772e 100644 --- a/src/V3ThreadPool.cpp +++ b/src/V3ThreadPool.cpp @@ -183,8 +183,10 @@ void V3ThreadPool::selfTest() { futures.push_back(s().enqueue(std::bind(thirdJob, 100))); futures.push_back(s().enqueue(std::bind(thirdJob, 100))); V3ThreadPool::waitForFutures(futures); + s().waitIfStopRequested(); s().requestExclusiveAccess(std::bind(firstJob, 100)); + auto forthJob = [&]() -> int { return 1234; }; std::list> futuresInt; futuresInt.push_back(s().enqueue(forthJob)); diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 6737b8f40..9aeb177e1 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -624,6 +624,7 @@ static void verilate(const string& argString) { V3Partition::selfTestNormalizeCosts(); V3Broken::selfTest(); V3ThreadPool::selfTest(); + UINFO(2, "selfTest done\n"); } // Read first filename From 1a1c5c5d44f56237820fdb43d89e8490f6ea5e8e Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 6 May 2023 06:05:11 -0400 Subject: [PATCH 024/129] Internals: Fix pylint warning --- docs/guide/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/conf.py b/docs/guide/conf.py index 8755706ed..730b3e351 100644 --- a/docs/guide/conf.py +++ b/docs/guide/conf.py @@ -31,7 +31,7 @@ def get_vlt_version(): if match: try: data = os.popen('git log -n 1 --pretty=%cs').read() - except Exception: + except Exception: # pylint: disable=broad-except data = "" # fallback, and Sphinx will fill in today's date return "Devel " + match.group(1), data return "unknown", "unknown" From 76f5de6e54938e1d622186a3f39f85421f0f014a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 6 May 2023 06:08:32 -0400 Subject: [PATCH 025/129] Replace flake8 with ruff for Python linting --- Makefile.in | 10 ++++------ docs/guide/install.rst | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Makefile.in b/Makefile.in index c845f5e76..c74aadd73 100644 --- a/Makefile.in +++ b/Makefile.in @@ -424,17 +424,15 @@ YAPF_FLAGS = -i yapf: $(YAPF) $(YAPF_FLAGS) $(PY_FILES) -FLAKE8 = flake8 -FLAKE8_FLAGS = \ - --extend-exclude=fastcov.py \ - --ignore=E123,E129,E251,E402,E501,W503,W504,E701 - PYLINT = pylint PYLINT_FLAGS = --score=n --disable=R0801 +RUFF = ruff +RUFF_FLAGS = check --ignore=E402,E501,E701 + lint-py: - -$(FLAKE8) $(FLAKE8_FLAGS) $(PY_PROGRAMS) -$(PYLINT) $(PYLINT_FLAGS) $(PY_PROGRAMS) + -$(RUFF) $(RUFF_FLAGS) $(PY_PROGRAMS) format-pl-exec: -chmod a+x test_regress/t/*.pl diff --git a/docs/guide/install.rst b/docs/guide/install.rst index 681eaeba9..594773ae6 100644 --- a/docs/guide/install.rst +++ b/docs/guide/install.rst @@ -126,7 +126,7 @@ Those developing Verilator itself may also want these (see internals.rst): sudo apt-get install gdb graphviz cmake clang clang-format-14 gprof lcov sudo apt-get install libclang-dev yapf3 - sudo pip3 install clang sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe + sudo pip3 install clang sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe ruff cpan install Pod::Perldoc cpan install Parallel::Forker From 250c6950cfeea493d13fba14fefba00a6533ce17 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 6 May 2023 18:33:08 -0400 Subject: [PATCH 026/129] Fix randomize missing simple class rand members. --- src/V3Randomize.cpp | 8 ++++++++ test_regress/t/t_randomize_small.pl | 20 ++++++++++++++++++++ test_regress/t/t_randomize_small.v | 29 +++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100755 test_regress/t/t_randomize_small.pl create mode 100644 test_regress/t/t_randomize_small.v diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 409f09740..6f88a2372 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -47,6 +47,7 @@ private: using BaseToDerivedMap = std::unordered_map; BaseToDerivedMap m_baseToDerivedMap; // Mapping from base classes to classes that extend them + AstClass* m_classp = nullptr; // Current class // METHODS void markMembers(AstClass* nodep) { @@ -87,6 +88,8 @@ private: // VISITORS void visit(AstClass* nodep) override { + VL_RESTORER(m_classp); + m_classp = nodep; iterateChildrenConst(nodep); if (nodep->extendsp()) { // Save pointer to derived class @@ -104,6 +107,11 @@ private: markMembers(classp); } } + void visit(AstNodeFTaskRef* nodep) override { + iterateChildrenConst(nodep); + if (nodep->name() != "randomize") return; + if (m_classp) m_classp->user1(true); + } void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } diff --git a/test_regress/t/t_randomize_small.pl b/test_regress/t/t_randomize_small.pl new file mode 100755 index 000000000..49330a5fe --- /dev/null +++ b/test_regress/t/t_randomize_small.pl @@ -0,0 +1,20 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + ); + +ok(1); +1; diff --git a/test_regress/t/t_randomize_small.v b/test_regress/t/t_randomize_small.v new file mode 100644 index 000000000..1b91feab4 --- /dev/null +++ b/test_regress/t/t_randomize_small.v @@ -0,0 +1,29 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Cls; + rand int m_val; + + function void test; + automatic int rand_result; + + rand_result = randomize(); + if (rand_result != 1) $stop; + endfunction +endclass + +module t(/*AUTOARG*/); + + initial begin + Cls c; + c = new; + + c.test; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From a3640c176737fc118603aa71b4c49e529ab70b85 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 6 May 2023 19:09:19 -0400 Subject: [PATCH 027/129] Support get_randstate/set_randstate class method function. --- Changes | 1 + include/verilated.cpp | 31 +++++++++++----- include/verilated_types.h | 4 +-- src/V3LinkDot.cpp | 4 ++- src/V3Width.cpp | 46 ++++++++++++++++++++++-- test_regress/t/t_randstate_func.pl | 21 +++++++++++ test_regress/t/t_randstate_func.v | 48 +++++++++++++++++++++++++ test_regress/t/t_randstate_obj.out | 10 ++++++ test_regress/t/t_randstate_obj.pl | 19 ++++++++++ test_regress/t/t_randstate_obj.v | 39 ++++++++++++++++++++ test_regress/t/t_randstate_seed_bad.out | 2 ++ test_regress/t/t_randstate_seed_bad.pl | 21 +++++++++++ test_regress/t/t_randstate_seed_bad.v | 28 +++++++++++++++ 13 files changed, 259 insertions(+), 15 deletions(-) create mode 100755 test_regress/t/t_randstate_func.pl create mode 100644 test_regress/t/t_randstate_func.v create mode 100644 test_regress/t/t_randstate_obj.out create mode 100755 test_regress/t/t_randstate_obj.pl create mode 100644 test_regress/t/t_randstate_obj.v create mode 100644 test_regress/t/t_randstate_seed_bad.out create mode 100755 test_regress/t/t_randstate_seed_bad.pl create mode 100644 test_regress/t/t_randstate_seed_bad.v diff --git a/Changes b/Changes index cd1c4dee6..cd044ae68 100644 --- a/Changes +++ b/Changes @@ -18,6 +18,7 @@ Verilator 5.011 devel **Minor:** +* Support get_randstate/set_randstate class method function. * Optimize VPI callValueCbs (#4155). [Hennadii Chernyshchyk] * Fix crash on duplicate imported modules (#3231). [Robert Balas] * Fix false WIDTHEXPAND on array declarations (#3959). [JOTEGO] diff --git a/include/verilated.cpp b/include/verilated.cpp index dc23517cc..29fbf89ea 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -315,15 +315,28 @@ void VlRNG::srandom(uint64_t n) VL_MT_UNSAFE { if (VL_COUNTONES_I(m_state[0]) < 10) m_state[0] = ~m_state[0]; if (VL_COUNTONES_I(m_state[1]) < 10) m_state[1] = ~m_state[1]; } -// Unused: void VlRNG::set_randstate(const std::string& state) VL_MT_UNSAFE { -// Unused: if (VL_LIKELY(state.length() == sizeof(m_state))) { -// Unused: memcpy(m_state, state.data(), sizeof(m_state)); -// Unused: } -// Unused: } -// Unused: std::string VlRNG::get_randstate() const VL_MT_UNSAFE { -// Unused: std::string result{reinterpret_cast(&m_state), sizeof(m_state)}; -// Unused: return result; -// Unused: } +std::string VlRNG::get_randstate() const VL_MT_UNSAFE { + // Though not stated in IEEE, assumption is the string must be printable + const char* const stateCharsp = reinterpret_cast(&m_state); + static_assert(sizeof(m_state) == 16); + std::string result{"R00112233445566770011223344556677"}; + for (int i = 0; i < sizeof(m_state); ++i) { + result[1 + i * 2] = 'a' + ((stateCharsp[i] >> 4) & 15); + result[1 + i * 2 + 1] = 'a' + (stateCharsp[i] & 15); + } + return result; +} +void VlRNG::set_randstate(const std::string& state) VL_MT_UNSAFE { + if (VL_UNLIKELY((state.length() != 1 + 2 * sizeof(m_state)) || (state[0] != 'R'))) { + VL_PRINTF_MT("%%Warning: set_randstate ignored as state string not from get_randstate\n"); + return; + } + char* const stateCharsp = reinterpret_cast(&m_state); + for (int i = 0; i < sizeof(m_state); ++i) { + stateCharsp[i] + = (((state[1 + i * 2] - 'a') & 15) << 4) | ((state[1 + i * 2 + 1] - 'a') & 15); + } +} static uint32_t vl_sys_rand32() VL_MT_SAFE { // Return random 32-bits using system library. diff --git a/include/verilated_types.h b/include/verilated_types.h index 0214e8fb4..ab871ec84 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -161,8 +161,8 @@ public: VlRNG() VL_MT_SAFE; explicit VlRNG(uint64_t seed0) VL_MT_SAFE : m_state{0x12341234UL, seed0} {} void srandom(uint64_t n) VL_MT_UNSAFE; - // Unused: std::string get_randstate() const VL_MT_UNSAFE; - // Unused: void set_randstate(const std::string& state) VL_MT_UNSAFE; + std::string get_randstate() const VL_MT_UNSAFE; + void set_randstate(const std::string& state) VL_MT_UNSAFE; uint64_t rand64() VL_MT_UNSAFE; // Threadsafe, but requires use on vl_thread_rng static uint64_t vl_thread_rng_rand64() VL_MT_SAFE; diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index dabe702a0..ca1965964 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -3110,7 +3110,9 @@ private: } } else if (VN_IS(nodep, New) && m_statep->forPrearray()) { // Resolved in V3Width - } else if (nodep->name() == "randomize" || nodep->name() == "srandom") { + } else if (nodep->name() == "randomize" || nodep->name() == "srandom" + || nodep->name() == "get_randstate" + || nodep->name() == "set_randstate") { // Resolved in V3Width } else if (nodep->dotted() == "") { if (nodep->pli()) { diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 0d02e36a0..09f34f325 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2812,6 +2812,10 @@ private: return false; } + void visit(AstCExpr* nodep) override { + // Inserted by V3Width only so we know has been resolved + userIterateChildren(nodep, WidthVP{SELF, BOTH}.p()); + } void visit(AstCMethodHard* nodep) override { // Never created before V3Width, so no need to redo it UASSERT_OBJ(nodep->dtypep(), nodep, "CMETHODCALLs should have already been sized"); @@ -2878,7 +2882,7 @@ private: } return nullptr; } - void methodOkArguments(AstMethodCall* nodep, int minArg, int maxArg) { + void methodOkArguments(AstNodeFTaskRef* nodep, int minArg, int maxArg) { int narg = 0; for (AstNode* argp = nodep->pinsp(); argp; argp = argp->nextp()) { if (VN_IS(argp, With)) { @@ -3522,6 +3526,13 @@ private: processFTaskRefArgs(nodep); } return; + } else if (nodep->name() == "get_randstate" || nodep->name() == "set_randstate") { + // See implementations under AstNodeFTaskRef + nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'get_randstate'/'set_randstate' called " + "on object. Suggest call from inside class."); + nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::BitTrue{}}); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + return; } classp = classp->extendsp() ? classp->extendsp()->classp() : nullptr; } @@ -5537,7 +5548,9 @@ private: // For arguments, is assignment-like context; see IEEE rules in AstNodeAssign // Function hasn't been widthed, so make it so. UINFO(5, " FTASKREF " << nodep << endl); - if (nodep->name() == "randomize" || nodep->name() == "srandom") { + if (nodep->name() == "randomize" || nodep->name() == "srandom" + || (!nodep->taskp() + && (nodep->name() == "get_randstate" || nodep->name() == "set_randstate"))) { // TODO perhaps this should move to V3LinkDot if (!m_classp) { nodep->v3error("Calling implicit class method " << nodep->prettyNameQ() @@ -5548,8 +5561,35 @@ private: } if (nodep->name() == "randomize") { nodep->taskp(V3Randomize::newRandomizeFunc(m_classp)); - } else { + } else if (nodep->name() == "srandom") { nodep->taskp(V3Randomize::newSRandomFunc(m_classp)); + } else if (nodep->name() == "get_randstate") { + methodOkArguments(nodep, 0, 0); + m_classp->baseMostClassp()->needRNG(true); + v3Global.useRandomizeMethods(true); + AstCExpr* const newp + = new AstCExpr{nodep->fileline(), "__Vm_rng.get_randstate()", 1, true}; + newp->dtypeSetString(); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + return; + } else if (nodep->name() == "set_randstate") { + methodOkArguments(nodep, 1, 1); + AstNodeExpr* const expr1p = VN_AS(nodep->pinsp(), Arg)->exprp(); // May edit + iterateCheckString(nodep, "LHS", expr1p, BOTH); + AstNodeExpr* const exprp = VN_AS(nodep->pinsp(), Arg)->exprp(); + m_classp->baseMostClassp()->needRNG(true); + v3Global.useRandomizeMethods(true); + AstCExpr* const newp + = new AstCExpr{nodep->fileline(), "__Vm_rng.set_randstate(", 1, true}; + newp->addExprsp(exprp->unlinkFrBack()); + newp->addExprsp(new AstText{nodep->fileline(), ")", true}); + newp->dtypeSetString(); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + return; + } else { + UASSERT_OBJ(false, nodep, "Bad case"); } } UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked"); diff --git a/test_regress/t/t_randstate_func.pl b/test_regress/t/t_randstate_func.pl new file mode 100755 index 000000000..aabcde63e --- /dev/null +++ b/test_regress/t/t_randstate_func.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_randstate_func.v b/test_regress/t/t_randstate_func.v new file mode 100644 index 000000000..87563d1f4 --- /dev/null +++ b/test_regress/t/t_randstate_func.v @@ -0,0 +1,48 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Cls; + rand int length; + + function void test; + automatic int rand_result, v1, v2; + automatic string s; + + // UVM 2023 does a print, so check is ascii + $display("get_randstate = '%s'", get_randstate()); + + s = get_randstate(); + + rand_result = randomize(); + if (rand_result != 1) $stop; + v1 = length; + + set_randstate(s); + + rand_result = randomize(); + if (rand_result != 1) $stop; + v2 = length; + +`ifdef VERILATOR // About half of the other simulators fail at this + if (v1 != v2) $stop; +`endif + endfunction +endclass + +module t(/*AUTOARG*/); + + automatic int rand_result, v1, v2; + automatic string s; + + initial begin + Cls c; + c = new; + c.test; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_randstate_obj.out b/test_regress/t/t_randstate_obj.out new file mode 100644 index 000000000..74f858877 --- /dev/null +++ b/test_regress/t/t_randstate_obj.out @@ -0,0 +1,10 @@ +%Error-UNSUPPORTED: t/t_randstate_obj.v:20:13: Unsupported: 'get_randstate'/'set_randstate' called on object. Suggest call from inside class. + : ... In instance t + 20 | s = c.get_randstate(); + | ^~~~~~~~~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_randstate_obj.v:26:9: Unsupported: 'get_randstate'/'set_randstate' called on object. Suggest call from inside class. + : ... In instance t + 26 | c.set_randstate(s); + | ^~~~~~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_randstate_obj.pl b/test_regress/t/t_randstate_obj.pl new file mode 100755 index 000000000..b50a85167 --- /dev/null +++ b/test_regress/t/t_randstate_obj.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 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + expect_filename => $Self->{golden_filename}, + fails => $Self->{vlt_all}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_randstate_obj.v b/test_regress/t/t_randstate_obj.v new file mode 100644 index 000000000..bc5255913 --- /dev/null +++ b/test_regress/t/t_randstate_obj.v @@ -0,0 +1,39 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Cls; + rand int length; +endclass + +module t(/*AUTOARG*/); + + automatic int rand_result, v1, v2; + automatic string s; + + initial begin + Cls c; + c = new; + + s = c.get_randstate(); + + rand_result = c.randomize(); + if (rand_result != 1) $stop; + v1 = c.length; + + c.set_randstate(s); + + rand_result = c.randomize(); + if (rand_result != 1) $stop; + v2 = c.length; + +`ifdef VERILATOR // About half of the other simulators fail at this + if (v1 != v2) $stop; +`endif + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_randstate_seed_bad.out b/test_regress/t/t_randstate_seed_bad.out new file mode 100644 index 000000000..75e3250f6 --- /dev/null +++ b/test_regress/t/t_randstate_seed_bad.out @@ -0,0 +1,2 @@ +%Warning: set_randstate ignored as state string not from get_randstate +*-* All Finished *-* diff --git a/test_regress/t/t_randstate_seed_bad.pl b/test_regress/t/t_randstate_seed_bad.pl new file mode 100755 index 000000000..c7c7ef8ca --- /dev/null +++ b/test_regress/t/t_randstate_seed_bad.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +compile( + ); + +execute( + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_randstate_seed_bad.v b/test_regress/t/t_randstate_seed_bad.v new file mode 100644 index 000000000..ebcf2c0a9 --- /dev/null +++ b/test_regress/t/t_randstate_seed_bad.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, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Cls; + function void test; + automatic string s; + + s = get_randstate(); + // Vlt only result check + if (s[0] !== "R") $fatal(2, $sformatf("Bad get_randstate = '%s'", s)); + + set_randstate("000bad"); // Bad + endfunction +endclass + +module t(/*AUTOARG*/); + + initial begin + Cls c; + c = new; + c.test; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From 4bb876aee521be1359d9ec3dc60e06f9878b804d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 6 May 2023 19:48:22 -0400 Subject: [PATCH 028/129] Fix false IMPLICITSTATIC on package functions. --- Changes | 1 + docs/guide/warnings.rst | 11 ++++--- src/V3LinkParse.cpp | 37 +++++++++++++++-------- test_regress/t/t_func_no_lifetime_bad.out | 30 +++++++++++++----- test_regress/t/t_func_no_lifetime_bad.v | 28 ++++++++++++++--- 5 files changed, 79 insertions(+), 28 deletions(-) diff --git a/Changes b/Changes index cd044ae68..6b0380417 100644 --- a/Changes +++ b/Changes @@ -28,6 +28,7 @@ Verilator 5.011 devel * Fix linking AstRefDType if it has parameterized class ref (#4164) (#4170). [Ryszard Rozak, Antmicro Ltd] * Fix crash caused by $display() optimization (#4165) (#4166). [Tudor Timi] * Fix detection of wire/reg duplicates. +* Fix false IMPLICITSTATIC on package functions. Verilator 5.010 2023-04-30 diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst index fa131af70..5dc90fba4 100644 --- a/docs/guide/warnings.rst +++ b/docs/guide/warnings.rst @@ -769,11 +769,14 @@ List Of Warnings then automatic as static prevents the function from being reentrant, which may be a source of bugs, and/or performance issues. - If the function does not require static behavior, change it to "function - automatic". + If the function is in a module, and does not require static behavior, + change it to "function automatic". - If the function requires static behavior, change it to "function - static". + If the function is in a module, and requires static behavior, change it + to "function static". + + If the function is in a package, it defaults to static, and label the + function's variables as static. Ignoring this warning will only suppress the lint check; it will simulate correctly. diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index bc4af9391..9da829f30 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -124,13 +124,6 @@ private: && (VN_IS(nodep->stmtsp(), GenIf)) // Begin has if underneath && !nodep->stmtsp()->nextp()); // Has only one item } - bool hasStaticDeclAssignments(AstNodeFTask* nodep) { - for (const AstNode* itemp = nodep->stmtsp(); itemp; itemp = itemp->nextp()) { - const AstVar* const varp = VN_CAST(itemp, Var); - if (varp && varp->valuep() && !varp->lifetime().isAutomatic()) return true; - } - return false; - } // VISITs void visit(AstNodeFTask* nodep) override { @@ -156,12 +149,30 @@ private: // DPI-imported functions and properties don't have lifetime specifiers m_lifetime = VLifetime::NONE; } - if (m_lifetime.isStatic() && hasStaticDeclAssignments(nodep)) { - nodep->v3warn( - IMPLICITSTATIC, - "Function/task's lifetime implicitly set to static\n" - << nodep->warnMore() - << "... Suggest use 'function automatic' or 'function static'"); + for (AstNode* itemp = nodep->stmtsp(); itemp; itemp = itemp->nextp()) { + AstVar* const varp = VN_CAST(itemp, Var); + if (varp && varp->valuep() && varp->lifetime().isNone() + && m_lifetime.isStatic() && !varp->isIO()) { + if (VN_IS(m_modp, Module)) { + nodep->v3warn(IMPLICITSTATIC, + "Function/task's lifetime implicitly set to static\n" + << nodep->warnMore() + << "... Suggest use 'function automatic' or " + "'function static'\n" + << nodep->warnContextPrimary() << '\n' + << varp->warnOther() + << "... Location of implicit static variable\n" + << varp->warnContextSecondary() << '\n' + << "... Suggest use 'function automatic' or " + "'function static'"); + } else { + varp->v3warn(IMPLICITSTATIC, + "Variable's lifetime implicitly set to static\n" + << nodep->warnMore() + << "... Suggest use 'static' before " + "variable declaration'"); + } + } } nodep->lifetime(m_lifetime); } diff --git a/test_regress/t/t_func_no_lifetime_bad.out b/test_regress/t/t_func_no_lifetime_bad.out index ac2132066..bc145b029 100644 --- a/test_regress/t/t_func_no_lifetime_bad.out +++ b/test_regress/t/t_func_no_lifetime_bad.out @@ -1,11 +1,27 @@ -%Warning-IMPLICITSTATIC: t/t_func_no_lifetime_bad.v:7:14: Function/task's lifetime implicitly set to static - : ... Suggest use 'function automatic' or 'function static' - 7 | function int f_implicit_static(); - | ^~~~~~~~~~~~~~~~~ +%Warning-IMPLICITSTATIC: t/t_func_no_lifetime_bad.v:29:17: Function/task's lifetime implicitly set to static + : ... Suggest use 'function automatic' or 'function static' + 29 | function int f_implicit_static(); + | ^~~~~~~~~~~~~~~~~ + t/t_func_no_lifetime_bad.v:30:11: ... Location of implicit static variable + 30 | int cnt = 0; + | ^~~ +... Suggest use 'function automatic' or 'function static' ... For warning description see https://verilator.org/warn/IMPLICITSTATIC?v=latest ... Use "/* verilator lint_off IMPLICITSTATIC */" and lint_on around source to disable this message. -%Warning-IMPLICITSTATIC: t/t_func_no_lifetime_bad.v:12:6: Function/task's lifetime implicitly set to static +%Warning-IMPLICITSTATIC: t/t_func_no_lifetime_bad.v:34:9: Function/task's lifetime implicitly set to static : ... Suggest use 'function automatic' or 'function static' - 12 | task t_implicit_static(); - | ^~~~~~~~~~~~~~~~~ + 34 | task t_implicit_static(); + | ^~~~~~~~~~~~~~~~~ + t/t_func_no_lifetime_bad.v:35:11: ... Location of implicit static variable + 35 | int cnt = 0; + | ^~~ +... Suggest use 'function automatic' or 'function static' +%Warning-IMPLICITSTATIC: t/t_func_no_lifetime_bad.v:9:8: Variable's lifetime implicitly set to static + : ... Suggest use 'static' before variable declaration' + 9 | int cnt = 0; + | ^~~ +%Warning-IMPLICITSTATIC: t/t_func_no_lifetime_bad.v:15:8: Variable's lifetime implicitly set to static + : ... Suggest use 'static' before variable declaration' + 15 | int cnt = 0; + | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_func_no_lifetime_bad.v b/test_regress/t/t_func_no_lifetime_bad.v index e77979cf3..1c2fe0c2d 100644 --- a/test_regress/t/t_func_no_lifetime_bad.v +++ b/test_regress/t/t_func_no_lifetime_bad.v @@ -4,22 +4,38 @@ // any use, without warranty, 2023 by Antmicro Ltd. // SPDX-License-Identifier: CC0-1.0 -function int f_implicit_static(); - int cnt = 0; +// Not legal to put "static" here, so no warning +function int f_dunit_static(); + int cnt = 0; // Ok to require "static" here somehday return ++cnt; endfunction -task t_implicit_static(); - int cnt = 0; +// Not legal to put "static" here, so no warning +task t_dunit_static(); + int cnt = 0; // Ok to require "static" here somehday $display("%d", ++cnt); endtask +task t_dunit_static_ok(input int in_ok = 1); + static int cnt_ok = 0; // No warning here + $display("%d", ++cnt_ok); +endtask module t (/*AUTOARG*/ // Inputs clk ); + function int f_implicit_static(); + int cnt = 0; + return ++cnt; + endfunction + + task t_implicit_static(); + int cnt = 0; + $display("%d", ++cnt); + endtask + // verilator lint_off IMPLICITSTATIC function int f_implicit_but_lint_off(); int cnt = 0; @@ -30,6 +46,10 @@ module t (/*AUTOARG*/ int a, b; initial begin + a = f_dunit_static(); + t_dunit_static(); + t_dunit_static_ok(); + a = f_implicit_static(); t_implicit_static(); b = f_implicit_but_lint_off(); From c6052830e15f055a868352b89d753bee9265fac3 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 6 May 2023 20:23:35 -0400 Subject: [PATCH 029/129] Fix C++17 requirement on previous commit. --- include/verilated.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index 29fbf89ea..7b080f498 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -318,7 +318,7 @@ void VlRNG::srandom(uint64_t n) VL_MT_UNSAFE { std::string VlRNG::get_randstate() const VL_MT_UNSAFE { // Though not stated in IEEE, assumption is the string must be printable const char* const stateCharsp = reinterpret_cast(&m_state); - static_assert(sizeof(m_state) == 16); + static_assert(sizeof(m_state) == 16, ""); std::string result{"R00112233445566770011223344556677"}; for (int i = 0; i < sizeof(m_state); ++i) { result[1 + i * 2] = 'a' + ((stateCharsp[i] >> 4) & 15); From 0606a29f13c3fc272b46bc0b967f79330a217265 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 6 May 2023 21:41:17 -0400 Subject: [PATCH 030/129] Fix arrays of unpacked structs (#4173). --- Changes | 1 + src/V3AstNodeDType.h | 1 + src/V3AstNodes.cpp | 10 ++++++ src/V3Class.cpp | 6 ++-- src/V3Common.cpp | 1 + src/V3EmitCHeaders.cpp | 2 +- src/V3EmitCImp.cpp | 1 + test_regress/t/t_struct_nest_uarray.pl | 21 +++++++++++ test_regress/t/t_struct_nest_uarray.v | 48 ++++++++++++++++++++++++++ 9 files changed, 88 insertions(+), 3 deletions(-) create mode 100755 test_regress/t/t_struct_nest_uarray.pl create mode 100644 test_regress/t/t_struct_nest_uarray.v diff --git a/Changes b/Changes index 6b0380417..98018b690 100644 --- a/Changes +++ b/Changes @@ -27,6 +27,7 @@ Verilator 5.011 devel * Fix initialization order of initial static after function/task (#4159). [Kamil Rakoczy, Antmicro Ltd] * Fix linking AstRefDType if it has parameterized class ref (#4164) (#4170). [Ryszard Rozak, Antmicro Ltd] * Fix crash caused by $display() optimization (#4165) (#4166). [Tudor Timi] +* Fix arrays of unpacked structs (#4173). [Risto Pejašinović] * Fix detection of wire/reg duplicates. * Fix false IMPLICITSTATIC on package functions. diff --git a/src/V3AstNodeDType.h b/src/V3AstNodeDType.h index 10d90c33f..c06e761c0 100644 --- a/src/V3AstNodeDType.h +++ b/src/V3AstNodeDType.h @@ -887,6 +887,7 @@ public: if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); } AstNodeDType* getChildDTypep() const override { return childDTypep(); } + AstNodeUOrStructDType* getChildStructp() const; AstNodeDType* subDTypep() const override VL_MT_STABLE { return m_refDTypep ? m_refDTypep : childDTypep(); } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index e0b2f1b4f..46f5e53d7 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1671,10 +1671,19 @@ void AstLogOr::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); if (sideEffect()) str << " [SIDE]"; } + void AstMemberDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); str << "member"; } +AstNodeUOrStructDType* AstMemberDType::getChildStructp() const { + AstNodeDType* subdtp = skipRefp(); + while (AstNodeArrayDType* const asubdtp = VN_CAST(subdtp, NodeArrayDType)) { + subdtp = asubdtp->subDTypep(); + } + return VN_CAST(subdtp, NodeUOrStructDType); // Maybe nullptr +} + void AstMemberSel::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); str << " -> "; @@ -1831,6 +1840,7 @@ void AstNodeUOrStructDType::dump(std::ostream& str) const { this->AstNodeDType::dump(str); if (packed()) str << " [PACKED]"; if (isFourstate()) str << " [4STATE]"; + if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep()); } void AstNodeDType::dump(std::ostream& str) const { this->AstNode::dump(str); diff --git a/src/V3Class.cpp b/src/V3Class.cpp index 71cd260d3..f318048f8 100644 --- a/src/V3Class.cpp +++ b/src/V3Class.cpp @@ -62,6 +62,7 @@ private: AstClassPackage* const packagep = new AstClassPackage{nodep->fileline(), nodep->origName()}; packagep->name(nodep->name() + "__Vclpkg"); + nodep->editCountInc(); nodep->classOrPackagep(packagep); packagep->classp(nodep); v3Global.rootp()->addModulesp(packagep); @@ -177,14 +178,15 @@ private: } void setStructModulep(AstNodeUOrStructDType* const dtypep) { - // Give it a pointer to its package and a final name + // Give struct a pointer to its package and a final name + dtypep->editCountInc(); dtypep->classOrPackagep(m_classPackagep ? m_classPackagep : m_modp); dtypep->name(dtypep->name() + (VN_IS(dtypep, UnionDType) ? "__union" : "__struct") + cvtToStr(dtypep->uniqueNum())); for (const AstMemberDType* itemp = dtypep->membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) { - AstNodeUOrStructDType* const subp = VN_CAST(itemp->skipRefp(), NodeUOrStructDType); + AstNodeUOrStructDType* const subp = itemp->getChildStructp(); // Recurse only into anonymous unpacked structs inside this definition, // other unpacked structs will be reached from another typedefs if (subp && !subp->packed() && subp->name().empty()) setStructModulep(subp); diff --git a/src/V3Common.cpp b/src/V3Common.cpp index ed1570c51..25043d425 100644 --- a/src/V3Common.cpp +++ b/src/V3Common.cpp @@ -63,6 +63,7 @@ static void makeVlToString(AstIface* nodep) { } static void makeVlToString(AstNodeUOrStructDType* nodep) { AstNodeModule* const modp = nodep->classOrPackagep(); + UASSERT_OBJ(modp, nodep, "Unlinked struct package"); AstCFunc* const funcp = new AstCFunc{nodep->fileline(), "VL_TO_STRING", nullptr, "std::string"}; funcp->argTypes("const " + EmitCBase::prefixNameProtect(nodep) + "& obj"); diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp index 798006653..04eac47d7 100644 --- a/src/V3EmitCHeaders.cpp +++ b/src/V3EmitCHeaders.cpp @@ -219,7 +219,7 @@ class EmitCHeader final : public EmitCConstInit { emitted.insert(sdtypep); for (const AstMemberDType* itemp = sdtypep->membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) { - AstNodeUOrStructDType* subp = VN_CAST(itemp->skipRefp(), NodeUOrStructDType); + AstNodeUOrStructDType* const subp = itemp->getChildStructp(); if (subp && !subp->packed()) { // Recurse if it belongs to the current module if (subp->classOrPackagep() == modp) { diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index 5574613d6..f47b5bcf9 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -54,6 +54,7 @@ class EmitCGatherDependencies final : VNVisitorConst { } else if (const AstNodeUOrStructDType* const dtypep = VN_CAST(nodep, NodeUOrStructDType)) { if (!dtypep->packed()) { + UASSERT_OBJ(dtypep->classOrPackagep(), nodep, "Unlinked struct package"); m_dependencies.insert(EmitCBase::prefixNameProtect(dtypep->classOrPackagep())); } } diff --git a/test_regress/t/t_struct_nest_uarray.pl b/test_regress/t/t_struct_nest_uarray.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_struct_nest_uarray.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_struct_nest_uarray.v b/test_regress/t/t_struct_nest_uarray.v new file mode 100644 index 000000000..81cdeee3f --- /dev/null +++ b/test_regress/t/t_struct_nest_uarray.v @@ -0,0 +1,48 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); + +typedef struct { + struct { + struct { + logic [31:0] next; + } val; + } el[1]; +} pstr_t; + +module t (/*AUTOARG*/); + + typedef struct { + struct { + struct { + logic [31:0] next; + } val; + } el[1]; + } str_t; + + str_t str; + pstr_t pstr; + + initial begin + string s; + + str.el[0].val.next = 6; + s = $sformatf("%p", str); + $display("%s", s); + `checks(s, "'{el:'{'{val:'{next:'h6}}} }"); + + pstr.el[0].val.next = 6; + s = $sformatf("%p", pstr); + $display("%s", s); + `checks(s, "'{el:'{'{val:'{next:'h6}}} }"); + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From e6f5a0495f50f5f1583d223b9cc48642f44a45f5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 7 May 2023 08:25:10 -0400 Subject: [PATCH 031/129] Fix $fscanf of decimals overflowing variables (#4174). --- Changes | 1 + include/verilated.cpp | 10 ++++++---- src/V3EmitCFunc.h | 2 +- test_regress/t/t_sys_file_basic.v | 8 ++++++++ 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Changes b/Changes index 98018b690..c60a56374 100644 --- a/Changes +++ b/Changes @@ -28,6 +28,7 @@ Verilator 5.011 devel * Fix linking AstRefDType if it has parameterized class ref (#4164) (#4170). [Ryszard Rozak, Antmicro Ltd] * Fix crash caused by $display() optimization (#4165) (#4166). [Tudor Timi] * Fix arrays of unpacked structs (#4173). [Risto Pejašinović] +* Fix $fscanf of decimals overflowing variables (#4174). [Ahmed El-Mahmoudy] * Fix detection of wire/reg duplicates. * Fix false IMPLICITSTATIC on package functions. diff --git a/include/verilated.cpp b/include/verilated.cpp index 7b080f498..3b7a90de2 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -1373,16 +1373,18 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf *p = t_tmp; } else if (obits <= VL_BYTESIZE) { CData* const p = va_arg(ap, CData*); - *p = owp[0]; + *p = VL_CLEAN_II(obits, obits, owp[0]); } else if (obits <= VL_SHORTSIZE) { SData* const p = va_arg(ap, SData*); - *p = owp[0]; + *p = VL_CLEAN_II(obits, obits, owp[0]); } else if (obits <= VL_IDATASIZE) { IData* const p = va_arg(ap, IData*); - *p = owp[0]; + *p = VL_CLEAN_II(obits, obits, owp[0]); } else if (obits <= VL_QUADSIZE) { QData* const p = va_arg(ap, QData*); - *p = VL_SET_QW(owp); + *p = VL_CLEAN_QQ(obits, obits, VL_SET_QW(owp)); + } else { + _vl_clean_inplace_w(obits, owp); } } } // switch diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 1149c728f..540b1ea13 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -792,7 +792,7 @@ public: void visit(AstSysFuncAsTask* nodep) override { if (!nodep->lhsp()->isWide()) puts("(void)"); iterateAndNextConstNull(nodep->lhsp()); - if (!nodep->lhsp()->isWide()) puts(";"); + if (!nodep->lhsp()->isWide()) puts(";\n"); } void visit(AstStackTraceF* nodep) override { puts("VL_STACKTRACE_N()"); } void visit(AstStackTraceT* nodep) override { puts("VL_STACKTRACE();\n"); } diff --git a/test_regress/t/t_sys_file_basic.v b/test_regress/t/t_sys_file_basic.v index 7a0f0bda6..ac276d9a4 100644 --- a/test_regress/t/t_sys_file_basic.v +++ b/test_regress/t/t_sys_file_basic.v @@ -33,6 +33,9 @@ module t; integer v_length, v_off; + wire signed [16:0] wire17 = 17'h1ffff; + logic signed [16:0] scan17; + `ifdef TEST_VERBOSE `define verbose 1'b1 `else @@ -309,6 +312,11 @@ module t; $fclose(file); end + begin + $sscanf("-1", "%d", scan17); + if (scan17 !== wire17) $stop; + end + $write("*-* All Finished *-*\n"); $finish(0); // Test arguments to finish end From c2a524d80b71a6ff84ba8a01f79e2374b5fb28f5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 7 May 2023 08:36:03 -0400 Subject: [PATCH 032/129] Commentary (#4175) --- docs/guide/exe_verilator.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index 604db0702..5bc6c0474 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -1467,8 +1467,11 @@ Summary: them systematically. The generated file is in the Verilator Configuration format, see - :ref:`Configuration Files`, and can directly be consumed by - Verilator. The standard file extension is ".vlt". + :ref:`Configuration Files`. The standard file extension is ".vlt". + These files can directly be consumed by Verilator, typically by placing + the filename as part of the Verilator command line options. Waiver files + need to be listed on the command line before listing the files they are + waiving. .. option:: -Wall From 6188083baa3a36b654445db06dccf19535278632 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 7 May 2023 15:08:44 -0400 Subject: [PATCH 033/129] Tests: Improve randc tests --- test_regress/t/t_randc.out | 12 ++ test_regress/t/t_randc.pl | 19 +++ test_regress/t/t_randc.v | 125 ++++++++++++++++++ test_regress/t/t_randc_ignore_unsup.pl | 4 +- test_regress/t/t_randc_ignore_unsup.v | 38 ------ ...ndc_unsup.out => t_randc_oversize_bad.out} | 6 +- ...randc_unsup.pl => t_randc_oversize_bad.pl} | 0 ...t_randc_unsup.v => t_randc_oversize_bad.v} | 4 +- 8 files changed, 164 insertions(+), 44 deletions(-) create mode 100644 test_regress/t/t_randc.out create mode 100755 test_regress/t/t_randc.pl create mode 100644 test_regress/t/t_randc.v delete mode 100644 test_regress/t/t_randc_ignore_unsup.v rename test_regress/t/{t_randc_unsup.out => t_randc_oversize_bad.out} (59%) rename test_regress/t/{t_randc_unsup.pl => t_randc_oversize_bad.pl} (100%) rename test_regress/t/{t_randc_unsup.v => t_randc_oversize_bad.v} (73%) diff --git a/test_regress/t/t_randc.out b/test_regress/t/t_randc.out new file mode 100644 index 000000000..c42bb3bcf --- /dev/null +++ b/test_regress/t/t_randc.out @@ -0,0 +1,12 @@ +%Warning-RANDC: t/t_randc.v:8:26: Unsupported: Converting 'randc' to 'rand' + 8 | randc bit [WIDTH-1:0] m_var; + | ^~~~~ + ... For warning description see https://verilator.org/warn/RANDC?v=latest + ... Use "/* verilator lint_off RANDC */" and lint_on around source to disable this message. +%Warning-RANDC: t/t_randc.v:45:26: Unsupported: Converting 'randc' to 'rand' + 45 | randc bit [WIDTH-1:0] m_var; + | ^~~~~ +%Warning-RANDC: t/t_randc.v:74:17: Unsupported: Converting 'randc' to 'rand' + 74 | randc enum_t m_var; + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_randc.pl b/test_regress/t/t_randc.pl new file mode 100755 index 000000000..66fa61649 --- /dev/null +++ b/test_regress/t/t_randc.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 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_randc.v b/test_regress/t/t_randc.v new file mode 100644 index 000000000..e03ce4137 --- /dev/null +++ b/test_regress/t/t_randc.v @@ -0,0 +1,125 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class ClsNarrow #(parameter int WIDTH); + randc bit [WIDTH-1:0] m_var; + + function void test; + automatic int i; + automatic int count[2**WIDTH]; + automatic int maxcount; + automatic bit bad; + automatic int randomize_result; + for (int trial = 0; trial < 10; ++trial) begin + for (i = 0; i < (2 ** WIDTH); ++i) begin + randomize_result = randomize(); + if (randomize_result !== 1) $stop; +`ifdef TEST_VERBOSE + $display("w%0d trial=%0d m_var=%0d", WIDTH, i, m_var); +`endif + ++count[m_var]; + end + end + maxcount = count[0]; + bad = '0; +`ifndef TEST_IGNORE_RANDC + for (i = 0; i < (2 ** WIDTH); ++i) begin + if (maxcount != count[i]) bad = '1; + end +`endif + if (bad) begin + $display("%%Error: count mismatch"); + for (i = 0; i < (2 ** WIDTH); ++i) begin + $display("w%0d entry[%0d]=%0d", WIDTH, i, count[i]); + end + $stop; + end + endfunction + +endclass + +class ClsWide #(parameter int WIDTH); + randc bit [WIDTH-1:0] m_var; + + function void test; + automatic bit [WIDTH-1:0] last; + automatic int randomize_result; + for (int i = 0; i < 100; ++i) begin + randomize_result = randomize(); + if (randomize_result !== 1) $stop; +`ifdef TEST_VERBOSE + $display("ww%0d m_var=%0d", WIDTH, i, m_var); +`endif + if (i != 0) begin +`ifndef TEST_IGNORE_RANDC + if (m_var == last) $stop; +`endif + end + last = m_var; + end + endfunction + +endclass + +class ClsEnum; + typedef enum bit [3:0] { + TWO = 2, + FIVE = 5, + SIX = 6 + } enum_t; + + randc enum_t m_var; + + function void test; + automatic enum_t last; + automatic int randomize_result; + for (int trial = 0; trial < 10; ++trial) begin + for (int i = 0; i < 3; ++i) begin + randomize_result = randomize(); + if (randomize_result !== 1) $stop; +`ifdef TEST_VERBOSE + $display("we trial=%0d m_var=%0d", i, m_var); +`endif + if (m_var != TWO && m_var != FIVE && m_var != SIX) $stop; + if (i != 0) begin +`ifndef TEST_IGNORE_RANDC + if (m_var == last) $stop; +`endif + end + last = m_var; + end + end + endfunction + +endclass + +module t (/*AUTOARG*/); + + ClsNarrow #(1) c1; // Degenerate case + ClsNarrow #(2) c2; + ClsNarrow #(9) c9; + ClsWide #(31) c31; + ClsWide #(32) c32; + ClsEnum ce; + + initial begin + c1 = new; + c1.test(); + c2 = new; + c2.test(); + c9 = new; + c9.test(); + c31 = new; + c31.test(); + c32 = new; + c32.test(); + ce = new; + ce.test(); + $write("*-* All Finished *-*\n"); + $finish(); + end + +endmodule diff --git a/test_regress/t/t_randc_ignore_unsup.pl b/test_regress/t/t_randc_ignore_unsup.pl index a161852b1..af711b6c9 100755 --- a/test_regress/t/t_randc_ignore_unsup.pl +++ b/test_regress/t/t_randc_ignore_unsup.pl @@ -10,8 +10,10 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); +top_filename("t/t_randc.v"); + compile( - verilator_flags2 => ['-Wno-RANDC'], + verilator_flags2 => ['-Wno-RANDC -DTEST_IGNORE_RANDC'], ); execute( diff --git a/test_regress/t/t_randc_ignore_unsup.v b/test_regress/t/t_randc_ignore_unsup.v deleted file mode 100644 index a2087e6b0..000000000 --- a/test_regress/t/t_randc_ignore_unsup.v +++ /dev/null @@ -1,38 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2019 by Wilson Snyder. -// SPDX-License-Identifier: CC0-1.0 - -class Cls; - randc int i; - - function new; - i = 0; - endfunction - -endclass - -module t (/*AUTOARG*/); - bit ok = 0; - - Cls obj; - - initial begin - int rand_result; - int prev_i; - for (int i = 0; i < 10; i++) begin - obj = new; - rand_result = obj.randomize(); - if (i > 0 && obj.i != prev_i) begin - ok = 1; - end - prev_i = obj.i; - end - if (ok) begin - $write("*-* All Finished *-*\n"); - $finish; - end - else $stop; - end -endmodule diff --git a/test_regress/t/t_randc_unsup.out b/test_regress/t/t_randc_oversize_bad.out similarity index 59% rename from test_regress/t/t_randc_unsup.out rename to test_regress/t/t_randc_oversize_bad.out index 7d3436a4a..293258c1f 100644 --- a/test_regress/t/t_randc_unsup.out +++ b/test_regress/t/t_randc_oversize_bad.out @@ -1,6 +1,6 @@ -%Warning-RANDC: t/t_randc_unsup.v:8:14: Unsupported: Converting 'randc' to 'rand' - 8 | randc int i; - | ^ +%Warning-RANDC: t/t_randc_oversize_bad.v:8:21: Unsupported: Converting 'randc' to 'rand' + 8 | randc bit [33:0] i; + | ^ ... For warning description see https://verilator.org/warn/RANDC?v=latest ... Use "/* verilator lint_off RANDC */" and lint_on around source to disable this message. %Error: Exiting due to diff --git a/test_regress/t/t_randc_unsup.pl b/test_regress/t/t_randc_oversize_bad.pl similarity index 100% rename from test_regress/t/t_randc_unsup.pl rename to test_regress/t/t_randc_oversize_bad.pl diff --git a/test_regress/t/t_randc_unsup.v b/test_regress/t/t_randc_oversize_bad.v similarity index 73% rename from test_regress/t/t_randc_unsup.v rename to test_regress/t/t_randc_oversize_bad.v index 1a966261a..852f4743c 100644 --- a/test_regress/t/t_randc_unsup.v +++ b/test_regress/t/t_randc_oversize_bad.v @@ -1,11 +1,11 @@ // DESCRIPTION: Verilator: Verilog Test module // // This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2019 by Wilson Snyder. +// any use, without warranty, 2023 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 class Cls; - randc int i; + randc bit [33:0] i; endclass module t (/*AUTOARG*/); From 444020f7c763d2d00b670fceba46813fab521553 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 7 May 2023 16:47:34 -0400 Subject: [PATCH 034/129] Fix super.new missing data type (#4147). --- Changes | 1 + src/V3Width.cpp | 4 +++- test_regress/t/t_class_super_new2.pl | 21 +++++++++++++++++++ test_regress/t/t_class_super_new2.v | 31 ++++++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 1 deletion(-) create mode 100755 test_regress/t/t_class_super_new2.pl create mode 100644 test_regress/t/t_class_super_new2.v diff --git a/Changes b/Changes index c60a56374..ab0807c71 100644 --- a/Changes +++ b/Changes @@ -29,6 +29,7 @@ Verilator 5.011 devel * Fix crash caused by $display() optimization (#4165) (#4166). [Tudor Timi] * Fix arrays of unpacked structs (#4173). [Risto Pejašinović] * Fix $fscanf of decimals overflowing variables (#4174). [Ahmed El-Mahmoudy] +* Fix super.new missing data type (#4147). [Tudor Timi] * Fix detection of wire/reg duplicates. * Fix false IMPLICITSTATIC on package functions. diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 09f34f325..fec2ab39b 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -3755,7 +3755,9 @@ private: void visit(AstNew* nodep) override { if (nodep->didWidth()) return; AstClass* classp = nullptr; + bool assign = false; if (VN_IS(nodep->backp(), Assign)) { // assignment case + assign = true; AstClassRefDType* const refp = m_vup ? VN_CAST(m_vup->dtypeNullSkipRefp(), ClassRefDType) : nullptr; if (!refp) { // e.g. int a = new; @@ -3783,9 +3785,9 @@ private: classp = VN_CAST(nodep->classOrPackagep(), Class); UASSERT_OBJ(classp, nodep, "Unlinked classOrPackagep()"); UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked taskp()"); - nodep->dtypeFrom(nodep->taskp()); } userIterate(nodep->taskp(), nullptr); + if (!assign) nodep->dtypeFrom(nodep->taskp()); processFTaskRefArgs(nodep); } void visit(AstNewCopy* nodep) override { diff --git a/test_regress/t/t_class_super_new2.pl b/test_regress/t/t_class_super_new2.pl new file mode 100755 index 000000000..859050d63 --- /dev/null +++ b/test_regress/t/t_class_super_new2.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 2023 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_super_new2.v b/test_regress/t/t_class_super_new2.v new file mode 100644 index 000000000..95a01b683 --- /dev/null +++ b/test_regress/t/t_class_super_new2.v @@ -0,0 +1,31 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Tudor Timi. +// SPDX-License-Identifier: CC0-1.0 + +class svunit_base; + function new(string name); + endfunction +endclass + +class svunit_testcase extends svunit_base; + function new(string name); + super.new(name); + endfunction +endclass + +module dut_unit_test; + svunit_testcase svunit_ut = new("dut_ut"); +endmodule + +module t(/*AUTOARG*/); + + dut_unit_test dut_ut(); + + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From d269fbb4460ea38ef91a4f0e1344dbadaace5a6c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 7 May 2023 17:58:14 -0400 Subject: [PATCH 035/129] Add creating __inputs.vpp file with --debug (#4177). --- Changes | 1 + docs/guide/files.rst | 6 ++- docs/internals.rst | 15 ++++++- src/V3ParseImp.cpp | 71 ++++++++++++++++++++++--------- src/V3ParseImp.h | 3 +- src/V3Stats.h | 2 + src/V3StatsReport.cpp | 23 +++++----- test_regress/t/t_debug_inputs.pl | 22 ++++++++++ test_regress/t/t_debug_inputs.v | 11 +++++ test_regress/t/t_debug_inputs_a.v | 9 ++++ test_regress/t/t_debug_inputs_b.v | 9 ++++ 11 files changed, 134 insertions(+), 38 deletions(-) create mode 100755 test_regress/t/t_debug_inputs.pl create mode 100644 test_regress/t/t_debug_inputs.v create mode 100644 test_regress/t/t_debug_inputs_a.v create mode 100644 test_regress/t/t_debug_inputs_b.v diff --git a/Changes b/Changes index ab0807c71..518265821 100644 --- a/Changes +++ b/Changes @@ -19,6 +19,7 @@ Verilator 5.011 devel **Minor:** * Support get_randstate/set_randstate class method function. +* Add creating __inputs.vpp file with --debug (#4177). [Tudor Timi] * Optimize VPI callValueCbs (#4155). [Hennadii Chernyshchyk] * Fix crash on duplicate imported modules (#3231). [Robert Balas] * Fix false WIDTHEXPAND on array declarations (#3959). [JOTEGO] diff --git a/docs/guide/files.rst b/docs/guide/files.rst index d34ea6aa7..219979350 100644 --- a/docs/guide/files.rst +++ b/docs/guide/files.rst @@ -126,8 +126,10 @@ In specific debug and other modes, it also creates: - Debugging graph files (from --debug) * - *{prefix}{misc}*\ .tree - Debugging files (from --debug) - * - {mod_prefix}_{each_verilog_base_filename}*\ .vpp - - Pre-processed verilog (from --debug) + * - *{prefix}*\ __inputs\ .vpp + - Pre-processed verilog for all files (from --debug) + * - *{prefix}*\ _ *{each_verilog_base_filename}*\ .vpp + - Pre-processed verilog for each file (from --debug) After running Make, the C++ compiler may produce the following: diff --git a/docs/internals.rst b/docs/internals.rst index c055aae8c..ecd9dc5f2 100644 --- a/docs/internals.rst +++ b/docs/internals.rst @@ -1503,8 +1503,19 @@ debug level 5, with the V3Width.cpp file at level 9. --debug ------- -When you run with ``--debug``, there are two primary output file types -placed into the obj_dir, .tree and .dot files. +When you run with ``--debug``, there are three primary output file types +placed into the obj_dir, .vpp, .tree and .dot files. + +.vpp Output +----------- + +Verilator creates a *{mod_prefix}*\ __inputs\ .vpp file containing all the +files that were read, filtered by preprocessing. This file can be fed back +into Verilator, replacing on the command line all of the previous input +files, to enable simplification of test cases. + +Verilator also creates .vpp files for each individual file passed on the +command line. .dot Output diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index cbf1808d5..c7e2e62b4 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -35,6 +35,7 @@ #include "V3Os.h" #include "V3ParseBison.h" // Generated by bison #include "V3PreShell.h" +#include "V3Stats.h" #include @@ -247,24 +248,22 @@ size_t V3ParseImp::ppInputToLex(char* buf, size_t max_size) { return got; } -void V3ParseImp::preprocDumps(std::ostream& os) { - if (v3Global.opt.dumpDefines()) { - V3PreShell::dumpDefines(os); - } else { - const bool noblanks = v3Global.opt.preprocOnly() && v3Global.opt.preprocNoLine(); - for (auto& buf : m_ppBuffers) { - if (noblanks) { - bool blank = true; - for (string::iterator its = buf.begin(); its != buf.end(); ++its) { - if (!std::isspace(*its) && *its != '\n') { - blank = false; - break; - } +void V3ParseImp::preprocDumps(std::ostream& os, bool forInputs) { + bool noblanks = forInputs || (v3Global.opt.preprocOnly() && v3Global.opt.preprocNoLine()); + bool nolines = forInputs; + for (auto& buf : m_ppBuffers) { + if (noblanks) { + bool blank = true; + for (string::iterator its = buf.begin(); its != buf.end(); ++its) { + if (!std::isspace(*its) && *its != '\n') { + blank = false; + break; } - if (blank) continue; } - os << buf; + if (blank) continue; + if (nolines && buf.rfind("`line ", 0) == 0) continue; } + os << buf; } } @@ -292,7 +291,7 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i if (v3Global.opt.preprocOnly() || v3Global.opt.keepTempFiles()) { // Create output file with all the preprocessor output we buffered up const string vppfilename = v3Global.opt.hierTopDataDir() + "/" + v3Global.opt.prefix() - + "_" + nondirname + ".vpp"; + + "__" + nondirname + ".vpp"; std::ofstream* ofp = nullptr; std::ostream* osp; if (v3Global.opt.preprocOnly()) { @@ -303,15 +302,20 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i if (osp->fail()) { fileline->v3error("Cannot write preprocessor output: " + vppfilename); return; + } + if (v3Global.opt.dumpDefines()) { + V3PreShell::dumpDefines(*osp); } else { - preprocDumps(*osp); - if (ofp) { - ofp->close(); - VL_DO_DANGLING(delete ofp, ofp); - } + preprocDumps(*osp, false); + } + if (ofp) { + ofp->close(); + VL_DO_DANGLING(delete ofp, ofp); } } + if (debug() && modfilename != V3Options::getStdPackagePath()) dumpInputsFile(); + // Parse it if (!v3Global.opt.preprocOnly()) { lexFile(modfilename); @@ -320,6 +324,31 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i } } +void V3ParseImp::dumpInputsFile() { + // Create output file with joined preprocessor output we buffered up, + // Useful for debug to feed back into Verilator + static bool append = false; + const string vppfilename + = v3Global.opt.hierTopDataDir() + "/" + v3Global.opt.prefix() + "__inputs.vpp"; + std::ofstream* ofp = V3File::new_ofstream(vppfilename, append); + if (ofp->fail()) { + v3error("Cannot write preprocessor output: " + vppfilename); + return; + } + if (!append) { + append = true; + UINFO(1, "Writing all preprocessed output to " << vppfilename << endl); + *ofp << "// Dump of all post-preprocessor input\n"; + *ofp << "// Blank lines and `line directives have been removed\n"; + *ofp << "//\n"; + V3Stats::infoHeader(*ofp, "// "); + } + *ofp << "\n"; + preprocDumps(*ofp, true); + ofp->close(); + VL_DO_DANGLING(delete ofp, ofp); +} + void V3ParseImp::lexFile(const string& modname) { // Prepare for lexing UINFO(3, "Lexing " << modname << endl); diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index e1037b130..bba341102 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -295,6 +295,7 @@ public: void parseFile(FileLine* fileline, const string& modfilename, bool inLibrary, const string& errmsg); + void dumpInputsFile(); private: void lexFile(const string& modname); @@ -305,7 +306,7 @@ private: size_t tokenPipeScanParam(size_t depth); size_t tokenPipeScanType(size_t depth); const V3ParseBisonYYSType* tokenPeekp(size_t depth); - void preprocDumps(std::ostream& os); + void preprocDumps(std::ostream& os, bool forInputs); }; #endif // Guard diff --git a/src/V3Stats.h b/src/V3Stats.h index fb56fbfe8..97c61050b 100644 --- a/src/V3Stats.h +++ b/src/V3Stats.h @@ -121,6 +121,8 @@ public: static void statsFinalAll(AstNetlist* nodep); /// Called by the top level to dump the statistics static void statsReport(); + /// Called by debug dumps + static void infoHeader(std::ofstream& os, const string& prefix); }; #endif // Guard diff --git a/src/V3StatsReport.cpp b/src/V3StatsReport.cpp index d72f13c1c..c725a40f5 100644 --- a/src/V3StatsReport.cpp +++ b/src/V3StatsReport.cpp @@ -40,18 +40,8 @@ class StatsReport final { std::ofstream& os; ///< Output stream static StatColl s_allStats; ///< All statistics - void header() { - os << "Verilator Statistics Report\n\n"; - - os << "Information:\n"; - os << " " << V3Options::version() << '\n'; - os << " Arguments: " << v3Global.opt.allArgsString() << '\n'; - os << " Build jobs: " << v3Global.opt.buildJobs() << '\n'; - os << " Verilate jobs: " << v3Global.opt.verilateJobs() << '\n'; - os << '\n'; - } - void sumit() { + os << '\n'; // If sumit is set on a statistic, combine with others of same name std::multimap byName; // * is always first @@ -179,7 +169,8 @@ public: // CONSTRUCTORS explicit StatsReport(std::ofstream* aofp) : os(*aofp) { // Need () or GCC 4.8 false warning - header(); + os << "Verilator Statistics Report\n\n"; + V3Stats::infoHeader(os, ""); sumit(); stars(); stages(); @@ -222,6 +213,14 @@ void V3Stats::statsStage(const string& name) { V3Stats::addStatPerf("Stage, Memory (MB), " + digitName, memory); } +void V3Stats::infoHeader(std::ofstream& os, const string& prefix) { + os << prefix << "Information:\n"; + os << prefix << " " << V3Options::version() << '\n'; + os << prefix << " Arguments: " << v3Global.opt.allArgsString() << '\n'; + os << prefix << " Build jobs: " << v3Global.opt.buildJobs() << '\n'; + os << prefix << " Verilate jobs: " << v3Global.opt.verilateJobs() << '\n'; +} + void V3Stats::statsReport() { UINFO(2, __FUNCTION__ << ": " << endl); diff --git a/test_regress/t/t_debug_inputs.pl b/test_regress/t/t_debug_inputs.pl new file mode 100755 index 000000000..9b9054d09 --- /dev/null +++ b/test_regress/t/t_debug_inputs.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +lint( + v_flags => ["--debug --debugi 1 -Wno-MULTITOP t/t_debug_inputs_b.v"], + ); + +file_grep("$Self->{obj_dir}/V$Self->{name}__inputs.vpp", qr/module t_debug_inputs /); +file_grep("$Self->{obj_dir}/V$Self->{name}__inputs.vpp", qr/module t_debug_inputs_a /); +file_grep("$Self->{obj_dir}/V$Self->{name}__inputs.vpp", qr/module t_debug_inputs_b /); + +ok(1); +1; diff --git a/test_regress/t/t_debug_inputs.v b/test_regress/t/t_debug_inputs.v new file mode 100644 index 000000000..0e4f4c44d --- /dev/null +++ b/test_regress/t/t_debug_inputs.v @@ -0,0 +1,11 @@ +// DESCRIPTION: Verilator: Dotted reference that uses another dotted reference +// as the select expression +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`include "t/t_debug_inputs_a.v" + +module t_debug_inputs (/*AUTOARG*/); +endmodule diff --git a/test_regress/t/t_debug_inputs_a.v b/test_regress/t/t_debug_inputs_a.v new file mode 100644 index 000000000..7754ce73a --- /dev/null +++ b/test_regress/t/t_debug_inputs_a.v @@ -0,0 +1,9 @@ +// DESCRIPTION: Verilator: Dotted reference that uses another dotted reference +// as the select expression +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t_debug_inputs_a (/*AUTOARG*/); +endmodule diff --git a/test_regress/t/t_debug_inputs_b.v b/test_regress/t/t_debug_inputs_b.v new file mode 100644 index 000000000..7321188ab --- /dev/null +++ b/test_regress/t/t_debug_inputs_b.v @@ -0,0 +1,9 @@ +// DESCRIPTION: Verilator: Dotted reference that uses another dotted reference +// as the select expression +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t_debug_inputs_b (/*AUTOARG*/); +endmodule From c0490627bf91ef0dc3438b1ae507b7e66aa39d7a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 7 May 2023 22:00:52 -0400 Subject: [PATCH 036/129] Tests: Update historical --- test_regress/t/t_lint_historical.v | 18 ++++++++++++++---- test_regress/t/t_randc.out | 8 ++++---- test_regress/t/t_randc.v | 15 ++++++++++++--- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/test_regress/t/t_lint_historical.v b/test_regress/t/t_lint_historical.v index b1c1caf24..95f11bcc2 100644 --- a/test_regress/t/t_lint_historical.v +++ b/test_regress/t/t_lint_historical.v @@ -7,6 +7,7 @@ module t; // Test all warnings, including those that are historically removed still parse // verilator lint_off ALWCOMBORDER + // verilator lint_off ASCRANGE // verilator lint_off ASSIGNDLY // verilator lint_off ASSIGNIN // verilator lint_off BADSTDPRAGMA @@ -24,13 +25,14 @@ module t; // verilator lint_off CMPCONST // verilator lint_off COLONPLUS // verilator lint_off COMBDLY + // verilator lint_off CONSTRAINTIGN // verilator lint_off CONTASSREG - // verilator lint_off DEFPARAM // verilator lint_off DECLFILENAME + // verilator lint_off DEFPARAM // verilator lint_off DEPRECATED - // verilator lint_off RISEFALLDLY - // verilator lint_off MINTYPMAXDLY + // verilator lint_off ENCAPSULATED // verilator lint_off ENDLABEL + // verilator lint_off ENUMVALUE // verilator lint_off EOFNEWLINE // verilator lint_off GENCLK // verilator lint_off HIERBLOCK @@ -38,6 +40,7 @@ module t; // verilator lint_off IGNOREDRETURN // verilator lint_off IMPERFECTSCH // verilator lint_off IMPLICIT + // verilator lint_off IMPLICITSTATIC // verilator lint_off IMPORTSTAR // verilator lint_off IMPURE // verilator lint_off INCABSPATH @@ -45,10 +48,12 @@ module t; // verilator lint_off INITIALDLY // verilator lint_off INSECURE // verilator lint_off LATCH - // verilator lint_off ASCRANGE + // verilator lint_off LITENDIAN + // verilator lint_off MINTYPMAXDLY // verilator lint_off MODDUP // verilator lint_off MULTIDRIVEN // verilator lint_off MULTITOP + // verilator lint_off NEWERSTD // verilator lint_off NOLATCH // verilator lint_off NULLPORT // verilator lint_off PINCONNECTEMPTY @@ -62,9 +67,11 @@ module t; // verilator lint_off RANDC // verilator lint_off REALCVT // verilator lint_off REDEFMACRO + // verilator lint_off RISEFALLDLY // verilator lint_off SELRANGE // verilator lint_off SHORTREAL // verilator lint_off SPLITVAR + // verilator lint_off STATICVAR // verilator lint_off STMTDLY // verilator lint_off SYMRSVDWORD // verilator lint_off SYNCASYNCNET @@ -87,6 +94,9 @@ module t; // verilator lint_off WAITCONST // verilator lint_off WIDTH // verilator lint_off WIDTHCONCAT + // verilator lint_off WIDTHEXPAND + // verilator lint_off WIDTHTRUNC + // verilator lint_off WIDTHXZEXPAND // verilator lint_off ZERODLY endmodule diff --git a/test_regress/t/t_randc.out b/test_regress/t/t_randc.out index c42bb3bcf..f83777149 100644 --- a/test_regress/t/t_randc.out +++ b/test_regress/t/t_randc.out @@ -3,10 +3,10 @@ | ^~~~~ ... For warning description see https://verilator.org/warn/RANDC?v=latest ... Use "/* verilator lint_off RANDC */" and lint_on around source to disable this message. -%Warning-RANDC: t/t_randc.v:45:26: Unsupported: Converting 'randc' to 'rand' - 45 | randc bit [WIDTH-1:0] m_var; +%Warning-RANDC: t/t_randc.v:46:26: Unsupported: Converting 'randc' to 'rand' + 46 | randc bit [WIDTH-1:0] m_var; | ^~~~~ -%Warning-RANDC: t/t_randc.v:74:17: Unsupported: Converting 'randc' to 'rand' - 74 | randc enum_t m_var; +%Warning-RANDC: t/t_randc.v:76:17: Unsupported: Converting 'randc' to 'rand' + 76 | randc enum_t m_var; | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_randc.v b/test_regress/t/t_randc.v index e03ce4137..683cb996c 100644 --- a/test_regress/t/t_randc.v +++ b/test_regress/t/t_randc.v @@ -13,12 +13,13 @@ class ClsNarrow #(parameter int WIDTH); automatic int maxcount; automatic bit bad; automatic int randomize_result; + $display("Test %m"); for (int trial = 0; trial < 10; ++trial) begin for (i = 0; i < (2 ** WIDTH); ++i) begin randomize_result = randomize(); if (randomize_result !== 1) $stop; `ifdef TEST_VERBOSE - $display("w%0d trial=%0d m_var=%0d", WIDTH, i, m_var); + $display("w%0d i=%0d m_var=%x", WIDTH, i, m_var); `endif ++count[m_var]; end @@ -47,11 +48,12 @@ class ClsWide #(parameter int WIDTH); function void test; automatic bit [WIDTH-1:0] last; automatic int randomize_result; + $display("Test %m"); for (int i = 0; i < 100; ++i) begin randomize_result = randomize(); if (randomize_result !== 1) $stop; `ifdef TEST_VERBOSE - $display("ww%0d m_var=%0d", WIDTH, i, m_var); + $display("ww%0d i=%0d m_var=%x", WIDTH, i, m_var); `endif if (i != 0) begin `ifndef TEST_IGNORE_RANDC @@ -76,12 +78,13 @@ class ClsEnum; function void test; automatic enum_t last; automatic int randomize_result; + $display("Test %m"); for (int trial = 0; trial < 10; ++trial) begin for (int i = 0; i < 3; ++i) begin randomize_result = randomize(); if (randomize_result !== 1) $stop; `ifdef TEST_VERBOSE - $display("we trial=%0d m_var=%0d", i, m_var); + $display("we i=%0d m_var=%x", i, m_var); `endif if (m_var != TWO && m_var != FIVE && m_var != SIX) $stop; if (i != 0) begin @@ -100,6 +103,8 @@ module t (/*AUTOARG*/); ClsNarrow #(1) c1; // Degenerate case ClsNarrow #(2) c2; + ClsNarrow #(3) c3; + ClsNarrow #(3) c3b; // Need to have two of same size to cover dtype dedup code ClsNarrow #(9) c9; ClsWide #(31) c31; ClsWide #(32) c32; @@ -110,6 +115,10 @@ module t (/*AUTOARG*/); c1.test(); c2 = new; c2.test(); + c3 = new; + c3.test(); + c3b = new; + c3b.test(); c9 = new; c9.test(); c31 = new; From befb415f278af51fc3ecc3dda1dfe820de023bd1 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 7 May 2023 22:31:31 -0400 Subject: [PATCH 037/129] Fix mod/div/round argument side effects --- include/verilated_funcs.h | 19 +++++++++++++++---- include/verilatedos.h | 12 ++++++++++-- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index 983f19b4c..ec5ff4eb3 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -152,9 +152,11 @@ extern const char* vl_mc_scan_plusargs(const char* prefixp) VL_MT_SAFE; // PLIi // Base macros // Return true if data[bit] set; not 0/1 return, but 0/non-zero return. +// Arguments must not have side effects #define VL_BITISSETLIMIT_W(data, width, bit) (((bit) < (width)) && VL_BITISSET_W(data, bit)) // Shift appropriate word by bit. Does not account for wrapping between two words +// Argument 'bit' must not have side effects #define VL_BITRSHIFT_W(data, bit) ((data)[VL_BITWORD_E(bit)] >> VL_BITBIT_E(bit)) // Create two 32-bit words from quadword @@ -758,6 +760,7 @@ static inline IData VL_ONEHOT0_W(int words, WDataInP const lwp) VL_PURE { static inline IData VL_CLOG2_I(IData lhs) VL_PURE { // There are faster algorithms, or fls GCC4 builtins, but rarely used + // In C++20 there will be std::bit_width(lhs) - 1 if (VL_UNLIKELY(!lhs)) return 0; --lhs; int shifts = 0; @@ -953,11 +956,19 @@ static inline void VL_NEGATE_INPLACE_W(int words, WDataOutP owp_lwp) VL_MT_SAFE // EMIT_RULE: VL_MUL: oclean=dirty; lclean==clean; rclean==clean; // EMIT_RULE: VL_DIV: oclean=dirty; lclean==clean; rclean==clean; // EMIT_RULE: VL_MODDIV: oclean=dirty; lclean==clean; rclean==clean; -#define VL_DIV_III(lbits, lhs, rhs) (((rhs) == 0) ? 0 : (lhs) / (rhs)) -#define VL_DIV_QQQ(lbits, lhs, rhs) (((rhs) == 0) ? 0 : (lhs) / (rhs)) +static inline IData VL_DIV_III(int lbits, IData lhs, IData rhs) { + return (rhs == 0) ? 0 : lhs / rhs; +} +static inline QData VL_DIV_QQQ(int lbits, QData lhs, QData rhs) { + return (rhs == 0) ? 0 : lhs / rhs; +} #define VL_DIV_WWW(lbits, owp, lwp, rwp) (_vl_moddiv_w(lbits, owp, lwp, rwp, 0)) -#define VL_MODDIV_III(lbits, lhs, rhs) (((rhs) == 0) ? 0 : (lhs) % (rhs)) -#define VL_MODDIV_QQQ(lbits, lhs, rhs) (((rhs) == 0) ? 0 : (lhs) % (rhs)) +static inline IData VL_MODDIV_III(int lbits, IData lhs, IData rhs) { + return (rhs == 0) ? 0 : lhs % rhs; +} +static inline QData VL_MODDIV_QQQ(int lbits, QData lhs, QData rhs) { + return (rhs == 0) ? 0 : lhs % rhs; +} #define VL_MODDIV_WWW(lbits, owp, lwp, rwp) (_vl_moddiv_w(lbits, owp, lwp, rwp, 1)) static inline WDataOutP VL_ADD_W(int words, WDataOutP owp, WDataInP const lwp, diff --git a/include/verilatedos.h b/include/verilatedos.h index 6a24ea36f..b86d7925a 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -321,6 +321,7 @@ extern "C" void __gcov_dump(); // Now that C++ requires these standard types the vl types are deprecated #include #include +#include #ifndef VL_NO_LEGACY using vluint8_t = uint8_t; ///< 8-bit unsigned type (backward compatibility) @@ -445,11 +446,14 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read() #define VL_SIZEBITS_E (VL_EDATASIZE - 1) ///< Bit mask for bits in a quad /// Return mask for words with 1's where relevant bits are (0=all bits) +/// Arguments must not have side effects #define VL_MASK_I(nbits) (((nbits) & VL_SIZEBITS_I) ? ((1U << ((nbits) & VL_SIZEBITS_I)) - 1) : ~0) /// Return mask for quads with 1's where relevant bits are (0=all bits) +/// Arguments must not have side effects #define VL_MASK_Q(nbits) \ (((nbits) & VL_SIZEBITS_Q) ? ((1ULL << ((nbits) & VL_SIZEBITS_Q)) - 1ULL) : ~0ULL) /// Return mask for EData with 1's where relevant bits are (0=all bits) +/// Arguments must not have side effects #define VL_MASK_E(nbits) VL_MASK_I(nbits) #define VL_EUL(n) VL_UL(n) // Make constant number EData sized @@ -471,8 +475,12 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read() // #defines, to avoid requiring math.h on all compile runs #ifdef _MSC_VER -# define VL_TRUNC(n) (((n) < 0) ? std::ceil((n)) : std::floor((n))) -# define VL_ROUND(n) (((n) < 0) ? std::ceil((n)-0.5) : std::floor((n) + 0.5)) +static inline double VL_TRUNC(double n) { + return (n < 0) ? std::ceil(n) : std::floor(n); +} +static inline double VL_ROUND(double n) { + return (n < 0) ? std::ceil(n-0.5) : std::floor(n + 0.5); +} #else # define VL_TRUNC(n) std::trunc(n) # define VL_ROUND(n) std::round(n) From 485e230dd8cc79847c8ade3fc817b89dac11def2 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 10 May 2023 17:51:22 -0400 Subject: [PATCH 038/129] Commentary (#4187) --- docs/guide/simulating.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/simulating.rst b/docs/guide/simulating.rst index 5f9440da9..8067b0366 100644 --- a/docs/guide/simulating.rst +++ b/docs/guide/simulating.rst @@ -143,7 +143,7 @@ Functional Coverage ------------------- With :vlopt:`--coverage` or :vlopt:`--coverage-user`, Verilator will -translate functional coverage points the user has inserted manually win +translate functional coverage points the user has inserted manually in SystemVerilog code through into the Verilated model. Currently, all functional coverage points are specified using SystemVerilog From 5aecfa98a1d41fe09234b0d6d5c81d9d28e14e17 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Wed, 10 May 2023 23:52:17 +0200 Subject: [PATCH 039/129] Internals: Add param value string to hash in V3Param.cpp (#4186) --- src/V3Param.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/V3Param.cpp b/src/V3Param.cpp index fab0a077e..d9e69a5a6 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -257,8 +257,7 @@ class ParamProcessor final { // Generated modules by this visitor is not included V3StringSet m_allModuleNames; - using ValueMapValue = std::pair; - std::map m_valueMap; // Hash of node hash to (param value, name) + std::map m_valueMap; // Hash of node hash to param value int m_nextValue = 1; // Next value to use in m_valueMap const AstNodeModule* m_modp = nullptr; // Current module being processed @@ -304,7 +303,7 @@ class ParamProcessor final { return st; } - static string paramValueKey(const AstNode* nodep) { + static string paramValueString(const AstNode* nodep) { if (const AstRefDType* const refp = VN_CAST(nodep, RefDType)) { nodep = refp->skipRefp(); } string key = nodep->name(); if (const AstIfaceRefDType* const ifrtp = VN_CAST(nodep, IfaceRefDType)) { @@ -322,13 +321,13 @@ class ParamProcessor final { key += " {"; for (const AstNode* memberp = dtypep->membersp(); memberp; memberp = memberp->nextp()) { - key += paramValueKey(memberp); + key += paramValueString(memberp); key += ";"; } key += "}"; } else if (const AstMemberDType* const dtypep = VN_CAST(nodep, MemberDType)) { key += " "; - key += paramValueKey(dtypep->subDTypep()); + key += paramValueString(dtypep->subDTypep()); } else if (const AstBasicDType* const dtypep = VN_CAST(nodep, BasicDType)) { if (dtypep->isSigned()) { key += " signed"; } if (dtypep->isRanged()) { @@ -343,19 +342,19 @@ class ParamProcessor final { // particularly robust for type parameters. We should really have a type // equivalence predicate function. if (const AstRefDType* const refp = VN_CAST(nodep, RefDType)) nodep = refp->skipRefp(); - const string key = paramValueKey(nodep); + const string paramStr = paramValueString(nodep); // cppcheck-has-bug-suppress unreadVariable - V3Hash hash = V3Hasher::uncachedHash(nodep); + V3Hash hash = V3Hasher::uncachedHash(nodep) + paramStr; // Force hash collisions -- for testing only // cppcheck-has-bug-suppress unreadVariable - if (VL_UNLIKELY(v3Global.opt.debugCollision())) hash = V3Hash{}; + if (VL_UNLIKELY(v3Global.opt.debugCollision())) hash = V3Hash{paramStr}; int num; const auto it = m_valueMap.find(hash); - if (it != m_valueMap.end() && it->second.second == key) { - num = it->second.first; + if (it != m_valueMap.end()) { + num = it->second; } else { num = m_nextValue++; - m_valueMap[hash] = std::make_pair(num, key); + m_valueMap[hash] = num; } return std::string{"z"} + cvtToStr(num); } From 2267db093fc194c41fa11a2b78cb56814c58f208 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Thu, 11 May 2023 00:34:29 +0200 Subject: [PATCH 040/129] Fix hashes of instances of parameterized classes (#4182) --- src/V3Hasher.cpp | 2 +- test_regress/t/t_class_param_typedef.pl | 21 +++++++++++ test_regress/t/t_class_param_typedef.v | 47 +++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100755 test_regress/t/t_class_param_typedef.pl create mode 100644 test_regress/t/t_class_param_typedef.v diff --git a/src/V3Hasher.cpp b/src/V3Hasher.cpp index c68f1167e..432f62b17 100644 --- a/src/V3Hasher.cpp +++ b/src/V3Hasher.cpp @@ -307,7 +307,7 @@ private: } void visit(AstNodeModule* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, false, [=]() { // - m_hash += nodep->origName(); + m_hash += nodep->name(); }); } void visit(AstNodePreSel* nodep) override { diff --git a/test_regress/t/t_class_param_typedef.pl b/test_regress/t/t_class_param_typedef.pl new file mode 100755 index 000000000..1aa73f80a --- /dev/null +++ b/test_regress/t/t_class_param_typedef.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 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_param_typedef.v b/test_regress/t/t_class_param_typedef.v new file mode 100644 index 000000000..0218b205a --- /dev/null +++ b/test_regress/t/t_class_param_typedef.v @@ -0,0 +1,47 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Foo #(type T=int); + typedef Foo#(T) this_type; + function int get_x; + return T::get_s_x(); + endfunction +endclass + +class Bar #(type S=int); + typedef Bar #(S) this_type; + typedef Foo#(this_type) foo_type; + function int get_x; + foo_type f = new; + return f.get_x(); + endfunction + static function int get_s_x; + return S::x; + endfunction +endclass + +class Cls1; + static int x = 1; + typedef Bar#(Cls1) type_id; +endclass + +class Cls2; + static int x = 2; + typedef Bar#(Cls2) type_id; +endclass + +module t; + initial begin + Cls1::type_id bar1 = new; + Cls2::type_id bar2 = new; + + if (bar1.get_x() != 1) $stop; + if (bar2.get_x() != 2) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From d5de67c6dcb478b304f2a2ace73efc909b83fb95 Mon Sep 17 00:00:00 2001 From: Aylon Chaim Porat <124075536+apstrike@users.noreply.github.com> Date: Wed, 10 May 2023 20:34:44 -0400 Subject: [PATCH 041/129] Fix wide structure VL_TOSTRING_W generation (#4188) (#4189) * V3Common.cpp::makeVlToString: fix `VL_TOSTRING_W` statement generation to include width argument * fix contribution name * add testcase for long struct `VL_TO_STRING_W` bug --- docs/CONTRIBUTORS | 1 + src/V3Common.cpp | 8 +++++--- test_regress/t/t_trace_wide_struct.pl | 16 ++++++++++++++++ test_regress/t/t_trace_wide_struct.v | 23 +++++++++++++++++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) create mode 100755 test_regress/t/t_trace_wide_struct.pl create mode 100644 test_regress/t/t_trace_wide_struct.v diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 54a3058fd..2baed846f 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -14,6 +14,7 @@ Ameya Vikram Singh Andreas Kuster Andrew Nolte Arkadiusz Kozdra +Aylon Chaim Porat Cameron Kirk Chris Randall Chuxuan Wang diff --git a/src/V3Common.cpp b/src/V3Common.cpp index 25043d425..4dc587a10 100644 --- a/src/V3Common.cpp +++ b/src/V3Common.cpp @@ -82,11 +82,13 @@ static void makeVlToString(AstNodeUOrStructDType* nodep) { } stmt += VIdProtect::protect(itemp->prettyName()) + ":\" + "; if (VN_IS(itemp->dtypep()->skipRefp(), BasicDType) && itemp->isWide()) { - stmt += "VL_TO_STRING_W"; + stmt += "VL_TO_STRING_W("; + stmt += cvtToStr(itemp->widthWords()); + stmt += ", "; } else { - stmt += "VL_TO_STRING"; + stmt += "VL_TO_STRING("; } - stmt += "(obj." + itemp->nameProtect() + ");\n"; + stmt += "obj." + itemp->nameProtect() + ");\n"; funcp->addStmtsp(new AstCStmt{nodep->fileline(), stmt}); } funcp->addStmtsp(new AstCStmt{nodep->fileline(), "out += \"}\";\n"}); diff --git a/test_regress/t/t_trace_wide_struct.pl b/test_regress/t/t_trace_wide_struct.pl new file mode 100755 index 000000000..7914ddcc8 --- /dev/null +++ b/test_regress/t/t_trace_wide_struct.pl @@ -0,0 +1,16 @@ +#!/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 (verilator_flags2 => ['--trace --trace-structs'],); + +ok(1); +1; diff --git a/test_regress/t/t_trace_wide_struct.v b/test_regress/t/t_trace_wide_struct.v new file mode 100644 index 000000000..4a381de5a --- /dev/null +++ b/test_regress/t/t_trace_wide_struct.v @@ -0,0 +1,23 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2011 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + typedef struct { + logic [64:0] long_signal; + } mystruct_t; + + mystruct_t mystruct; + + initial begin + $finish; + end + +endmodule From e095bf1af0d79dbb0603f4f8ba95f6616e1a5cd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Boro=C5=84ski?= <94375110+kboronski-ant@users.noreply.github.com> Date: Thu, 11 May 2023 02:36:41 +0200 Subject: [PATCH 042/129] Support inside expressions with strings and doubles (#4138) (#4139) --- src/V3Width.cpp | 36 ++++++++++++++++++++---------- test_regress/t/t_inside_nonint.pl | 21 ++++++++++++++++++ test_regress/t/t_inside_nonint.v | 37 +++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 12 deletions(-) create mode 100755 test_regress/t/t_inside_nonint.pl create mode 100644 test_regress/t/t_inside_nonint.v diff --git a/src/V3Width.cpp b/src/V3Width.cpp index fec2ab39b..241e886da 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2473,23 +2473,35 @@ private: nextip = itemp->nextp(); // iterate may cause the node to get replaced VL_DO_DANGLING(userIterate(itemp, WidthVP{CONTEXT_DET, PRELIM}.p()), itemp); } - // Take width as maximum across all items - int width = nodep->exprp()->width(); - int mwidth = nodep->exprp()->widthMin(); - for (const AstNode* itemp = nodep->itemsp(); itemp; itemp = itemp->nextp()) { - width = std::max(width, itemp->width()); - mwidth = std::max(mwidth, itemp->widthMin()); + + AstBasicDType* dtype = VN_CAST(nodep->exprp()->dtypep(), BasicDType); + AstNodeDType* subDTypep = nullptr; + + if (dtype && dtype->isString()) { + nodep->dtypeSetString(); + subDTypep = nodep->findStringDType(); + } else if (dtype && dtype->isDouble()) { + nodep->dtypeSetDouble(); + subDTypep = nodep->findDoubleDType(); + } else { + // Take width as maximum across all items + int width = nodep->exprp()->width(); + int mwidth = nodep->exprp()->widthMin(); + for (const AstNode* itemp = nodep->itemsp(); itemp; itemp = itemp->nextp()) { + width = std::max(width, itemp->width()); + mwidth = std::max(mwidth, itemp->widthMin()); + } + nodep->dtypeSetBit(); + subDTypep = nodep->findLogicDType(width, mwidth, nodep->exprp()->dtypep()->numeric()); } - // Apply width - AstNodeDType* const subDTypep - = nodep->findLogicDType(width, mwidth, nodep->exprp()->dtypep()->numeric()); + iterateCheck(nodep, "Inside expression", nodep->exprp(), CONTEXT_DET, FINAL, subDTypep, EXTEND_EXP); for (AstNode *nextip, *itemp = nodep->itemsp(); itemp; itemp = nextip) { nextip = itemp->nextp(); // iterate may cause the node to get replaced iterateCheck(nodep, "Inside Item", itemp, CONTEXT_DET, FINAL, subDTypep, EXTEND_EXP); } - nodep->dtypeSetBit(); + if (debug() >= 9) nodep->dumpTree("- inside-in: "); // Now rip out the inside and replace with simple math AstNodeExpr* newp = nullptr; @@ -2513,8 +2525,8 @@ private: "Inside operator not legal on non-unpacked arrays (IEEE 1800-2017 11.4.13)"); continue; } else { - inewp = new AstEqWild{itemp->fileline(), nodep->exprp()->cloneTree(true), - itemp->unlinkFrBack()}; + inewp = AstEqWild::newTyped(itemp->fileline(), nodep->exprp()->cloneTree(true), + itemp->unlinkFrBack()); } if (newp) { newp = new AstOr{nodep->fileline(), newp, inewp}; diff --git a/test_regress/t/t_inside_nonint.pl b/test_regress/t/t_inside_nonint.pl new file mode 100755 index 000000000..859050d63 --- /dev/null +++ b/test_regress/t/t_inside_nonint.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 2023 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_inside_nonint.v b/test_regress/t/t_inside_nonint.v new file mode 100644 index 000000000..90f5cecce --- /dev/null +++ b/test_regress/t/t_inside_nonint.v @@ -0,0 +1,37 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +function bit check_string(string s); + if (s inside {"RW", "WO"}) + return 1'b1; + return 1'b0; +endfunction + +function bit check_double(real d); + if (d inside {0.0, 2.5}) + return 1'b1; + return 1'b0; +endfunction + +module t(); + initial begin + if (!check_string("WO")) + $stop; + if (!check_string("RW")) + $stop; + if (check_string("ABC")) + $stop; + if (!check_double(0.0)) + $stop; + if (!check_double(2.5)) + $stop; + if (check_double(1.0)) + $stop; + + $display("*-* All Finished *-*"); + $finish; + end +endmodule From 0198a3fc5298e8db7a5115257ab33498ad109d30 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Thu, 11 May 2023 09:56:15 +0200 Subject: [PATCH 043/129] Use unchanged copy of parameterized class for instantation (#4179) --- src/V3Param.cpp | 70 +++++++++++++++++------- test_regress/t/t_class_param_extends2.pl | 21 +++++++ test_regress/t/t_class_param_extends2.v | 38 +++++++++++++ 3 files changed, 108 insertions(+), 21 deletions(-) create mode 100755 test_regress/t/t_class_param_extends2.pl create mode 100644 test_regress/t/t_class_param_extends2.v diff --git a/src/V3Param.cpp b/src/V3Param.cpp index d9e69a5a6..7ebafda9e 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -221,7 +221,7 @@ public: //###################################################################### // Remove parameters from cells and build new modules -class ParamProcessor final { +class ParamProcessor final : public VNDeleter { // NODE STATE - Local // AstVar::user4() // int Global parameter number (for naming new module) // // (0=not processed, 1=iterated, but no number, @@ -257,6 +257,9 @@ class ParamProcessor final { // Generated modules by this visitor is not included V3StringSet m_allModuleNames; + CloneMap m_originalParams; // Map between parameters of copied parameteized classes and their + // original nodes + std::map m_valueMap; // Hash of node hash to param value int m_nextValue = 1; // Next value to use in m_valueMap @@ -387,23 +390,20 @@ class ParamProcessor final { } return nullptr; } - void collectPins(CloneMap* clonemapp, AstNodeModule* modp) { + void collectPins(CloneMap* clonemapp, AstNodeModule* modp, bool originalIsCopy) { // Grab all I/O so we can remap our pins later for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) { + const AstNode* originalParamp = nullptr; if (AstVar* const varp = VN_CAST(stmtp, Var)) { if (varp->isIO() || varp->isGParam() || varp->isIfaceRef()) { // Cloning saved a pointer to the new node for us, so just follow that link. - const AstVar* const oldvarp = varp->clonep(); - // UINFO(8,"Clone list 0x"< 0x"<<(uint32_t)varp<emplace(oldvarp, varp); + originalParamp = varp->clonep(); } } else if (AstParamTypeDType* const ptp = VN_CAST(stmtp, ParamTypeDType)) { - if (ptp->isGParam()) { - const AstParamTypeDType* const oldptp = ptp->clonep(); - clonemapp->emplace(oldptp, ptp); - } + if (ptp->isGParam()) originalParamp = ptp->clonep(); } + if (originalIsCopy) originalParamp = m_originalParams[originalParamp]; + clonemapp->emplace(originalParamp, stmtp); } } void relinkPins(const CloneMap* clonemapp, AstPin* startpinp) { @@ -545,9 +545,8 @@ class ParamProcessor final { } void replaceRefsRecurse(AstNode* const nodep, const AstClass* const oldClassp, AstClass* const newClassp) { - // Some of the nodes may be already marked as visited, because they were copied. They - // should be marked as unvisited, because parameterized references have to be handled. - nodep->user5(false); + // Self references linked in the first pass of V3LinkDot.cpp should point to the default + // instance. if (AstClassRefDType* const classRefp = VN_CAST(nodep, ClassRefDType)) { if (classRefp->classp() == oldClassp) classRefp->classp(newClassp); } else if (AstClassOrPackageRef* const classRefp = VN_CAST(nodep, ClassOrPackageRef)) { @@ -565,7 +564,13 @@ class ParamProcessor final { // Deep clone of new module // Note all module internal variables will be re-linked to the new modules by clone // However links outside the module (like on the upper cells) will not. - AstNodeModule* const newmodp = srcModp->cloneTree(false); + AstNodeModule* newmodp; + if (srcModp->user2p()) { + newmodp = VN_CAST(srcModp->user2p()->cloneTree(false), NodeModule); + } else { + newmodp = srcModp->cloneTree(false); + } + if (AstClass* const newClassp = VN_CAST(newmodp, Class)) { newClassp->isParameterized(false); replaceRefsRecurse(newmodp->stmtsp(), newClassp, VN_AS(srcModp, Class)); @@ -603,7 +608,7 @@ class ParamProcessor final { // Grab all I/O so we can remap our pins later // Note we allow multiple users of a parameterized model, // thus we need to stash this info. - collectPins(clonemapp, newmodp); + collectPins(clonemapp, newmodp, srcModp->user2p()); // Relink parameter vars to the new module relinkPins(clonemapp, paramsp); // Fix any interface references @@ -787,6 +792,18 @@ class ParamProcessor final { } } + void storeOriginalParams(AstClass* const classp) { + for (AstNode* stmtp = classp->stmtsp(); stmtp; stmtp = stmtp->nextp()) { + AstNode* originalParamp = nullptr; + if (AstVar* const varp = VN_CAST(stmtp, Var)) { + if (varp->isGParam()) originalParamp = varp->clonep(); + } else if (AstParamTypeDType* const ptp = VN_CAST(stmtp, ParamTypeDType)) { + if (ptp->isGParam()) originalParamp = ptp->clonep(); + } + if (originalParamp) m_originalParams[stmtp] = originalParamp; + } + } + bool nodeDeparamCommon(AstNode* nodep, AstNodeModule*& srcModpr, AstPin* paramsp, AstPin* pinsp, bool any_overrides) { // Make sure constification worked @@ -809,9 +826,16 @@ class ParamProcessor final { if (!any_overrides) { UINFO(8, "Cell parameters all match original values, skipping expansion.\n"); - // Mark that the defeult instance is used. - // It will be checked only if srcModpr is a class. - srcModpr->user2(true); + // If it's the first use of the default instance, create a copy and store it in user2p. + // user2p will also be used to check if the default instance is used. + if (!srcModpr->user2p() && VN_IS(srcModpr, Class)) { + AstClass* classCopyp = VN_AS(srcModpr, Class)->cloneTree(false); + // It is a temporary copy of the original class node, stored in order to create + // another instances. It is needed only during class instantiation. + pushDeletep(classCopyp); + srcModpr->user2p(classCopyp); + storeOriginalParams(classCopyp); + } } else if (AstNodeModule* const paramedModp = m_hierBlocks.findByParams(srcModpr->name(), paramsp, m_modp)) { paramedModp->dead(false); @@ -919,7 +943,11 @@ public: class ParamVisitor final : public VNVisitor { // NODE STATE // AstNodeModule::user1 -> bool: already fixed level - // AstClass::user2 -> bool: Referenced (value read only in parameterized classes) + // AstClass::user2p -> AstClass*: Unchanged copy of the parameterized class node. + // The class node may be modified according to parameter + // values and an unchanged copy is needed to instantiate + // classes with different parameters. + // STATE ParamProcessor m_processor; // De-parameterize a cell, build modules UnrollStateful m_unroller; // Loop unroller @@ -1377,8 +1405,8 @@ public: for (AstNodeModule* const modp : modps) netlistp->addModulesp(modp); for (AstClass* const classp : m_paramClasses) { - if (!classp->user2()) { - // Unreferenced, so it can be removed + if (!classp->user2p()) { + // The default value isn't referenced, so it can be removed VL_DO_DANGLING(pushDeletep(classp->unlinkFrBack()), classp); } else { // Referenced. classp became a specialized class with the default diff --git a/test_regress/t/t_class_param_extends2.pl b/test_regress/t/t_class_param_extends2.pl new file mode 100755 index 000000000..1aa73f80a --- /dev/null +++ b/test_regress/t/t_class_param_extends2.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 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_param_extends2.v b/test_regress/t/t_class_param_extends2.v new file mode 100644 index 000000000..f4420d0d0 --- /dev/null +++ b/test_regress/t/t_class_param_extends2.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, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Foo #(type T=bit); + int x = $bits(T); +endclass + +class Bar #(type S=int) extends Foo#(S); +endclass + +typedef Bar#() bar_default_t; + +class Baz; + Bar#(logic[7:0]) bar_string; + int bar_x; + function new; + bar_string = new; + bar_x = bar_string.x; + endfunction +endclass + +typedef Baz baz_t; + +module t; + initial begin + bar_default_t bar_default = new; + baz_t baz = new; + + if (bar_default.x != 32) $stop; + if (baz.bar_x != 8) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From 4835ed6967a4d6d080f6b52ad154013eb9446b76 Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Fri, 12 May 2023 12:57:12 +0200 Subject: [PATCH 044/129] Fix forced assignments that override non-continuous assignments (#4183) (#4192) Only assign forced value on release if it was forced in the first place. --- src/V3Force.cpp | 29 ++++++++++--- test_regress/t/t_clocked_release_combo.pl | 21 ++++++++++ test_regress/t/t_clocked_release_combo.v | 51 +++++++++++++++++++++++ 3 files changed, 95 insertions(+), 6 deletions(-) create mode 100755 test_regress/t/t_clocked_release_combo.pl create mode 100644 test_regress/t/t_clocked_release_combo.v diff --git a/src/V3Force.cpp b/src/V3Force.cpp index 9d563a687..6eab5f0d4 100644 --- a/src/V3Force.cpp +++ b/src/V3Force.cpp @@ -253,16 +253,33 @@ class ForceConvertVisitor final : public VNVisitor { resetRdp->rhsp()->foreach([this](AstNodeVarRef* refp) { if (refp->access() != VAccess::WRITE) return; AstVarScope* const vscp = refp->varScopep(); - AstVarScope* const newVscp - = vscp->varp()->isContinuously() ? vscp : getForceComponents(vscp).m_valVscp; - AstVarRef* const newpRefp = new AstVarRef{refp->fileline(), newVscp, VAccess::READ}; + FileLine* const flp = new FileLine{refp->fileline()}; + AstVarRef* const newpRefp = new AstVarRef{refp->fileline(), vscp, VAccess::READ}; newpRefp->user2(1); // Don't replace this read ref with the read signal - refp->replaceWith(newpRefp); + if (vscp->varp()->isContinuously()) { + refp->replaceWith(newpRefp); + } else if (isRangedDType(vscp)) { + refp->replaceWith(new AstOr{ + flp, + new AstAnd{ + flp, new AstVarRef{flp, getForceComponents(vscp).m_enVscp, VAccess::READ}, + new AstVarRef{flp, getForceComponents(vscp).m_valVscp, VAccess::READ}}, + new AstAnd{ + flp, + new AstNot{flp, new AstVarRef{flp, getForceComponents(vscp).m_enVscp, + VAccess::READ}}, + newpRefp}}); + } else { + refp->replaceWith(new AstCond{ + flp, new AstVarRef{flp, getForceComponents(vscp).m_enVscp, VAccess::READ}, + new AstVarRef{flp, getForceComponents(vscp).m_valVscp, VAccess::READ}, + newpRefp}); + } VL_DO_DANGLING(refp->deleteTree(), refp); }); - resetEnp->addNext(resetRdp); - relinker.relink(resetEnp); + resetRdp->addNext(resetEnp); + relinker.relink(resetRdp); } void visit(AstVarScope* nodep) override { diff --git a/test_regress/t/t_clocked_release_combo.pl b/test_regress/t/t_clocked_release_combo.pl new file mode 100755 index 000000000..fcd9221f5 --- /dev/null +++ b/test_regress/t/t_clocked_release_combo.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 2023 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_clocked_release_combo.v b/test_regress/t/t_clocked_release_combo.v new file mode 100644 index 000000000..fe0605223 --- /dev/null +++ b/test_regress/t/t_clocked_release_combo.v @@ -0,0 +1,51 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +// verilator lint_off MULTIDRIVEN +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + logic [31:0] lhs1, lhs2, rhs; + logic cond = 0; + + always_comb lhs1 = rhs; + assign lhs2 = rhs; + + always @(posedge clk) rhs = '1; + + always @(negedge clk) begin + if (cond) begin + force lhs1 = 'hdeadbeef; + force lhs2 = 'hfeedface; + end + else begin + release lhs1; + release lhs2; + end + end + + int cyc = 0; + always @(posedge clk) begin + cyc <= cyc + 1; + if (cyc == 0) cond <= 1; + if (cyc == 3) cond <= 0; + if (cyc > 1 && cyc < 4) begin + if (lhs1 != 'hdeadbeef) $stop; + if (lhs2 != 'hfeedface) $stop; + end + if (cyc > 4 && cyc < 8) begin + if (lhs1 != '1) $stop; + if (lhs2 != '1) $stop; + end + if (cyc >= 8) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule From e7714e09020206871a80bb117217caf8bbfdae87 Mon Sep 17 00:00:00 2001 From: Mariusz Glebocki Date: Fri, 12 May 2023 15:06:36 +0200 Subject: [PATCH 045/129] Internals: Add additional clang's thread safety analysis annotations (#4195) * Simplify some Clang-specific attribute defines. * Add `VL_RETURN_CAPABILITY` and `VL_PT_GUARDED_BY`. --- include/verilatedos.h | 131 +++++++++++++++++++++--------------------- 1 file changed, 65 insertions(+), 66 deletions(-) diff --git a/include/verilatedos.h b/include/verilatedos.h index b86d7925a..fdcbe64cd 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -37,6 +37,12 @@ //========================================================================= // Compiler pragma abstraction +#if defined(__clang__) +# define VL_CLANG_ATTR(attr) __attribute__(( attr )) +#else +# define VL_CLANG_ATTR(attr) +#endif + #ifdef __GNUC__ # define VL_ATTR_ALWINLINE __attribute__((always_inline)) inline # define VL_ATTR_NOINLINE __attribute__((noinline)) @@ -56,19 +62,6 @@ // All VL_ATTR_WEAK symbols must be marked with the macOS -U linker flag in verilated.mk.in # define VL_ATTR_WEAK __attribute__((weak)) # endif -# if defined(__clang__) -# define VL_ACQUIRE(...) __attribute__((annotate("ACQUIRE"))) __attribute__((acquire_capability(__VA_ARGS__))) -# define VL_ACQUIRE_SHARED(...) __attribute__((annotate("ACQUIRE_SHARED"))) __attribute__((acquire_shared_capability(__VA_ARGS__))) -# define VL_RELEASE(...) __attribute__((annotate("RELEASE"))) __attribute__((release_capability(__VA_ARGS__))) -# define VL_RELEASE_SHARED(...) __attribute__((annotate("RELEASE_SHARED"))) __attribute__((release_shared_capability(__VA_ARGS__))) -# define VL_TRY_ACQUIRE(...) __attribute__((try_acquire_capability(__VA_ARGS__))) -# define VL_TRY_ACQUIRE_SHARED(...) __attribute__((try_acquire_shared_capability(__VA_ARGS__))) -# define VL_CAPABILITY(x) __attribute__((capability(x))) -# define VL_REQUIRES(x) __attribute__((annotate("REQUIRES"))) __attribute__((requires_capability(x))) -# define VL_GUARDED_BY(x) __attribute__((annotate("GUARDED_BY"))) __attribute__((guarded_by(x))) -# define VL_EXCLUDES(x) __attribute__((annotate("EXCLUDES"))) __attribute__((locks_excluded(x))) -# define VL_SCOPED_CAPABILITY __attribute__((scoped_lockable)) -# endif # define VL_LIKELY(x) __builtin_expect(!!(x), 1) // Prefer over C++20 [[likely]] # define VL_UNLIKELY(x) __builtin_expect(!!(x), 0) // Prefer over C++20 [[unlikely]] # define VL_UNREACHABLE __builtin_unreachable() // C++23 std::unreachable() @@ -76,6 +69,57 @@ # define VL_PREFETCH_RW(p) __builtin_prefetch((p), 1) #endif +// Function acquires a capability/lock (-fthread-safety) +#define VL_ACQUIRE(...) \ + VL_CLANG_ATTR(annotate("ACQUIRE")) \ + VL_CLANG_ATTR(acquire_capability(__VA_ARGS__)) +// Function acquires a shared capability/lock (-fthread-safety) +#define VL_ACQUIRE_SHARED(...) \ + VL_CLANG_ATTR(annotate("ACQUIRE_SHARED")) \ + VL_CLANG_ATTR(acquire_shared_capability(__VA_ARGS__)) +// Function releases a capability/lock (-fthread-safety) +#define VL_RELEASE(...) \ + VL_CLANG_ATTR(annotate("RELEASE")) \ + VL_CLANG_ATTR(release_capability(__VA_ARGS__)) +// Function releases a shared capability/lock (-fthread-safety) +#define VL_RELEASE_SHARED(...) \ + VL_CLANG_ATTR(annotate("RELEASE_SHARED")) \ + VL_CLANG_ATTR(release_shared_capability(__VA_ARGS__)) +// Function returns bool if acquired a capability (-fthread-safety) +#define VL_TRY_ACQUIRE(...) \ + VL_CLANG_ATTR(try_acquire_capability(__VA_ARGS__)) +// Function returns bool if acquired shared (-fthread-safety) +#define VL_TRY_ACQUIRE_SHARED(...) \ + VL_CLANG_ATTR(try_acquire_shared_capability(__VA_ARGS__)) +// Function requires a capability inbound (-fthread-safety) +#define VL_CAPABILITY(x) \ + VL_CLANG_ATTR(capability(x)) +// Function requires not having a capability inbound (-fthread-safety) +#define VL_REQUIRES(x) \ + VL_CLANG_ATTR(annotate("REQUIRES")) \ + VL_CLANG_ATTR(requires_capability(x)) +// Name of capability/lock (-fthread-safety) +#define VL_GUARDED_BY(x) \ + VL_CLANG_ATTR(annotate("GUARDED_BY")) \ + VL_CLANG_ATTR(guarded_by(x)) +// The data that the annotated pointer points to is protected by the given capability. +// The pointer itself is not protected. +// Allowed on: pointer data member. (-fthread-safety) +#define VL_PT_GUARDED_BY(x) \ + VL_CLANG_ATTR(annotate("PT_GUARDED_BY")) \ + VL_CLANG_ATTR(pt_guarded_by(x)) +// Name of mutex protecting this variable (-fthread-safety) +#define VL_EXCLUDES(x) \ + VL_CLANG_ATTR(annotate("EXCLUDES")) \ + VL_CLANG_ATTR(locks_excluded(x)) +// Scoped threaded capability/lock (-fthread-safety) +#define VL_SCOPED_CAPABILITY \ + VL_CLANG_ATTR(scoped_lockable) +// Annotated function returns reference to the given capability. +// Allowed on: function, method. (-fthread-safety) +#define VL_RETURN_CAPABILITY(x) \ + VL_CLANG_ATTR(lock_returned(x)) + // Defaults for unsupported compiler features #ifndef VL_ATTR_ALWINLINE # define VL_ATTR_ALWINLINE ///< Attribute to inline, even when not optimizing @@ -107,19 +151,6 @@ #ifndef VL_ATTR_WEAK # define VL_ATTR_WEAK ///< Attribute that function external that is optionally defined #endif -#ifndef VL_CAPABILITY -# define VL_ACQUIRE(...) ///< Function acquires a capability/lock (-fthread-safety) -# define VL_ACQUIRE_SHARED(...) ///< Function acquires a shared capability/lock (-fthread-safety) -# define VL_RELEASE(...) ///< Function releases a capability/lock (-fthread-safety) -# define VL_RELEASE_SHARED(...) ///< Function releases a shared capability/lock (-fthread-safety) -# define VL_TRY_ACQUIRE(...) ///< Function returns bool if acquired a capability (-fthread-safety) -# define VL_TRY_ACQUIRE_SHARED(...) ///< Function returns bool if acquired shared (-fthread-safety) -# define VL_REQUIRES(x) ///< Function requires a capability inbound (-fthread-safety) -# define VL_EXCLUDES(x) ///< Function requires not having a capability inbound (-fthread-safety) -# define VL_CAPABILITY(x) ///< Name of capability/lock (-fthread-safety) -# define VL_GUARDED_BY(x) ///< Name of mutex protecting this variable (-fthread-safety) -# define VL_SCOPED_CAPABILITY ///< Scoped threaded capability/lock (-fthread-safety) -#endif #ifndef VL_LIKELY # define VL_LIKELY(x) (!!(x)) ///< Return boolean expression that is more often true # define VL_UNLIKELY(x) (!!(x)) ///< Return boolean expression that is more often false @@ -146,56 +177,24 @@ #endif // Comment tag that Function is pure (and thus also VL_MT_SAFE) -#if defined(__clang__) -# define VL_PURE __attribute__((annotate("PURE"))) -#else -# define VL_PURE -#endif +#define VL_PURE VL_CLANG_ATTR(annotate("PURE")) // Comment tag that function is threadsafe -#if defined(__clang__) -# define VL_MT_SAFE __attribute__((annotate("MT_SAFE"))) -#else -# define VL_MT_SAFE -#endif +#define VL_MT_SAFE VL_CLANG_ATTR(annotate("MT_SAFE")) // Comment tag that function is threadsafe, only if // other threads doesn't change tree topology -#if defined(__clang__) -# define VL_MT_STABLE __attribute__((annotate("MT_STABLE"))) -#else -# define VL_MT_STABLE -#endif +#define VL_MT_STABLE VL_CLANG_ATTR(annotate("MT_STABLE")) // Comment tag that function is threadsafe, only // during normal operation (post-init) -#if defined(__clang__) -# define VL_MT_SAFE_POSTINIT __attribute__((annotate("MT_SAFE_POSTINIT"))) -#else -# define VL_MT_SAFE_POSTINIT -#endif +#define VL_MT_SAFE_POSTINIT VL_CLANG_ATTR(annotate("MT_SAFE_POSTINIT")) // Attribute that function is clang threadsafe and uses given mutex -#if defined(__clang__) -# define VL_MT_SAFE_EXCLUDES(mutex) __attribute__((annotate("MT_SAFE_EXCLUDES"))) VL_EXCLUDES(mutex) -#else -# define VL_MT_SAFE_EXCLUDES(mutex) VL_EXCLUDES(mutex) -#endif +#define VL_MT_SAFE_EXCLUDES(mutex) VL_CLANG_ATTR(annotate("MT_SAFE_EXCLUDES")) VL_EXCLUDES(mutex) // Comment tag that function is not threadsafe -#if defined(__clang__) -# define VL_MT_UNSAFE __attribute__((annotate("MT_UNSAFE"))) -#else -# define VL_MT_UNSAFE -#endif +#define VL_MT_UNSAFE VL_CLANG_ATTR(annotate("MT_UNSAFE")) // Comment tag that function is not threadsafe // protected to make sure single-caller -#if defined(__clang__) -# define VL_MT_UNSAFE_ONE __attribute__((annotate("MT_UNSAFE_ONE"))) -#else -# define VL_MT_UNSAFE_ONE -#endif +#define VL_MT_UNSAFE_ONE VL_CLANG_ATTR(annotate("MT_UNSAFE_ONE")) // Comment tag that function is entry point of parallelization -#if defined(__clang__) -# define VL_MT_START __attribute__((annotate("MT_START"))) -#else -# define VL_MT_START -#endif +#define VL_MT_START VL_CLANG_ATTR(annotate("MT_START")) #ifndef VL_NO_LEGACY # define VL_ULL(c) (c##ULL) // Add appropriate suffix to 64-bit constant (deprecated) From be429a58000e4e75a0f47d170706cbd70879a790 Mon Sep 17 00:00:00 2001 From: Mariusz Glebocki Date: Sat, 13 May 2023 16:28:34 +0200 Subject: [PATCH 046/129] Internals: Lock the same mutex reference as specified in VL_ACQUIRE. (#4194) --- include/verilated.h | 2 +- src/V3Mutex.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/verilated.h b/include/verilated.h index ac2d3c773..190488d04 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -218,7 +218,7 @@ public: /// Construct and hold given mutex lock until destruction or unlock() explicit VerilatedLockGuard(VerilatedMutex& mutexr) VL_ACQUIRE(mutexr) VL_MT_SAFE : m_mutexr(mutexr) { // Need () or GCC 4.8 false warning - m_mutexr.lock(); + mutexr.lock(); } /// Destruct and unlock the mutex ~VerilatedLockGuard() VL_RELEASE() { m_mutexr.unlock(); } diff --git a/src/V3Mutex.h b/src/V3Mutex.h index b1ee4b021..ffa1bdd07 100644 --- a/src/V3Mutex.h +++ b/src/V3Mutex.h @@ -137,7 +137,7 @@ public: /// Construct and hold given mutex lock until destruction or unlock() explicit V3LockGuardImp(T& mutexr) VL_ACQUIRE(mutexr) VL_MT_SAFE : m_mutexr(mutexr) { // Need () or GCC 4.8 false warning - m_mutexr.lock(); + mutexr.lock(); } /// Destruct and unlock the mutex ~V3LockGuardImp() VL_RELEASE() { m_mutexr.unlock(); } From 949be301ded6453d4bb3e8db63ab77aa98277aaa Mon Sep 17 00:00:00 2001 From: Mariusz Glebocki Date: Sat, 13 May 2023 16:32:33 +0200 Subject: [PATCH 047/129] Internals: Fix unbalanced V3LockGuard locking (#4193) --- include/verilated.cpp | 15 +++++--- include/verilated.h | 13 ------- include/verilated_threads.h | 2 +- include/verilated_trace.h | 2 +- include/verilated_trace_imp.h | 2 +- include/verilated_types.h | 2 +- src/V3Mutex.h | 13 ------- src/V3ThreadPool.cpp | 70 +++++++++++++++++++---------------- src/V3ThreadPool.h | 14 +++---- 9 files changed, 58 insertions(+), 75 deletions(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index 3b7a90de2..af1f419b1 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -3228,15 +3228,18 @@ void VerilatedAssertOneThread::fatal_different() VL_MT_SAFE { //=========================================================================== // VlDeleter:: Methods -void VlDeleter::deleteAll() { +void VlDeleter::deleteAll() VL_EXCLUDES(m_mutex) VL_EXCLUDES(m_deleteMutex) VL_MT_SAFE { while (true) { - VerilatedLockGuard lock{m_mutex}; - if (m_newGarbage.empty()) break; - VerilatedLockGuard deleteLock{m_deleteMutex}; - std::swap(m_newGarbage, m_toDelete); - lock.unlock(); // So destructors can enqueue new objects + { + VerilatedLockGuard lock{m_mutex}; + if (m_newGarbage.empty()) break; + m_deleteMutex.lock(); + std::swap(m_newGarbage, m_toDelete); + // m_mutex is unlocked here, so destructors can enqueue new objects + } for (VlDeletable* const objp : m_toDelete) delete objp; m_toDelete.clear(); + m_deleteMutex.unlock(); } } diff --git a/include/verilated.h b/include/verilated.h index 190488d04..a66472266 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -222,19 +222,6 @@ public: } /// Destruct and unlock the mutex ~VerilatedLockGuard() VL_RELEASE() { m_mutexr.unlock(); } - /// Lock the mutex - void lock() VL_ACQUIRE() VL_MT_SAFE { m_mutexr.lock(); } - /// Unlock the mutex - void unlock() VL_RELEASE() VL_MT_SAFE { m_mutexr.unlock(); } - /// Acquire/lock mutex and check for stop request. - /// It tries to lock the mutex and if it fails, it check if stop request was send. - /// It returns after locking mutex. - /// This function should be extracted to V3ThreadPool, but due to clang thread-safety - /// limitations it needs to be placed here. - void lockCheckStopRequest(std::function checkStopRequestFunction) - VL_ACQUIRE() VL_MT_SAFE { - m_mutexr.lockCheckStopRequest(checkStopRequestFunction); - } }; // Internals: Remember the calling thread at construction time, and make diff --git a/include/verilated_threads.h b/include/verilated_threads.h index dfb949f2d..155862c9b 100644 --- a/include/verilated_threads.h +++ b/include/verilated_threads.h @@ -173,7 +173,7 @@ public: VerilatedLockGuard lock{m_mutex}; while (m_ready.empty()) { m_waiting = true; - m_cv.wait(lock); + m_cv.wait(m_mutex); } m_waiting = false; // As noted above this is inefficient if our ready list is ever diff --git a/include/verilated_trace.h b/include/verilated_trace.h index 48b7e3558..d0c2ff4e3 100644 --- a/include/verilated_trace.h +++ b/include/verilated_trace.h @@ -75,7 +75,7 @@ public: // Get an element from the front of the queue. Blocks if none available T get() VL_MT_SAFE_EXCLUDES(m_mutex) { VerilatedLockGuard lock{m_mutex}; - m_cv.wait(lock, [this]() VL_REQUIRES(m_mutex) { return !m_queue.empty(); }); + m_cv.wait(m_mutex, [this]() VL_REQUIRES(m_mutex) { return !m_queue.empty(); }); assert(!m_queue.empty()); T value = m_queue.front(); m_queue.pop_front(); diff --git a/include/verilated_trace_imp.h b/include/verilated_trace_imp.h index f4972d163..f7d03fc99 100644 --- a/include/verilated_trace_imp.h +++ b/include/verilated_trace_imp.h @@ -482,7 +482,7 @@ VL_ATTR_NOINLINE void VerilatedTrace::ParallelWorkerData::wa // We have been spinning for a while, so yield the thread VerilatedLockGuard lock{m_mutex}; m_waiting = true; - m_cv.wait(lock, [this] { return m_ready.load(std::memory_order_relaxed); }); + m_cv.wait(m_mutex, [this] { return m_ready.load(std::memory_order_relaxed); }); m_waiting = false; } diff --git a/include/verilated_types.h b/include/verilated_types.h index ab871ec84..39e487bb7 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -1138,7 +1138,7 @@ public: } // Deletes all queued garbage objects. - void deleteAll() VL_MT_SAFE; + void deleteAll() VL_EXCLUDES(m_mutex) VL_EXCLUDES(m_deleteMutex) VL_MT_SAFE; }; //=================================================================== diff --git a/src/V3Mutex.h b/src/V3Mutex.h index ffa1bdd07..2d9e99eda 100644 --- a/src/V3Mutex.h +++ b/src/V3Mutex.h @@ -141,19 +141,6 @@ public: } /// Destruct and unlock the mutex ~V3LockGuardImp() VL_RELEASE() { m_mutexr.unlock(); } - /// Lock the mutex - void lock() VL_ACQUIRE() VL_MT_SAFE { m_mutexr.lock(); } - /// Unlock the mutex - void unlock() VL_RELEASE() VL_MT_SAFE { m_mutexr.unlock(); } - /// Acquire/lock mutex and check for stop request. - /// It tries to lock the mutex and if it fails, it check if stop request was send. - /// It returns after locking mutex. - /// This function should be extracted to V3ThreadPool, but due to clang thread-safety - /// limitations it needs to be placed here. - void lockCheckStopRequest(std::function checkStopRequestFunction) - VL_ACQUIRE() VL_MT_SAFE { - m_mutexr.lockCheckStopRequest(checkStopRequestFunction); - } }; using V3Mutex = V3MutexImp; diff --git a/src/V3ThreadPool.cpp b/src/V3ThreadPool.cpp index 71ca0772e..678270a13 100644 --- a/src/V3ThreadPool.cpp +++ b/src/V3ThreadPool.cpp @@ -23,29 +23,33 @@ // c++11 requires definition of static constexpr as well as declaration constexpr unsigned int V3ThreadPool::FUTUREWAITFOR_MS; -void V3ThreadPool::resize(unsigned n) VL_MT_UNSAFE { +void V3ThreadPool::resize(unsigned n) VL_MT_UNSAFE VL_EXCLUDES(m_mutex) + VL_EXCLUDES(m_stoppedJobsMutex) { // This function is not thread-safe and can result in race between threads UASSERT(V3MutexConfig::s().lockConfig(), "Mutex config needs to be locked before starting ThreadPool"); - V3LockGuard lock{m_mutex}; - V3LockGuard stoppedJobsLock{m_stoppedJobsMutex}; - UASSERT(m_queue.empty(), "Resizing busy thread pool"); - // Shut down old threads - m_shutdown = true; - m_stoppedJobs = 0; - m_cv.notify_all(); - m_stoppedJobsCV.notify_all(); - stoppedJobsLock.unlock(); - lock.unlock(); + { + V3LockGuard lock{m_mutex}; + V3LockGuard stoppedJobsLock{m_stoppedJobsMutex}; + + UASSERT(m_queue.empty(), "Resizing busy thread pool"); + // Shut down old threads + m_shutdown = true; + m_stoppedJobs = 0; + m_cv.notify_all(); + m_stoppedJobsCV.notify_all(); + } while (!m_workers.empty()) { m_workers.front().join(); m_workers.pop_front(); } - lock.lock(); - // Start new threads - m_shutdown = false; - for (unsigned int i = 1; i < n; ++i) { - m_workers.emplace_back(&V3ThreadPool::startWorker, this, i); + if (n > 1) { + V3LockGuard lock{m_mutex}; + // Start new threads + m_shutdown = false; + for (unsigned int i = 1; i < n; ++i) { + m_workers.emplace_back(&V3ThreadPool::startWorker, this, i); + } } } @@ -60,7 +64,7 @@ void V3ThreadPool::workerJobLoop(int id) VL_MT_SAFE { job_t job; { V3LockGuard lock(m_mutex); - m_cv.wait(lock, [&]() VL_REQUIRES(m_mutex) { + m_cv.wait(m_mutex, [&]() VL_REQUIRES(m_mutex) { return !m_queue.empty() || m_shutdown || m_stopRequested; }); if (m_shutdown) return; // Terminate if requested @@ -100,9 +104,9 @@ void V3ThreadPool::requestExclusiveAccess(const V3ThreadPool::job_t&& exclusiveA V3LockGuard stoppedJobLock{m_stoppedJobsMutex}; // if some other job already requested exclusive access // wait until it stops - if (stopRequested()) { waitStopRequested(stoppedJobLock); } + if (stopRequested()) { waitStopRequested(); } m_stopRequested = true; - waitOtherThreads(stoppedJobLock); + waitOtherThreads(); m_exclusiveAccess = true; exclusiveAccessJob(); m_exclusiveAccess = false; @@ -114,25 +118,26 @@ void V3ThreadPool::requestExclusiveAccess(const V3ThreadPool::job_t&& exclusiveA bool V3ThreadPool::waitIfStopRequested() VL_MT_SAFE { V3LockGuard stoppedJobLock(m_stoppedJobsMutex); if (!stopRequested()) return false; - waitStopRequested(stoppedJobLock); + waitStopRequested(); return true; } -void V3ThreadPool::waitStopRequested(V3LockGuard& stoppedJobLock) VL_REQUIRES(m_stoppedJobsMutex) { +void V3ThreadPool::waitStopRequested() VL_REQUIRES(m_stoppedJobsMutex) { ++m_stoppedJobs; m_stoppedJobsCV.notify_all(); - m_stoppedJobsCV.wait( - stoppedJobLock, [&]() VL_REQUIRES(m_stoppedJobsMutex) { return !m_stopRequested.load(); }); + m_stoppedJobsCV.wait(m_stoppedJobsMutex, [&]() VL_REQUIRES(m_stoppedJobsMutex) { + return !m_stopRequested.load(); + }); --m_stoppedJobs; m_stoppedJobsCV.notify_all(); } -void V3ThreadPool::waitOtherThreads(V3LockGuard& stoppedJobLock) VL_MT_SAFE_EXCLUDES(m_mutex) +void V3ThreadPool::waitOtherThreads() VL_MT_SAFE_EXCLUDES(m_mutex) VL_REQUIRES(m_stoppedJobsMutex) { ++m_stoppedJobs; m_stoppedJobsCV.notify_all(); m_cv.notify_all(); - m_stoppedJobsCV.wait(stoppedJobLock, [&]() VL_REQUIRES(m_stoppedJobsMutex) { + m_stoppedJobsCV.wait(m_stoppedJobsMutex, [&]() VL_REQUIRES(m_stoppedJobsMutex) { // count also the main thread return m_stoppedJobs == (m_workers.size() + 1); }); @@ -152,19 +157,20 @@ void V3ThreadPool::selfTest() { }); }; auto secondJob = [&](int sleep) -> void { - V3LockGuard lock{commonMutex}; - lock.unlock(); + commonMutex.lock(); + commonMutex.unlock(); s().waitIfStopRequested(); - lock.lock(); + V3LockGuard lock{commonMutex}; std::this_thread::sleep_for(std::chrono::milliseconds{sleep}); commonValue = 1000; }; auto thirdJob = [&](int sleep) -> void { - V3LockGuard lock{commonMutex}; - std::this_thread::sleep_for(std::chrono::milliseconds{sleep}); - lock.unlock(); + { + V3LockGuard lock{commonMutex}; + std::this_thread::sleep_for(std::chrono::milliseconds{sleep}); + } s().requestExclusiveAccess([&]() { firstJob(sleep); }); - lock.lock(); + V3LockGuard lock{commonMutex}; commonValue = 1000; }; std::list> futures; diff --git a/src/V3ThreadPool.h b/src/V3ThreadPool.h index 69e093fcc..1f4f32f95 100644 --- a/src/V3ThreadPool.h +++ b/src/V3ThreadPool.h @@ -67,9 +67,10 @@ class V3ThreadPool final { // CONSTRUCTORS V3ThreadPool() = default; ~V3ThreadPool() { - V3LockGuard lock{m_mutex}; - m_queue = {}; // make sure queue is empty - lock.unlock(); + { + V3LockGuard lock{m_mutex}; + m_queue = {}; // make sure queue is empty + } resize(0); } @@ -82,7 +83,7 @@ public: } // Resize thread pool to n workers (queue must be empty) - void resize(unsigned n) VL_MT_UNSAFE; + void resize(unsigned n) VL_MT_UNSAFE VL_EXCLUDES(m_mutex) VL_EXCLUDES(m_stoppedJobsMutex); // Enqueue a job for asynchronous execution // Due to missing support for lambda annotations in c++11, @@ -165,11 +166,10 @@ private: } // Waits until exclusive access job completes its job - void waitStopRequested(V3LockGuard& stoppedJobLock) VL_REQUIRES(m_stoppedJobsMutex); + void waitStopRequested() VL_REQUIRES(m_stoppedJobsMutex); // Waits until all other jobs are stopped - void waitOtherThreads(V3LockGuard& stoppedJobLock) VL_MT_SAFE_EXCLUDES(m_mutex) - VL_REQUIRES(m_stoppedJobsMutex); + void waitOtherThreads() VL_MT_SAFE_EXCLUDES(m_mutex) VL_REQUIRES(m_stoppedJobsMutex); template void pushJob(std::shared_ptr>& prom, std::function&& f) VL_MT_SAFE; From 46f719ceaaa658a2c51cf974b548b635fc276593 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 13 May 2023 20:15:03 -0400 Subject: [PATCH 048/129] Tests: Fix some coverage holes --- test_regress/t/t_array_pattern_bad3.out | 13 ++++++++++++ test_regress/t/t_array_pattern_bad3.pl | 19 +++++++++++++++++ test_regress/t/t_array_pattern_bad3.v | 25 +++++++++++++++++++++++ test_regress/t/t_clocked_release_combo.pl | 2 +- test_regress/t/t_dist_warn_coverage.pl | 7 +++---- test_regress/t/t_dpi_import_mix_bad.out | 4 ++++ test_regress/t/t_dpi_import_mix_bad.pl | 19 +++++++++++++++++ test_regress/t/t_dpi_import_mix_bad.v | 18 ++++++++++++++++ 8 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 test_regress/t/t_array_pattern_bad3.out create mode 100755 test_regress/t/t_array_pattern_bad3.pl create mode 100644 test_regress/t/t_array_pattern_bad3.v create mode 100644 test_regress/t/t_dpi_import_mix_bad.out create mode 100755 test_regress/t/t_dpi_import_mix_bad.pl create mode 100644 test_regress/t/t_dpi_import_mix_bad.v diff --git a/test_regress/t/t_array_pattern_bad3.out b/test_regress/t/t_array_pattern_bad3.out new file mode 100644 index 000000000..dd393b336 --- /dev/null +++ b/test_regress/t/t_array_pattern_bad3.out @@ -0,0 +1,13 @@ +%Error: t/t_array_pattern_bad3.v:20:15: Assignment pattern key used multiple times: 1 + : ... In instance t + 20 | 1: '1}; + | ^ +%Error: t/t_array_pattern_bad3.v:21:13: Assignment pattern with too many elements + : ... In instance t + 21 | arr = '{'0, '1, '0, '1}; + | ^~ +%Error: t/t_array_pattern_bad3.v:22:13: Assignment pattern missed initializing elements: 2 + : ... In instance t + 22 | arr = '{'0, '1}; + | ^~ +%Error: Exiting due to diff --git a/test_regress/t/t_array_pattern_bad3.pl b/test_regress/t/t_array_pattern_bad3.pl new file mode 100755 index 000000000..a60503a1f --- /dev/null +++ b/test_regress/t/t_array_pattern_bad3.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(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_array_pattern_bad3.v b/test_regress/t/t_array_pattern_bad3.v new file mode 100644 index 000000000..a646ecca9 --- /dev/null +++ b/test_regress/t/t_array_pattern_bad3.v @@ -0,0 +1,25 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2018 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// bug1364 + +module t (/*AUTOARG*/ + // Inputs + clk, res + ); + input clk; + input res; + + int arr[3]; + initial begin + arr = '{default: '0, + 1: '0, + 1: '1}; // Bad + arr = '{'0, '1, '0, '1}; // Bad, too many + arr = '{'0, '1}; // Bad, too few + end + +endmodule diff --git a/test_regress/t/t_clocked_release_combo.pl b/test_regress/t/t_clocked_release_combo.pl index fcd9221f5..859050d63 100755 --- a/test_regress/t/t_clocked_release_combo.pl +++ b/test_regress/t/t_clocked_release_combo.pl @@ -2,7 +2,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } # DESCRIPTION: Verilator: Verilog Test driver/expect definition # -# Copyright 2023 by Antmicro Ltd. This program is free software; you +# Copyright 2023 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. diff --git a/test_regress/t/t_dist_warn_coverage.pl b/test_regress/t/t_dist_warn_coverage.pl index 234e2bce3..bddd75ed5 100755 --- a/test_regress/t/t_dist_warn_coverage.pl +++ b/test_regress/t/t_dist_warn_coverage.pl @@ -38,14 +38,11 @@ foreach my $s ( 'Array initialization has too few elements, need element ', 'Assert not allowed under another assert', 'Assigned pin is neither input nor output', - 'Assignment pattern key used multiple times: ', 'Assignment pattern with no members', - 'Assignment pattern with too many elements', 'Attempted parameter setting of non-parameter: Param ', 'Can\'t find typedef: ', 'Can\'t find varpin scope of ', 'Can\'t resolve module reference: \'', - 'Cannot mix DPI import, DPI export, class methods, and/or public ', 'Cannot write preprocessor output: ', 'Circular logic when ordering code (non-cutable edge loop)', 'Deferred assertions must use \'#0\' (IEEE 1800-2017 16.4)', @@ -161,12 +158,14 @@ sub check { print(" Line is: ", $line, "\n") if $Debug; } } + print "\n"; for my $msg (sort keys %Suppressed) { if (!$used_suppressed{$msg}) { print "Suppression not used: '$msg'\n"; } - } + } + print "\n"; } sub read_messages { diff --git a/test_regress/t/t_dpi_import_mix_bad.out b/test_regress/t/t_dpi_import_mix_bad.out new file mode 100644 index 000000000..ef362e51b --- /dev/null +++ b/test_regress/t/t_dpi_import_mix_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_dpi_import_mix_bad.v:11:32: Cannot mix DPI import, DPI export, class methods, and/or public on same function: 't.foo' + 11 | import "DPI-C" function int foo (int i); + | ^~~ +%Error: Exiting due to diff --git a/test_regress/t/t_dpi_import_mix_bad.pl b/test_regress/t/t_dpi_import_mix_bad.pl new file mode 100755 index 000000000..a60503a1f --- /dev/null +++ b/test_regress/t/t_dpi_import_mix_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 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(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_dpi_import_mix_bad.v b/test_regress/t/t_dpi_import_mix_bad.v new file mode 100644 index 000000000..e924d2f94 --- /dev/null +++ b/test_regress/t/t_dpi_import_mix_bad.v @@ -0,0 +1,18 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 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 + +module t (); + + import "DPI-C" function int foo (int i); + export "DPI-C" function foo; // Bad mix + + initial begin + $stop; + end + +endmodule From 2ce7a348dfbc6f16eb744064b26a1e9184768a71 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Tue, 16 May 2023 01:50:04 +0200 Subject: [PATCH 049/129] Fix references to members of parameterized base classes (#4196) --- src/V3AstNodeOther.h | 8 +- src/V3AstNodes.cpp | 19 ++- src/V3LinkDot.cpp | 225 ++++++++++++++----------- test_regress/t/t_class_param_extends.v | 36 ++++ 4 files changed, 180 insertions(+), 108 deletions(-) diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index fc998872b..960f10d09 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -809,6 +809,8 @@ class AstClassExtends final : public AstNode { // @astgen op1 := childDTypep : Optional[AstNodeDType] // @astgen op2 := classOrPkgsp : Optional[AstNode] const bool m_isImplements = false; // class implements + bool m_parameterized = false; // has parameters in its statement + public: AstClassExtends(FileLine* fl, AstNode* classOrPkgsp, bool isImplements) : ASTGEN_SUPER_ClassExtends(fl) @@ -819,8 +821,12 @@ public: void dump(std::ostream& str) const override; bool hasDType() const override { return true; } string verilogKwd() const override { return isImplements() ? "implements" : "extends"; } - AstClass* classp() const; // Class being extended (after link) + // Class being extended (after link and instantiation if needed) + AstClass* classOrNullp() const; + AstClass* classp() const; // Like above, but throws error if nulll bool isImplements() const { return m_isImplements; } + void parameterized(bool flag) { m_parameterized = flag; } + bool parameterized() const { return m_parameterized; } }; class AstClocking final : public AstNode { // Parents: MODULE diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 46f5e53d7..0f3fa80a4 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1501,13 +1501,20 @@ void AstClassExtends::dump(std::ostream& str) const { this->AstNode::dump(str); if (isImplements()) str << " [IMPLEMENTS]"; } -AstClass* AstClassExtends::classp() const { - const AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType); - if (VL_UNLIKELY(!refp)) { // LinkDot uses this for 'super.' - refp = VN_AS(childDTypep(), ClassRefDType); +AstClass* AstClassExtends::classOrNullp() const { + const AstNodeDType* const dtp = dtypep() ? dtypep() : childDTypep(); + const AstClassRefDType* const refp = VN_CAST(dtp, ClassRefDType); + if (refp && !refp->paramsp()) { + // Class already resolved + return refp->classp(); + } else { + return nullptr; } - UASSERT_OBJ(refp, this, "class extends non-ref"); - return refp->classp(); +} +AstClass* AstClassExtends::classp() const { + AstClass* const clsp = classOrNullp(); + UASSERT_OBJ(clsp, this, "Extended class is unresolved"); + return clsp; } void AstClassRefDType::dump(std::ostream& str) const { this->AstNodeDType::dump(str); diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index ca1965964..dd39277b6 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2020,9 +2020,10 @@ private: int m_modportNum = 0; // Uniqueify modport numbers bool m_inSens = false; // True if in senitem std::set m_ifClassImpNames; // Names imported from interface class - std::set m_extendsParam; // Classes that has a parameter as its super class - bool m_insideClassExtParam = false; // Inside a class that extends a parameter. - // It may be set only in linkDotPrimary. + std::set m_extendsParam; // Classes that have a parameterized super class + // (except the default instances) + // They are added to the set only in linkDotPrimary. + bool m_insideClassExtParam = false; // Inside a class from m_extendsParam struct DotStates { DotPosition m_dotPos; // Scope part of dotted resolution @@ -3273,6 +3274,86 @@ private: // No checknodot(nodep), visit(AstScope) will check for LambdaArgRef iterateChildren(nodep); } + void visit(AstClassExtends* nodep) override { + // Resolve the symbol and get the class. + // If it is a parameterized case, the class will be resolved after V3Param.cpp + if (nodep->user3SetOnce()) return; + // If the class is resolved, there is nothing more to do + if (nodep->classOrNullp()) return; + if (m_statep->forPrimary()) { + AstNode* cprp = nodep->classOrPkgsp(); + VSymEnt* lookSymp = m_curSymp; + if (AstDot* const dotp = VN_CAST(cprp, Dot)) { + dotp->user3(true); + if (AstClassOrPackageRef* lookNodep = VN_CAST(dotp->lhsp(), ClassOrPackageRef)) { + iterate(lookNodep); + cprp = dotp->rhsp(); + lookSymp = m_statep->getNodeSym(lookNodep->classOrPackagep()); + } else { + dotp->lhsp()->v3error("Attempting to extend" // LCOV_EXCL_LINE + " using non-class under dot"); + } + } + AstClassOrPackageRef* const cpackagerefp = VN_CAST(cprp, ClassOrPackageRef); + if (VL_UNCOVERABLE(!cpackagerefp)) { + // Linking the extend gives an error before this is hit + nodep->v3error("Attempting to extend using non-class"); // LCOV_EXCL_LINE + return; + } + VSymEnt* const foundp = lookSymp->findIdFallback(cpackagerefp->name()); + if (foundp) { + if (AstClass* const classp = VN_CAST(foundp->nodep(), Class)) { + AstPin* paramsp = cpackagerefp->paramsp(); + if (paramsp) { + paramsp = paramsp->cloneTree(true); + nodep->parameterized(true); + } + nodep->childDTypep(new AstClassRefDType{nodep->fileline(), classp, paramsp}); + // Link pins + iterate(nodep->childDTypep()); + } else if (AstParamTypeDType* const paramp + = VN_CAST(foundp->nodep(), ParamTypeDType)) { + AstRefDType* const refParamp + = new AstRefDType{nodep->fileline(), paramp->name()}; + refParamp->refDTypep(paramp); + nodep->childDTypep(refParamp); + nodep->parameterized(true); + } else { + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: " << foundp->nodep()->prettyTypeName() + << " in AstClassExtends"); + return; + } + } else { + const string suggest = m_statep->suggestSymFallback( + m_curSymp, cpackagerefp->name(), LinkNodeMatcherClass{}); + cpackagerefp->v3error( + "Class for '" << nodep->verilogKwd() // extends/implements + << "' not found: " << cpackagerefp->prettyNameQ() << '\n' + << (suggest.empty() ? "" : cpackagerefp->warnMore() + suggest)); + return; + } + if (!nodep->childDTypep()) nodep->v3error("Attempting to extend using non-class"); + nodep->classOrPkgsp()->unlinkFrBack()->deleteTree(); + } else { + // Probably a parameter + if (AstRefDType* const refp = VN_CAST(nodep->childDTypep(), RefDType)) { + if (AstClassRefDType* classRefp = VN_CAST(refp->skipRefp(), ClassRefDType)) { + // Resolved to a class reference. + refp->replaceWith(classRefp->cloneTree(false)); + } else { + // Unable to resolve the ref type to a class reference. + // Get the value of type parameter passed to the class instance, + // to print the helpful error message. + const AstNodeDType* typep = refp->refDTypep(); + if (const AstParamTypeDType* const paramp = VN_CAST(typep, ParamTypeDType)) { + typep = paramp->subDTypep(); + } + typep->v3error("Attempting to extend using non-class"); + } + } + } + } void visit(AstClass* nodep) override { if (nodep->user3SetOnce()) return; UINFO(5, " " << nodep << endl); @@ -3295,110 +3376,50 @@ private: cextp->v3error("Multiple inheritance illegal on non-interface classes" " (IEEE 1800-2017 8.13)"); } - if (cextp->childDTypep() || cextp->dtypep()) { + iterate(cextp); + if (m_statep->forPrimary()) { + if (cextp->parameterized()) { + // Parameters in extends statement. + // The class can't be resolved in the current pass. + m_extendsParam.insert(nodep); + m_insideClassExtParam = true; + } + if (AstClassRefDType* const classRefp + = VN_CAST(cextp->childDTypep(), ClassRefDType)) { + AstClass* const classp = classRefp->classp(); + if (classp != nodep) iterate(classp); + if (m_extendsParam.find(classp) != m_extendsParam.end()) { + // One of its super classes has parameters in extends statement. + // Some links may not be resolved in the first pass. + m_extendsParam.insert(nodep); + m_insideClassExtParam = true; + } + } + } + + if (AstClass* const classp = cextp->classOrNullp()) { // Already converted. Update symbol table to link unlinked members. // Base class has to be visited in a case if its extends statement // needs to be handled. Recursive inheritance was already checked. - iterate(cextp->classp()); + if (classp == nodep) { + cextp->v3error("Attempting to extend class " << nodep->prettyNameQ() + << " from itself"); + } else if (cextp->isImplements() && !classp->isInterfaceClass()) { + cextp->v3error("Attempting to implement from non-interface class " + << classp->prettyNameQ() << '\n' + << "... Suggest use 'extends'"); + } else if (!cextp->isImplements() && !nodep->isInterfaceClass() + && classp->isInterfaceClass()) { + cextp->v3error("Attempting to extend from interface class " + << classp->prettyNameQ() << '\n' + << "... Suggest use 'implements'"); + } + classp->isExtended(true); + nodep->isExtended(true); + iterate(classp); importSymbolsFromExtended(nodep, cextp); continue; } - AstNode* cprp = cextp->classOrPkgsp(); - VSymEnt* lookSymp = m_curSymp; - if (AstDot* const dotp = VN_CAST(cprp, Dot)) { - dotp->user3(true); - if (AstClassOrPackageRef* lookNodep - = VN_CAST(dotp->lhsp(), ClassOrPackageRef)) { - iterate(lookNodep); - cprp = dotp->rhsp(); - lookSymp = m_statep->getNodeSym(lookNodep->classOrPackagep()); - } else { - dotp->lhsp()->v3error("Attempting to extend" // LCOV_EXCL_LINE - " using non-class under dot"); - } - } - AstClassOrPackageRef* const cpackagerefp = VN_CAST(cprp, ClassOrPackageRef); - if (VL_UNCOVERABLE(!cpackagerefp)) { - // Linking the extend gives an error before this is hit - cextp->v3error("Attempting to extend using non-class"); // LCOV_EXCL_LINE - } else { - VSymEnt* const foundp = lookSymp->findIdFallback(cpackagerefp->name()); - if (foundp) { - AstClassRefDType* classRefDtypep = nullptr; - AstClass* classp = VN_CAST(foundp->nodep(), Class); - if (classp) { - if (classp != nodep) { - // Case with recursive inheritance is handled later in this - // function - iterate(classp); - } - if (m_statep->forPrimary() - && m_extendsParam.find(classp) != m_extendsParam.end()) { - // Has a parameter as its base class - m_extendsParam.insert(nodep); - m_insideClassExtParam = true; - } - AstPin* paramsp = cpackagerefp->paramsp(); - if (paramsp) paramsp = paramsp->cloneTree(true); - classRefDtypep - = new AstClassRefDType{nodep->fileline(), classp, paramsp}; - } else if (AstParamTypeDType* const paramp - = VN_CAST(foundp->nodep(), ParamTypeDType)) { - if (m_statep->forPrimary()) { - // Extending has to be handled after V3Param.cpp - m_extendsParam.insert(nodep); - m_insideClassExtParam = true; - continue; - } else { - AstNodeDType* const paramTypep = paramp->subDTypep(); - classRefDtypep - = VN_CAST(paramTypep->cloneTree(false), ClassRefDType); - if (!classRefDtypep) { - paramTypep->v3error("Attempting to extend using non-class"); - } else { - classp = classRefDtypep->classp(); - } - } - } else { - cextp->v3warn(E_UNSUPPORTED, - "Unsupported: " << foundp->nodep()->prettyTypeName() - << " in AstClassExtends"); - } - - if (classp) { - UINFO(8, "Import to " << nodep << " from export class " << classp - << endl); - if (classp == nodep) { - cextp->v3error("Attempting to extend class " - << nodep->prettyNameQ() << " from itself"); - } else if (cextp->isImplements() && !classp->isInterfaceClass()) { - cextp->v3error("Attempting to implement from non-interface class " - << classp->prettyNameQ() << '\n' - << "... Suggest use 'extends'"); - } else if (!cextp->isImplements() && !nodep->isInterfaceClass() - && classp->isInterfaceClass()) { - cextp->v3error("Attempting to extend from interface class " - << classp->prettyNameQ() << '\n' - << "... Suggest use 'implements'"); - } else { - cextp->childDTypep(classRefDtypep); - classp->isExtended(true); - nodep->isExtended(true); - importSymbolsFromExtended(nodep, cextp); - VL_DO_DANGLING(cextp->classOrPkgsp()->unlinkFrBack()->deleteTree(), - cpackagerefp); - } - } - } else { - const string suggest = m_statep->suggestSymFallback( - m_curSymp, cpackagerefp->name(), LinkNodeMatcherClass{}); - cpackagerefp->v3error( - "Class for '" - << cextp->verilogKwd() // extends/implements - << "' not found: " << cpackagerefp->prettyNameQ() << '\n' - << (suggest.empty() ? "" : cpackagerefp->warnMore() + suggest)); - } - } } m_ds.m_dotSymp = m_curSymp; @@ -3491,6 +3512,8 @@ private: nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); return; + } else if (m_insideClassExtParam) { + return; } else { if (foundp) UINFO(1, "Found sym node: " << foundp->nodep() << endl); nodep->v3error("Can't find typedef: " << nodep->prettyNameQ()); diff --git a/test_regress/t/t_class_param_extends.v b/test_regress/t/t_class_param_extends.v index 1c1078ea7..e63ccb0b5 100644 --- a/test_regress/t/t_class_param_extends.v +++ b/test_regress/t/t_class_param_extends.v @@ -21,16 +21,49 @@ endclass typedef Cls#(8) Cls8_t; +class Getter1; + function int get_int; + return 1; + endfunction +endclass + +class Getter2; + function int get_int; + return 2; + endfunction +endclass + +class Foo #(type T=Getter1); + int x; + function new(int y); + x = y; + endfunction +endclass + +class Bar #(type S=Getter2) extends Foo#(S); + T field; + function new(int y); + super.new(y); + field = new; + endfunction + + function int get_field_int; + return field.get_int(); + endfunction +endclass + // See also t_class_param_mod.v module t (/*AUTOARG*/); Cls #(.P(4)) c4; Cls8_t c8; + Bar b; initial begin c4 = new; c8 = new; + b = new(1); if (c4.PBASE != 4) $stop; if (c8.PBASE != 8) $stop; if (c4.get_p() != 4) $stop; @@ -46,6 +79,9 @@ module t (/*AUTOARG*/); $display("c4 = %s", $sformatf("%p", c4)); if ($sformatf("%p", c4) != "'{member:'ha}") $stop; + if (b.x != 1) $stop; + if (b.get_field_int() != 2) $stop; + $write("*-* All Finished *-*\n"); $finish; end From 279216048b33dd5ffef06a40200aaf4613eac17d Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Tue, 16 May 2023 13:40:02 +0200 Subject: [PATCH 050/129] Fix dotted references in parameterized classes (#4206) --- src/V3LinkDot.cpp | 90 ++++++++++++++------------ test_regress/t/t_class_param_extends.v | 7 ++ 2 files changed, 56 insertions(+), 41 deletions(-) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index dd39277b6..72c3f762c 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2772,49 +2772,57 @@ private: } } } - // Don't throw error ifthe reference is inside a class that extends a param, because - // some members can't be linked in such a case. m_insideClassExtParam may be true only - // in the first stage of linking. - if (!ok && !m_insideClassExtParam) { - // Cells/interfaces can't be implicit - const bool isCell = foundp ? VN_IS(foundp->nodep(), Cell) : false; - const bool checkImplicit = (!m_ds.m_dotp && m_ds.m_dotText == "" && !isCell); - const bool err = !(checkImplicit && m_statep->implicitOk(m_modp, nodep->name())); - if (err) { - if (foundp) { - nodep->v3error("Found definition of '" - << m_ds.m_dotText << (m_ds.m_dotText == "" ? "" : ".") - << nodep->prettyName() << "'" - << " as a " << foundp->nodep()->typeName() - << " but expected a " << expectWhat); - } else if (m_ds.m_dotText == "") { - UINFO(7, " ErrParseRef curSymp=se" << cvtToHex(m_curSymp) - << " ds=" << m_ds.ascii() << endl); - const string suggest = m_statep->suggestSymFallback( - m_ds.m_dotSymp, nodep->name(), VNodeMatcher{}); - nodep->v3error("Can't find definition of " - << expectWhat << ": " << nodep->prettyNameQ() << '\n' - << (suggest.empty() ? "" : nodep->warnMore() + suggest)); - } else { - nodep->v3error("Can't find definition of " - << (!baddot.empty() ? AstNode::prettyNameQ(baddot) - : nodep->prettyNameQ()) - << " in dotted " << expectWhat << ": '" - << m_ds.m_dotText + "." + nodep->prettyName() << "'"); - if (okSymp) { - okSymp->cellErrorScopes(nodep, AstNode::prettyName(m_ds.m_dotText)); + if (!ok) { + if (m_insideClassExtParam) { + // Don't throw error if the reference is inside a class that extends a param, + // because some members can't be linked in such a case. m_insideClassExtParam + // may be true only in the first stage of linking. + // Mark that the Dot statement can't be resolved. + m_ds.m_unresolvedClass = true; + } else { + // Cells/interfaces can't be implicit + const bool isCell = foundp ? VN_IS(foundp->nodep(), Cell) : false; + const bool checkImplicit = (!m_ds.m_dotp && m_ds.m_dotText == "" && !isCell); + const bool err + = !(checkImplicit && m_statep->implicitOk(m_modp, nodep->name())); + if (err) { + if (foundp) { + nodep->v3error("Found definition of '" + << m_ds.m_dotText << (m_ds.m_dotText == "" ? "" : ".") + << nodep->prettyName() << "'" + << " as a " << foundp->nodep()->typeName() + << " but expected a " << expectWhat); + } else if (m_ds.m_dotText == "") { + UINFO(7, " ErrParseRef curSymp=se" + << cvtToHex(m_curSymp) << " ds=" << m_ds.ascii() << endl); + const string suggest = m_statep->suggestSymFallback( + m_ds.m_dotSymp, nodep->name(), VNodeMatcher{}); + nodep->v3error( + "Can't find definition of " + << expectWhat << ": " << nodep->prettyNameQ() << '\n' + << (suggest.empty() ? "" : nodep->warnMore() + suggest)); + } else { + nodep->v3error("Can't find definition of " + << (!baddot.empty() ? AstNode::prettyNameQ(baddot) + : nodep->prettyNameQ()) + << " in dotted " << expectWhat << ": '" + << m_ds.m_dotText + "." + nodep->prettyName() << "'"); + if (okSymp) { + okSymp->cellErrorScopes(nodep, + AstNode::prettyName(m_ds.m_dotText)); + } } + m_ds.m_dotErr = true; + } + if (checkImplicit) { + // Create if implicit, and also if error (so only complain once) + // Else if a scope is allowed, making a signal won't help error cascade + AstVarRef* const newp + = new AstVarRef{nodep->fileline(), nodep->name(), VAccess::READ}; + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + createImplicitVar(m_curSymp, newp, m_modp, m_modSymp, err); } - m_ds.m_dotErr = true; - } - if (checkImplicit) { - // Create if implicit, and also if error (so only complain once) - // Else if a scope is allowed, making a signal won't help error cascade - AstVarRef* const newp - = new AstVarRef{nodep->fileline(), nodep->name(), VAccess::READ}; - nodep->replaceWith(newp); - VL_DO_DANGLING(pushDeletep(nodep), nodep); - createImplicitVar(m_curSymp, newp, m_modp, m_modSymp, err); } } } diff --git a/test_regress/t/t_class_param_extends.v b/test_regress/t/t_class_param_extends.v index e63ccb0b5..5e59c09d2 100644 --- a/test_regress/t/t_class_param_extends.v +++ b/test_regress/t/t_class_param_extends.v @@ -34,8 +34,10 @@ class Getter2; endclass class Foo #(type T=Getter1); + T foo_field; int x; function new(int y); + foo_field = new; x = y; endfunction endclass @@ -50,6 +52,10 @@ class Bar #(type S=Getter2) extends Foo#(S); function int get_field_int; return field.get_int(); endfunction + + function int get_foo_field_int; + return foo_field.get_int(); + endfunction endclass // See also t_class_param_mod.v @@ -81,6 +87,7 @@ module t (/*AUTOARG*/); if (b.x != 1) $stop; if (b.get_field_int() != 2) $stop; + if (b.get_foo_field_int() != 2) $stop; $write("*-* All Finished *-*\n"); $finish; From 729f8b9334ce01d289e31e59a126f1611b20736b Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Wed, 17 May 2023 19:09:33 +0200 Subject: [PATCH 051/129] Move suspendable detection to a separate visitor (#4208) This makes the implementation of the detection and propagation of the suspendable property simpler and easier to read. More importantly, there are no more jumps around the AST with the `visit` functions, which in some cases could result in incorrect visitor context while in the `visit` function. See the added test, which would cause Verilator to segfault before this patch. In testing, verilation performance was not shown to be affected by this change. Though there is a slight performance improvement from this patch, due to adding one more check before refreshing class member cache. Signed-off-by: Krzysztof Bieganski --- docs/internals.rst | 28 ++- src/V3Timing.cpp | 288 ++++++++++++++++----------- test_regress/t/t_semaphore_always.pl | 27 +++ test_regress/t/t_semaphore_always.v | 23 +++ 4 files changed, 246 insertions(+), 120 deletions(-) create mode 100755 test_regress/t/t_semaphore_always.pl create mode 100644 test_regress/t/t_semaphore_always.v diff --git a/docs/internals.rst b/docs/internals.rst index ecd9dc5f2..ca4b626e4 100644 --- a/docs/internals.rst +++ b/docs/internals.rst @@ -638,7 +638,22 @@ condition. See the `Timing Pass` section for more details. Timing Pass ~~~~~~~~~~~ -The visitor in ``V3Timing.cpp`` transforms each timing control into a ``co_await``. +There are two visitors in ``V3Timing.cpp``. + +The first one, ``TimingSuspendableVisitor``, does not perform any AST +transformations. It is responsible for marking processes and C++ functions that +contain timing controls as suspendable. Processes that call suspendable +functions are also marked as suspendable. Functions that call, are overridden +by, or override suspendable functions are marked as suspendable as well. + +The visitor keeps a dependency graph of functions and processes to handle such +cases. A function or process is dependent on a function if it calls it. A +virtual class method is dependent on another class method if it calls it, +overrides it, or is overriden by it. + +The second visitor in ``V3Timing.cpp``, ``TimingControlVisitor``, uses the +information provided by ``TimingSuspendableVisitor`` and transforms each timing +control into a ``co_await``. * event controls are turned into ``co_await`` on a trigger scheduler's ``trigger`` method. The awaited trigger scheduler is the one corresponding to @@ -670,14 +685,9 @@ Each sub-statement of a ``fork`` is put in an ``AstBegin`` node for easier grouping. In a later step, each of these gets transformed into a new, separate function. See the `Forks` section for more detail. -Processes that use awaits are marked as suspendable. Later, during ``V3Sched``, -they are transformed into coroutines. Functions that use awaits get the return -type of ``VlCoroutine``. This immediately makes them coroutines. Note that if a -process calls a function that is a coroutine, the call gets wrapped in an -await, which means the process itself will be marked as suspendable. A virtual -function is a coroutine if any of its overriding or overridden functions are -coroutines. The visitor keeps a dependency graph of functions and processes to -handle such cases. +Suspendable functions get the return type of ``VlCoroutine``, which makes them +coroutines. Later, during ``V3Sched``, suspendable processes are also +transformed into coroutines. Scheduling with timing ~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index 8d520a413..a49761636 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -12,7 +12,13 @@ // Version 2.0. // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 // -// TimingVisitor transformations: +// TimingSuspendableVisitor locates all C++ functions and processes that contain timing controls, +// and marks them as suspendable. If a process calls a suspendable function, then it is also marked +// as suspendable. If a function calls or overrides a suspendable function, it is also marked as +// suspendable. TimingSuspendableVisitor creates a dependency graph to propagate this property. It +// does not perform any AST transformations. +// +// TimingControlVisitor is the one that actually performs transformations: // - for each intra-assignment timing control: // - if it's a continuous assignment, transform it into an always // - introduce an intermediate variable @@ -33,9 +39,6 @@ // - if it's not a fork..join_none: // - create a join sync variable // - create statements that sync the main process with its children -// - for each process or C++ function, if it has CAwait statements, mark it as suspendable -// - if we mark a virtual function as suspendable, mark all overriding and overridden functions -// as suspendable, as well as calling processes // // See the internals documentation docs/internals.rst for more details. // @@ -57,15 +60,16 @@ VL_DEFINE_DEBUG_FUNCTIONS; // ###################################################################### -// Transform nodes affected by timing +// Detect nodes affected by timing -class TimingVisitor final : public VNVisitor { +class TimingSuspendableVisitor final : public VNVisitor { private: // TYPES // Vertex of a dependency graph of suspendable nodes, e.g. if a node (process or task) is // suspendable, all its dependents should also be suspendable - class DependencyVertex final : public V3GraphVertex { + class TimingDependencyVertex final : public V3GraphVertex { AstNode* const m_nodep; // AST node represented by this graph vertex + // ACCESSORS string name() const override VL_MT_STABLE { return cvtToHex(nodep()) + ' ' + nodep()->prettyTypeName(); @@ -75,29 +79,153 @@ private: public: // CONSTRUCTORS - DependencyVertex(V3Graph* graphp, AstNode* nodep) + TimingDependencyVertex(V3Graph* graphp, AstNode* nodep) : V3GraphVertex{graphp} , m_nodep{nodep} {} - ~DependencyVertex() override = default; + ~TimingDependencyVertex() override = default; // ACCESSORS virtual AstNode* nodep() const VL_MT_STABLE { return m_nodep; } }; // NODE STATE - // AstNode::user1() -> bool. Set true if the node has been - // processed. - // AstSenTree::user1() -> AstVarScope*. Trigger scheduler assigned - // to this sentree - // Ast{NodeProcedure,CFunc,Begin}::user2() -> bool. Set true if process/task is - // suspendable - // AstSenTree::user2() -> AstCExpr*. Debug info passed to the - // timing schedulers + // AstClass::user1() -> bool. Set true if the class + // member cache has been + // refreshed. + // Ast{NodeProcedure,CFunc,Begin}::user2() -> bool. Set true if process/task is + // suspendable // Ast{NodeProcedure,CFunc,Begin}::user3() -> DependencyVertex*. Vertex in m_depGraph const VNUser1InUse m_user1InUse; const VNUser2InUse m_user2InUse; const VNUser3InUse m_user3InUse; + // STATE + AstClass* m_classp = nullptr; // Current class + AstNode* m_procp = nullptr; // NodeProcedure/CFunc/Begin we're under + V3Graph m_depGraph; // Dependency graph where a node is a dependency of another if it being + // suspendable makes the other node suspendable + + // METHODS + // Get or create the dependency vertex for the given node + TimingDependencyVertex* getDependencyVertex(AstNode* const nodep) { + if (!nodep->user3p()) nodep->user3p(new TimingDependencyVertex{&m_depGraph, nodep}); + return nodep->user3u().to(); + } + // Propagate suspendable flag to all nodes that depend on the given one + void propagateSuspendable(TimingDependencyVertex* const vxp) { + for (V3GraphEdge* edgep = vxp->inBeginp(); edgep; edgep = edgep->inNextp()) { + auto* const depVxp = static_cast(edgep->fromp()); + AstNode* const depp = depVxp->nodep(); + if (!depp->user2()) { + depp->user2(true); + propagateSuspendable(depVxp); + } + } + } + + // VISITORS + void visit(AstClass* nodep) override { + UASSERT(!m_classp, "Class under class"); + VL_RESTORER(m_classp); + m_classp = nodep; + iterateChildren(nodep); + } + void visit(AstNodeProcedure* nodep) override { + VL_RESTORER(m_procp); + m_procp = nodep; + iterateChildren(nodep); + } + void visit(AstCFunc* nodep) override { + VL_RESTORER(m_procp); + m_procp = nodep; + iterateChildren(nodep); + TimingDependencyVertex* const vxp = getDependencyVertex(nodep); + if (!m_classp) return; + // If class method (possibly overrides another method) + if (!m_classp->user1SetOnce()) m_classp->repairCache(); + // Go over overridden functions + for (auto* cextp = m_classp->extendsp(); cextp; + cextp = VN_AS(cextp->nextp(), ClassExtends)) { + // TODO: It is possible that a methods the same name in the base class is not + // actually overridden by our method. If this causes a problem, traverse to the + // root of the inheritance hierarchy and check if the original method is virtual or + // not. + if (!cextp->classp()->user1SetOnce()) cextp->classp()->repairCache(); + if (auto* const overriddenp + = VN_CAST(cextp->classp()->findMember(nodep->name()), CFunc)) { + if (overriddenp->user2()) { // If it's suspendable + nodep->user2(true); // Then we are also suspendable + // As both are suspendable already, there is no need to add it as our + // dependency or self to its dependencies + } else { + // Make a dependency cycle, as being suspendable should propagate both up + // and down the inheritance tree + TimingDependencyVertex* const overriddenVxp = getDependencyVertex(overriddenp); + new V3GraphEdge{&m_depGraph, vxp, overriddenVxp, 1}; + new V3GraphEdge{&m_depGraph, overriddenVxp, vxp, 1}; + } + } + } + } + void visit(AstNodeCCall* nodep) override { + if (nodep->funcp()->user2()) { + m_procp->user2(true); + // Both the caller and the callee are suspendable, no need to make dependency edges + // between them + } else { + TimingDependencyVertex* const procVxp = getDependencyVertex(m_procp); + TimingDependencyVertex* const funcVxp = getDependencyVertex(nodep->funcp()); + new V3GraphEdge{&m_depGraph, procVxp, funcVxp, 1}; + iterateChildren(nodep); + } + } + void visit(AstBegin* nodep) override { + VL_RESTORER(m_procp); + m_procp = nodep; + iterateChildren(nodep); + } + void visit(AstNode* nodep) override { + if (nodep->isTimingControl()) { + v3Global.setUsesTiming(); + if (m_procp) m_procp->user2(true); + } + iterateChildren(nodep); + } + + //-------------------- + void visit(AstVar*) override {} // Accelerate + +public: + // CONSTRUCTORS + explicit TimingSuspendableVisitor(AstNetlist* nodep) { + iterate(nodep); + m_depGraph.removeTransitiveEdges(); + for (V3GraphVertex* vxp = m_depGraph.verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { + TimingDependencyVertex* const depVxp = static_cast(vxp); + if (depVxp->nodep()->user2()) propagateSuspendable(depVxp); + } + if (dumpGraphLevel() >= 6) m_depGraph.dumpDotFilePrefixed("timing_deps"); + } + ~TimingSuspendableVisitor() override = default; +}; + +// ###################################################################### +// Transform nodes affected by timing + +class TimingControlVisitor final : public VNVisitor { +private: + // NODE STATE + // Ast{Always,NodeCCall,Fork,NodeAssign}::user1() -> bool. Set true if the node has + // been processed. + // AstSenTree::user1() -> AstVarScope*. Trigger scheduler assigned + // to this sentree + // Ast{NodeProcedure,CFunc,Begin}::user2() -> bool. Set true if process/task + // is suspendable + // AstSenTree::user2() -> AstCExpr*. Debug info passed to the + // timing schedulers + // const VNUser1InUse m_user1InUse; (Allocated for use in SuspendableVisitor) + // const VNUser2InUse m_user2InUse; (Allocated for use in SuspendableVisitor) + // STATE // Current context AstNetlist* const m_netlistp; // Root node @@ -105,7 +233,6 @@ private: AstClass* m_classp = nullptr; // Current class AstScope* m_scopep = nullptr; // Current scope AstActive* m_activep = nullptr; // Current active - AstNode* m_procp = nullptr; // NodeProcedure/CFunc/Fork we're under double m_timescaleFactor = 1.0; // Factor to scale delays by // Unique names @@ -128,16 +255,9 @@ private: AstSenTree* m_dynamicSensesp = nullptr; // Domain to trigger if a dynamic trigger is set // Other - V3Graph m_depGraph; // Dependency graph where a node is a dependency of another if it being - // suspendable makes the other node suspendable SenTreeFinder m_finder{m_netlistp}; // Sentree finder and uniquifier // METHODS - // Get or create the dependency vertex for the given node - DependencyVertex* getDependencyVertex(AstNode* const nodep) { - if (!nodep->user3p()) nodep->user3p(new DependencyVertex{&m_depGraph, nodep}); - return nodep->user3u().to(); - } // Find net delay on the LHS of an assignment AstDelay* getLhsNetDelay(AstNodeAssign* nodep) const { bool foundWrite = false; @@ -359,7 +479,7 @@ private: // Create a fork sync var FileLine* const flp = forkp->fileline(); // If we're in a function, insert the sync var directly before the fork - AstNode* const insertBeforep = VN_IS(m_procp, CFunc) ? forkp : nullptr; + AstNode* const insertBeforep = m_classp ? forkp : nullptr; AstVarScope* forkVscp = createTemp(flp, forkp->name() + "__sync", getCreateForkSyncDTypep(), insertBeforep); unsigned joinCount = 0; // Needed for join counter @@ -404,105 +524,54 @@ private: m_activep = nullptr; } void visit(AstNodeProcedure* nodep) override { - VL_RESTORER(m_procp); - m_procp = nodep; iterateChildren(nodep); if (nodep->user2()) nodep->setSuspendable(); } void visit(AstAlways* nodep) override { - visit(static_cast(nodep)); - if (nodep->isSuspendable() && !nodep->user1SetOnce()) { - FileLine* const flp = nodep->fileline(); - AstSenTree* const sensesp = m_activep->sensesp(); - if (sensesp->hasClocked()) { - AstNode* bodysp = nodep->stmtsp()->unlinkFrBackWithNext(); - auto* const controlp = new AstEventControl{flp, sensesp->cloneTree(false), bodysp}; - nodep->addStmtsp(controlp); - iterate(controlp); - } - // Note: The 'while (true)' outer loop will be added in V3Sched - auto* const activep = new AstActive{ - flp, "", new AstSenTree{flp, new AstSenItem{flp, AstSenItem::Initial{}}}}; - activep->sensesStorep(activep->sensesp()); - activep->addStmtsp(nodep->unlinkFrBack()); - m_activep->addNextHere(activep); + if (nodep->user1SetOnce()) return; + iterateChildren(nodep); + if (!nodep->user2()) return; + nodep->setSuspendable(); + FileLine* const flp = nodep->fileline(); + AstSenTree* const sensesp = m_activep->sensesp(); + if (sensesp->hasClocked()) { + AstNode* const bodysp = nodep->stmtsp()->unlinkFrBackWithNext(); + auto* const controlp = new AstEventControl{flp, sensesp->cloneTree(false), bodysp}; + nodep->addStmtsp(controlp); + iterate(controlp); } + // Note: The 'while (true)' outer loop will be added in V3Sched + auto* const activep = new AstActive{ + flp, "", new AstSenTree{flp, new AstSenItem{flp, AstSenItem::Initial{}}}}; + activep->sensesStorep(activep->sensesp()); + activep->addStmtsp(nodep->unlinkFrBack()); + m_activep->addNextHere(activep); } void visit(AstCFunc* nodep) override { - VL_RESTORER(m_procp); - m_procp = nodep; iterateChildren(nodep); - DependencyVertex* const vxp = getDependencyVertex(nodep); - if (m_classp && !nodep->user1SetOnce()) { // If class method (possibly overrides another - // method); only visit once - // Go over overridden functions - m_classp->repairCache(); - for (auto* cextp = m_classp->extendsp(); cextp; - cextp = VN_AS(cextp->nextp(), ClassExtends)) { - if (!cextp->classp()->user1SetOnce()) { - // Repair class cache if it's not repaired already - cextp->classp()->repairCache(); - } - if (auto* const overriddenp - = VN_CAST(cextp->classp()->findMember(nodep->name()), CFunc)) { - if (overriddenp->user2()) { // If suspendable - if (!nodep->user2()) { - // It should be a coroutine but it has no awaits. Add a co_return at - // the end (either that or a co_await is required in a coroutine) - nodep->addStmtsp(new AstCStmt{nodep->fileline(), "co_return;\n"}); - } - nodep->user2(true); - // If it's suspendable already, no need to add it as our dependency or - // self to its dependencies - } else { - DependencyVertex* const overriddenVxp = getDependencyVertex(overriddenp); - new V3GraphEdge{&m_depGraph, vxp, overriddenVxp, 1}; - new V3GraphEdge{&m_depGraph, overriddenVxp, vxp, 1}; - } - } - } - } - if (nodep->user2() && !nodep->isCoroutine()) { // If first marked as suspendable + if (nodep->user2()) { nodep->rtnType("VlCoroutine"); // If in a class, create a shared pointer to 'this' if (m_classp) nodep->addInitsp(new AstCStmt{nodep->fileline(), "VL_KEEP_THIS;\n"}); - // Revisit dependent nodes if needed - for (V3GraphEdge* edgep = vxp->inBeginp(); edgep; edgep = edgep->inNextp()) { - auto* const depVxp = static_cast(edgep->fromp()); - AstNode* const depp = depVxp->nodep(); - if (!depp->user2()) { // If dependent not suspendable - depp->user2(true); - if (auto* const funcp = VN_CAST(depp, CFunc)) { - // It's a coroutine but has no awaits (a class method that overrides/is - // overridden by a suspendable, but doesn't have any awaits itself). Add a - // co_return at the end (either that or a co_await is required in a - // coroutine) - funcp->addStmtsp(new AstCStmt{funcp->fileline(), "co_return;\n"}); - } - } - iterate(depp); + if (!nodep->exists([](AstCAwait*) { return true; })) { + // It's a coroutine but has no awaits (a class method that overrides/is + // overridden by a suspendable, but doesn't have any awaits itself). Add a + // co_return at the end (either that or a co_await is required in a + // coroutine) + nodep->addStmtsp(new AstCStmt{nodep->fileline(), "co_return;\n"}); } } } void visit(AstNodeCCall* nodep) override { - if (nodep->funcp()->user2()) { // If suspendable + if (nodep->funcp()->user2() && !nodep->user1SetOnce()) { // If suspendable VNRelinker relinker; nodep->unlinkFrBack(&relinker); AstCAwait* const awaitp = new AstCAwait{nodep->fileline(), nodep}; awaitp->dtypeSetVoid(); relinker.relink(awaitp); - } else { - // Add our process/func as the CFunc's dependency as we might have to put an await here - DependencyVertex* const procVxp = getDependencyVertex(m_procp); - DependencyVertex* const funcVxp = getDependencyVertex(nodep->funcp()); - new V3GraphEdge{&m_depGraph, procVxp, funcVxp, 1}; } iterateChildren(nodep); } - void visit(AstCAwait* nodep) override { - v3Global.setUsesTiming(); - m_procp->user2(true); - } void visit(AstDelay* nodep) override { UASSERT_OBJ(!nodep->isCycleDelay(), nodep, "Cycle delays should have been handled in V3AssertPre"); @@ -648,7 +717,7 @@ private: } // Insert new vars before the timing control if we're in a function; in a process we can't // do that. These intra-assignment vars will later be passed to forked processes by value. - AstNode* const insertBeforep = VN_IS(m_procp, CFunc) ? controlp : nullptr; + AstNode* const insertBeforep = m_classp ? controlp : nullptr; // Function for replacing values with intermediate variables const auto replaceWithIntermediate = [&](AstNodeExpr* const valuep, const std::string& name) { @@ -775,8 +844,6 @@ private: } auto* const beginp = VN_AS(stmtp, Begin); stmtp = beginp->nextp(); - VL_RESTORER(m_procp); - m_procp = beginp; iterate(beginp); // Even if we do not find any awaits, we cannot simply inline the process here, as new // awaits could be added later. @@ -787,18 +854,16 @@ private: } //-------------------- - void visit(AstNodeExpr*) override {} // Accelerate - void visit(AstVar*) override {} + void visit(AstVar*) override {} // Accelerate void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS - explicit TimingVisitor(AstNetlist* nodep) + explicit TimingControlVisitor(AstNetlist* nodep) : m_netlistp{nodep} { iterate(nodep); - if (dumpGraphLevel() >= 6) m_depGraph.dumpDotFilePrefixed("timing_deps"); } - ~TimingVisitor() override = default; + ~TimingControlVisitor() override = default; }; //###################################################################### @@ -806,6 +871,7 @@ public: void V3Timing::timingAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); - TimingVisitor{nodep}; + TimingSuspendableVisitor susVisitor{nodep}; + if (v3Global.usesTiming()) TimingControlVisitor{nodep}; V3Global::dumpCheckGlobalTree("timing", 0, dumpTreeLevel() >= 3); } diff --git a/test_regress/t/t_semaphore_always.pl b/test_regress/t/t_semaphore_always.pl new file mode 100755 index 000000000..1db13024b --- /dev/null +++ b/test_regress/t/t_semaphore_always.pl @@ -0,0 +1,27 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 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); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--timing"], + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_semaphore_always.v b/test_regress/t/t_semaphore_always.v new file mode 100644 index 000000000..ddfc9b568 --- /dev/null +++ b/test_regress/t/t_semaphore_always.v @@ -0,0 +1,23 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + semaphore s = new; + + initial begin + s.put(); + end + + always @(posedge clk) begin + s.get(); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From 9da3aacd08f7e6e63c31cf0c99d35a7f94430683 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Fri, 19 May 2023 02:01:36 +0200 Subject: [PATCH 052/129] Fix bit selections under parameterized classes (#4210) --- src/V3LinkDot.cpp | 7 ++++ test_regress/t/t_class_extends_param.v | 45 ++++++++++++++++++-------- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 72c3f762c..d6a5121f2 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2779,6 +2779,8 @@ private: // may be true only in the first stage of linking. // Mark that the Dot statement can't be resolved. m_ds.m_unresolvedClass = true; + // If the symbol was a scope name, it would be resolved. + if (m_ds.m_dotPos == DP_SCOPE) m_ds.m_dotPos = DP_MEMBER; } else { // Cells/interfaces can't be implicit const bool isCell = foundp ? VN_IS(foundp->nodep(), Cell) : false; @@ -3173,6 +3175,11 @@ private: void visit(AstSelBit* nodep) override { if (nodep->user3SetOnce()) return; iterateAndNextNull(nodep->fromp()); + if (m_ds.m_unresolvedClass) { + UASSERT_OBJ(m_ds.m_dotPos != DP_SCOPE, nodep, + "Object of unresolved class on scope position in dotted reference"); + return; + } if (m_ds.m_dotPos == DP_SCOPE) { // Already under dot, so this is {modulepart} DOT {modulepart} UINFO(9, " deferring until after a V3Param pass: " << nodep << endl); diff --git a/test_regress/t/t_class_extends_param.v b/test_regress/t/t_class_extends_param.v index aaaedce8a..f84fe1fa2 100644 --- a/test_regress/t/t_class_extends_param.v +++ b/test_regress/t/t_class_extends_param.v @@ -63,12 +63,23 @@ module t (/*AUTOARG*/ endfunction endclass + class FooDict; + Foo q[int]; + endclass + + class ExtendFooDict#(type BASE=FooDict) extends BASE; + function int get_x_of_item(int i); + return q[i].x; + endfunction + endclass + Bar #() bar_foo_i; Bar #(Baz) bar_baz_i; ExtendBar extend_bar_i; ExtendBar1 extend_bar1_i; ExtendBarBaz extend_bar_baz_i; ExtendExtendBar extend_extend_bar_i; + ExtendFooDict extend_foo_dict_i; initial begin bar_foo_i = new; @@ -77,18 +88,26 @@ module t (/*AUTOARG*/ extend_bar1_i = new; extend_bar_baz_i = new; extend_extend_bar_i = new; - if (bar_foo_i.get_x() == 1 && bar_foo_i.get_3() == 3 && - bar_baz_i.get_x() == 2 && bar_baz_i.get_4() == 4 && - extend_bar_i.get_x() == 1 && extend_bar_i.get_6() == 6 && - extend_bar_i.get_x() == 1 && extend_bar_i.get_6() == 6 && - extend_bar1_i.get_x() == 1 && extend_bar1_i.get_6() == 6 && - extend_bar_baz_i.get_x() == 2 && extend_bar_baz_i.get_8() == 8 && - extend_extend_bar_i.get_x() == 1 && extend_extend_bar_i.get_12() == 12) begin - $write("*-* All Finished *-*\n"); - $finish; - end - else begin - $stop; - end + extend_foo_dict_i = new; + extend_foo_dict_i.q[1] = new; + + if (bar_foo_i.get_x() != 1) $stop; + if (bar_foo_i.get_3() != 3) $stop; + if (bar_baz_i.get_x() != 2) $stop; + if (bar_baz_i.get_4() != 4) $stop; + if (extend_bar_i.get_x() != 1) $stop; + if (extend_bar_i.get_6() != 6) $stop; + if (extend_bar_i.get_x() != 1) $stop; + if (extend_bar_i.get_6() != 6) $stop; + if (extend_bar1_i.get_x() != 1) $stop; + if (extend_bar1_i.get_6() != 6) $stop; + if (extend_bar_baz_i.get_x() != 2) $stop; + if (extend_bar_baz_i.get_8() != 8) $stop; + if (extend_extend_bar_i.get_x() != 1) $stop; + if (extend_extend_bar_i.get_12() != 12) $stop; + if (extend_foo_dict_i.get_x_of_item(1) != 1) $stop; + + $write("*-* All Finished *-*\n"); + $finish; end endmodule From 4818130e4fd55c363ceea8f4cd9f552039be96fd Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 20 May 2023 22:37:28 -0400 Subject: [PATCH 053/129] Internals: Remove dead code, addBeforeStmt --- src/V3Ast.h | 2 -- src/V3AstNodeOther.h | 4 ---- src/V3AstNodes.cpp | 27 --------------------------- src/V3LinkInc.cpp | 1 - src/V3Task.cpp | 1 - 5 files changed, 35 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index 6a286bde8..8dc154695 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1915,8 +1915,6 @@ public: // Iterate and insert - assumes tree format virtual void addNextStmt(AstNode* newp, AstNode* belowp); // When calling, "this" is second argument - virtual void addBeforeStmt(AstNode* newp, - AstNode* belowp); // When calling, "this" is second argument // METHODS - Iterate on a tree // Clone or return nullptr if nullptr diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 960f10d09..1070c83f9 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -308,8 +308,6 @@ public: // METHODS void addNextStmt(AstNode* newp, AstNode* belowp) override; // Stop statement searchback here - void addBeforeStmt(AstNode* newp, - AstNode* belowp) override; // Stop statement searchback here void dump(std::ostream& str = std::cout) const override; }; class AstNodeAssign VL_NOT_FINAL : public AstNodeStmt { @@ -3246,8 +3244,6 @@ public: int instrCount() const override { return INSTR_COUNT_BRANCH; } bool same(const AstNode* /*samep*/) const override { return true; } // Stop statement searchback here - void addBeforeStmt(AstNode* newp, AstNode* belowp) override; - // Stop statement searchback here void addNextStmt(AstNode* newp, AstNode* belowp) override; bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); } }; diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 0f3fa80a4..eccb2d504 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1271,44 +1271,17 @@ AstVarScope* AstConstPool::findConst(AstConst* initp, bool mergeDType) { //====================================================================== // Special walking tree inserters -void AstNode::addBeforeStmt(AstNode* newp, AstNode*) { - UASSERT_OBJ(backp(), newp, "Can't find current statement to addBeforeStmt"); - // Look up; virtual call will find where to put it - this->backp()->addBeforeStmt(newp, this); -} void AstNode::addNextStmt(AstNode* newp, AstNode*) { UASSERT_OBJ(backp(), newp, "Can't find current statement to addNextStmt"); // Look up; virtual call will find where to put it this->backp()->addNextStmt(newp, this); } -void AstNodeStmt::addBeforeStmt(AstNode* newp, AstNode*) { - // Insert newp before current node - this->addHereThisAsNext(newp); -} void AstNodeStmt::addNextStmt(AstNode* newp, AstNode*) { // Insert newp after current node this->addNextHere(newp); } -void AstWhile::addBeforeStmt(AstNode* newp, AstNode* belowp) { - // Special, as statements need to be put in different places - // Belowp is how we came to recurse up to this point - // Preconditions insert first just before themselves (the normal rule - // for other statement types) - if (belowp == precondsp()) { - // Must have been first statement in precondsp list, so newp is new first statement - belowp->addHereThisAsNext(newp); - } else if (belowp == condp()) { - // Goes before condition, IE in preconditions - addPrecondsp(newp); - } else if (belowp == stmtsp()) { - // Was first statement in body, so new front - belowp->addHereThisAsNext(newp); - } else { - belowp->v3fatalSrc("Doesn't look like this was really under the while"); - } -} void AstWhile::addNextStmt(AstNode* newp, AstNode* belowp) { // Special, as statements need to be put in different places // Belowp is how we came to recurse up to this point diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp index 8c71d6bb2..904fd423f 100644 --- a/src/V3LinkInc.cpp +++ b/src/V3LinkInc.cpp @@ -69,7 +69,6 @@ private: // METHODS void insertBeforeStmt(AstNode* nodep, AstNode* newp) { // Return node that must be visited, if any - // See also AstNode::addBeforeStmt; this predates that function if (debug() >= 9) newp->dumpTree("- newstmt: "); UASSERT_OBJ(m_insStmtp, nodep, "Function not underneath a statement"); if (m_insMode == IM_BEFORE) { diff --git a/src/V3Task.cpp b/src/V3Task.cpp index e7ef1e0f7..9bc068a19 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -1335,7 +1335,6 @@ private: } AstNode* insertBeforeStmt(AstNode* nodep, AstNode* newp) { // Return node that must be visited, if any - // See also AstNode::addBeforeStmt; this predates that function if (debug() >= 9) nodep->dumpTree("- newstmt: "); UASSERT_OBJ(m_insStmtp, nodep, "Function not underneath a statement"); AstNode* visitp = nullptr; From 6b393e9d7cb036563a7f0d332443941ee14ca5ff Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 21 May 2023 12:03:13 -0400 Subject: [PATCH 054/129] Internals: Allow statement-in-statement recursion in V3Premit --- src/V3EmitCFunc.h | 2 +- src/V3Premit.cpp | 38 ++++++++++++++++++++++++++------------ 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 540b1ea13..c95e8ed46 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -467,7 +467,7 @@ public: void visit(AstLambdaArgRef* nodep) override { putbs(nodep->nameProtect()); } void visit(AstWith* nodep) override { // With uses a C++11 lambda - putbs("[=]("); + putbs("[&]("); if (auto* const argrefp = nodep->indexArgRefp()) { putbs(argrefp->dtypep()->cType(argrefp->nameProtect(), false, false)); puts(","); diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 233b7bf1d..d05ca7b78 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -157,30 +157,39 @@ private: } void visit(AstCFunc* nodep) override { VL_RESTORER(m_cfuncp); - { - m_cfuncp = nodep; - m_tempNames.reset(); - iterateChildren(nodep); - } + m_cfuncp = nodep; + m_tempNames.reset(); + iterateChildren(nodep); } + +#define RESTORER_START_STATEMENT() \ + VL_RESTORER(m_assignLhs); \ + VL_RESTORER(m_stmtp); + + // Must use RESTORER_START_STATEMENT() in visitors using this void startStatement(AstNode* nodep) { m_assignLhs = false; if (m_cfuncp) m_stmtp = nodep; } + void visit(AstWhile* nodep) override { UINFO(4, " WHILE " << nodep << endl); + RESTORER_START_STATEMENT(); startStatement(nodep); iterateAndNextNull(nodep->precondsp()); startStatement(nodep); - m_inWhilep = nodep; - iterateAndNextNull(nodep->condp()); - m_inWhilep = nullptr; + { + VL_RESTORER(m_inWhilep); + m_inWhilep = nodep; + iterateAndNextNull(nodep->condp()); + } startStatement(nodep); iterateAndNextNull(nodep->stmtsp()); iterateAndNextNull(nodep->incsp()); m_stmtp = nullptr; } void visit(AstNodeAssign* nodep) override { + RESTORER_START_STATEMENT(); startStatement(nodep); { bool noopt = false; @@ -202,22 +211,26 @@ private: } } iterateAndNextNull(nodep->rhsp()); - m_assignLhs = true; - iterateAndNextNull(nodep->lhsp()); - m_assignLhs = false; + { + VL_RESTORER(m_assignLhs); + m_assignLhs = true; + iterateAndNextNull(nodep->lhsp()); + } m_stmtp = nullptr; } void visit(AstNodeStmt* nodep) override { UINFO(4, " STMT " << nodep << endl); + RESTORER_START_STATEMENT(); startStatement(nodep); iterateChildren(nodep); m_stmtp = nullptr; } void visit(AstTraceInc* nodep) override { + RESTORER_START_STATEMENT(); startStatement(nodep); + VL_RESTORER(m_inTracep); m_inTracep = nodep; iterateChildren(nodep); - m_inTracep = nullptr; m_stmtp = nullptr; } void visitShift(AstNodeBiop* nodep) { @@ -345,6 +358,7 @@ private: // Autoflush void visit(AstDisplay* nodep) override { + RESTORER_START_STATEMENT(); startStatement(nodep); iterateChildren(nodep); m_stmtp = nullptr; From 65667356b62241cd88024187661a191ac048ba07 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 21 May 2023 12:24:00 -0400 Subject: [PATCH 055/129] wip --- src/V3Simulate.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/V3Simulate.h b/src/V3Simulate.h index 05fac3e7a..1feb44580 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -880,6 +880,14 @@ private: checkNodeInfo(nodep); iterateChildrenConst(nodep); } + void visit(AstExprStmt* nodep) override { + if (jumpingOver(nodep)) return; + checkNodeInfo(nodep); + iterateAndNextConstNull(nodep->stmtsp()); + if (!optimizable()) return; + iterateAndNextConstNull(nodep->resultp()); + newValue(nodep, fetchValue(nodep->resultp())); + } void visit(AstJumpBlock* nodep) override { if (jumpingOver(nodep)) return; From 950e29d56eabda84b20f8a78d99fa24a83d77f55 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 21 May 2023 12:49:07 -0400 Subject: [PATCH 056/129] Internals: Cleanup some missing VL_RESTORER in V3Gate. No functional change intended. --- src/V3Gate.cpp | 57 +++++++++++++++++++--------------------------- src/V3Localize.cpp | 12 ++++------ 2 files changed, 29 insertions(+), 40 deletions(-) diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 2c6497cb9..09cc696d8 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -53,7 +53,7 @@ class GateLogicVertex; class GateVarVertex; class GateGraphBaseVisitor VL_NOT_FINAL { public: - V3Graph* m_graphp; // Graph this class is visiting + V3Graph* const m_graphp; // Graph this class is visiting explicit GateGraphBaseVisitor(V3Graph* graphp) : m_graphp{graphp} {} virtual ~GateGraphBaseVisitor() = default; @@ -199,10 +199,11 @@ private: GateVarRefList m_rhsVarRefs; // VarRefs on rhs of assignment AstNode* m_substTreep = nullptr; // What to replace the variable with // STATE - bool m_buffersOnly; // Set when we only allow simple buffering, no equations (for clocks) + const bool + m_buffersOnly; // Set when we only allow simple buffering, no equations (for clocks) const AstNodeVarRef* m_lhsVarRef = nullptr; // VarRef on lhs of assignment (what we're replacing) - bool m_dedupe; // Set when we use isGateDedupable instead of isGateOptimizable + const bool m_dedupe; // Set when we use isGateDedupable instead of isGateOptimizable int m_ops = 0; // Operation count // METHODS @@ -277,9 +278,9 @@ private: public: // CONSTRUCTORS - GateOkVisitor(AstNode* nodep, bool buffersOnly, bool dedupe) { - m_buffersOnly = buffersOnly; - m_dedupe = dedupe; + GateOkVisitor(AstNode* nodep, bool buffersOnly, bool dedupe) + : m_buffersOnly{buffersOnly} + , m_dedupe{dedupe} { // Iterate iterateConst(nodep); // Check results @@ -452,29 +453,28 @@ private: } void visit(AstNodeModule* nodep) override { VL_RESTORER(m_modp); - { - m_modp = nodep; - m_activeReducible = true; - iterateChildren(nodep); - } + VL_RESTORER(m_activeReducible); + m_modp = nodep; + m_activeReducible = true; + iterateChildren(nodep); } void visit(AstScope* nodep) override { UINFO(4, " SCOPE " << nodep << endl); + VL_RESTORER(m_scopep); m_scopep = nodep; m_logicVertexp = nullptr; iterateChildren(nodep); - m_scopep = nullptr; } void visit(AstActive* nodep) override { // Create required blocks and add to module UINFO(4, " BLOCK " << nodep << endl); + VL_RESTORER(m_activep); + VL_RESTORER(m_activeReducible); m_activeReducible = !(nodep->hasClocked()); // Seq logic outputs aren't reducible m_activep = nodep; AstNode::user2ClearTree(); iterateChildren(nodep); AstNode::user2ClearTree(); - m_activep = nullptr; - m_activeReducible = true; } void visit(AstNodeVarRef* nodep) override { if (m_scopep) { @@ -506,31 +506,26 @@ private: } void visit(AstAlwaysPublic* nodep) override { VL_RESTORER(m_inSlow); - { - m_inSlow = true; - iterateNewStmt(nodep, "AlwaysPublic", nullptr); - } + m_inSlow = true; + iterateNewStmt(nodep, "AlwaysPublic", nullptr); } void visit(AstCFunc* nodep) override { iterateNewStmt(nodep, "User C Function", "User C Function"); } void visit(AstClocking* nodep) override { iterateNewStmt(nodep, nullptr, nullptr); } void visit(AstSenItem* nodep) override { + VL_RESTORER(m_inSenItem); m_inSenItem = true; if (m_logicVertexp) { // Already under logic; presumably a SenGate iterateChildren(nodep); } else { // Standalone item, probably right under a SenTree iterateNewStmt(nodep, nullptr, nullptr); } - m_inSenItem = false; } void visit(AstNodeProcedure* nodep) override { VL_RESTORER(m_inSlow); - { - m_inSlow = VN_IS(nodep, Initial) || VN_IS(nodep, Final); - iterateNewStmt(nodep, (nodep->isJustOneBodyStmt() ? nullptr : "Multiple Stmts"), - nullptr); - } + m_inSlow = VN_IS(nodep, Initial) || VN_IS(nodep, Final); + iterateNewStmt(nodep, (nodep->isJustOneBodyStmt() ? nullptr : "Multiple Stmts"), nullptr); } void visit(AstAssignAlias* nodep) override { // iterateNewStmt(nodep, nullptr, nullptr); @@ -543,10 +538,8 @@ private: } void visit(AstTraceDecl* nodep) override { VL_RESTORER(m_inSlow); - { - m_inSlow = true; - iterateNewStmt(nodep, "Tracing", "Tracing"); - } + m_inSlow = true; + iterateNewStmt(nodep, "Tracing", "Tracing"); } void visit(AstConcat* nodep) override { UASSERT_OBJ(!(VN_IS(nodep->backp(), NodeAssign) @@ -1269,9 +1262,7 @@ private: public: explicit GateMergeAssignsGraphVisitor(V3Graph* graphp) - : GateGraphBaseVisitor{graphp} { - m_graphp = graphp; // In base - } + : GateGraphBaseVisitor{graphp} {} void mergeAssignsTree(GateVarVertex* vvertexp) { vvertexp->accept(*this); } VDouble0 numMergedAssigns() { return m_numMergedAssigns; } }; @@ -1370,8 +1361,8 @@ private: if (vsp->user2SetOnce()) return VNUser{0}; UINFO(9, "CLK DECOMP Var - " << vvertexp << " : " << vsp << endl); if (vsp->varp()->width() > 1) { - m_seen_clk_vectors++; - m_total_seen_clk_vectors++; + ++m_seen_clk_vectors; + ++m_total_seen_clk_vectors; } const GateClkDecompState* const currState = reinterpret_cast(vu.c()); GateClkDecompState nextState{currState->m_offset, vsp}; diff --git a/src/V3Localize.cpp b/src/V3Localize.cpp index a6f30963c..cadc11a91 100644 --- a/src/V3Localize.cpp +++ b/src/V3Localize.cpp @@ -133,12 +133,10 @@ private: UINFO(4, " CFUNC " << nodep << endl); VL_RESTORER(m_cfuncp); VL_RESTORER(m_nodeDepth); - { - m_cfuncp = nodep; - m_nodeDepth = 0; - const VNUser2InUse user2InUse; - iterateChildrenConst(nodep); - } + m_cfuncp = nodep; + m_nodeDepth = 0; + const VNUser2InUse user2InUse; + iterateChildrenConst(nodep); } void visit(AstCCall* nodep) override { @@ -204,9 +202,9 @@ private: } void visit(AstNode* nodep) override { + VL_RESTORER(m_nodeDepth); ++m_nodeDepth; iterateChildrenConst(nodep); - --m_nodeDepth; } public: From 140994d2c49dae1f76a55775044b88215654772c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 21 May 2023 14:06:39 -0400 Subject: [PATCH 057/129] Internals: Cleanup more VL_RESTORER. No functional change intended. --- src/V3Delayed.cpp | 30 +++++++++++++++--------------- src/V3Localize.cpp | 6 ++++-- src/V3Premit.cpp | 10 +++------- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index 2fec08043..c65ad784e 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -92,21 +92,23 @@ private: const VNUser4InUse m_inuser4; const VNUser5InUse m_inuser5; - // STATE + // STATE - for current visit position (use VL_RESTORER) AstActive* m_activep = nullptr; // Current activate const AstCFunc* m_cfuncp = nullptr; // Current public C Function AstAssignDly* m_nextDlyp = nullptr; // Next delayed assignment in a list of assignments AstNodeProcedure* m_procp = nullptr; // Current process - std::set m_timingDomains; // Timing resume domains bool m_inDly = false; // True in delayed assignments bool m_inLoop = false; // True in for loops bool m_inInitial = false; // True in static initializers and initial blocks bool m_inSuspendableOrFork = false; // True in suspendable processes and forks bool m_ignoreBlkAndNBlk = false; // Suppress delayed assignment BLKANDNBLK + + // STATE - across all visitors + std::unordered_map m_scopeVecMap; // Next var number for each scope + std::set m_timingDomains; // Timing resume domains using VarMap = std::map, AstVar*>; VarMap m_modVarMap; // Table of new var names created under module VDouble0 m_statSharedSet; // Statistic tracking - std::unordered_map m_scopeVecMap; // Next var number for each scope // METHODS @@ -424,10 +426,8 @@ private: } void visit(AstCFunc* nodep) override { VL_RESTORER(m_cfuncp); - { - m_cfuncp = nodep; - iterateChildren(nodep); - } + m_cfuncp = nodep; + iterateChildren(nodep); } void visit(AstActive* nodep) override { m_activep = nodep; @@ -443,10 +443,12 @@ private: void visit(AstNodeProcedure* nodep) override { VL_RESTORER(m_inSuspendableOrFork); m_inSuspendableOrFork = nodep->isSuspendable(); - m_procp = nodep; - m_timingDomains.clear(); - iterateChildren(nodep); - m_procp = nullptr; + { + VL_RESTORER(m_procp); + m_procp = nodep; + m_timingDomains.clear(); + iterateChildren(nodep); + } if (m_timingDomains.empty()) return; if (auto* const actp = VN_AS(nodep->user3p(), Active)) { // Merge all timing domains (and possibly the active's domain) to create a sentree for @@ -618,10 +620,8 @@ private: } void visit(AstWhile* nodep) override { VL_RESTORER(m_inLoop); - { - m_inLoop = true; - iterateChildren(nodep); - } + m_inLoop = true; + iterateChildren(nodep); } //-------------------- diff --git a/src/V3Localize.cpp b/src/V3Localize.cpp index cadc11a91..a47d9d173 100644 --- a/src/V3Localize.cpp +++ b/src/V3Localize.cpp @@ -57,11 +57,13 @@ private: AstUser4Allocator> m_references; - // STATE - VDouble0 m_statLocVars; // Statistic tracking + // STATE - for current visit position (use VL_RESTORER) AstCFunc* m_cfuncp = nullptr; // Current active function uint32_t m_nodeDepth = 0; // Node depth under m_cfuncp + + // STATE - across all visitors std::vector m_varScopeps; // List of variables to consider for localization + VDouble0 m_statLocVars; // Statistic tracking // METHODS bool isOptimizable(AstVarScope* nodep) { diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index d05ca7b78..0e1dbdd4b 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -53,15 +53,16 @@ private: const VNUser1InUse m_inuser1; const VNUser2InUse m_inuser2; - // STATE + // STATE - for current visit position (use VL_RESTORER) AstCFunc* m_cfuncp = nullptr; // Current block AstNode* m_stmtp = nullptr; // Current statement AstCCall* m_callp = nullptr; // Current AstCCall AstWhile* m_inWhilep = nullptr; // Inside while loop, special statement additions AstTraceInc* m_inTracep = nullptr; // Inside while loop, special statement additions bool m_assignLhs = false; // Inside assignment lhs, don't breakup extracts - V3UniqueNames m_tempNames; // For generating unique temporary variable names + // STATE - across all visitors + V3UniqueNames m_tempNames; // For generating unique temporary variable names VDouble0 m_extractedToConstPool; // Statistic tracking // METHODS @@ -186,7 +187,6 @@ private: startStatement(nodep); iterateAndNextNull(nodep->stmtsp()); iterateAndNextNull(nodep->incsp()); - m_stmtp = nullptr; } void visit(AstNodeAssign* nodep) override { RESTORER_START_STATEMENT(); @@ -216,14 +216,12 @@ private: m_assignLhs = true; iterateAndNextNull(nodep->lhsp()); } - m_stmtp = nullptr; } void visit(AstNodeStmt* nodep) override { UINFO(4, " STMT " << nodep << endl); RESTORER_START_STATEMENT(); startStatement(nodep); iterateChildren(nodep); - m_stmtp = nullptr; } void visit(AstTraceInc* nodep) override { RESTORER_START_STATEMENT(); @@ -231,7 +229,6 @@ private: VL_RESTORER(m_inTracep); m_inTracep = nodep; iterateChildren(nodep); - m_stmtp = nullptr; } void visitShift(AstNodeBiop* nodep) { // Shifts of > 32/64 bits in C++ will wrap-around and generate non-0s @@ -361,7 +358,6 @@ private: RESTORER_START_STATEMENT(); startStatement(nodep); iterateChildren(nodep); - m_stmtp = nullptr; if (v3Global.opt.autoflush()) { const AstNode* searchp = nodep->nextp(); while (searchp && VN_IS(searchp, Comment)) searchp = searchp->nextp(); From 8e0682f442a5d61f8179fd0835ef0d4be304a0a2 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 21 May 2023 21:02:39 -0400 Subject: [PATCH 058/129] Fix V3Expand ignoring side effects --- src/V3Expand.cpp | 101 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 77 insertions(+), 24 deletions(-) diff --git a/src/V3Expand.cpp b/src/V3Expand.cpp index 5f3cf6fb7..812ac86fd 100644 --- a/src/V3Expand.cpp +++ b/src/V3Expand.cpp @@ -39,6 +39,38 @@ VL_DEFINE_DEBUG_FUNCTIONS; +//###################################################################### +// Find nodes with side effects, to mark as non-expandable + +class ExpandOkVisitor final : public VNVisitor { +private: + // NODE STATE + // AstNode::user2() -> bool. Is pure (along with all children) + const VNUser2InUse m_inuser2; + + // STATE - for current visit position (use VL_RESTORER) + // Tracks similar to AstNode::isTreePureRecurse(), but avoid O(n^2) + // False = pure, as nodes that ExpandVisitor inserts preserve pureness + bool m_isImpure = true; // Currently pure + + void visit(AstNode* nodep) override { + bool selfImpure = !nodep->isPure(); + { + VL_RESTORER(m_isImpure); + m_isImpure = false; + iterateChildren(nodep); + selfImpure |= m_isImpure; + nodep->user2(selfImpure); + } + m_isImpure |= selfImpure; + } + +public: + // CONSTRUCTORS + explicit ExpandOkVisitor(AstNetlist* nodep) { iterate(nodep); } + ~ExpandOkVisitor() = default; +}; + //###################################################################### // Expand state, as a visitor of each AstNode @@ -48,15 +80,24 @@ private: // AstNode::user1() -> bool. Processed const VNUser1InUse m_inuser1; - // STATE + // STATE - for current visit position (use VL_RESTORER) AstNode* m_stmtp = nullptr; // Current statement + + // STATE - across all visitors VDouble0 m_statWides; // Statistic tracking VDouble0 m_statWideWords; // Statistic tracking VDouble0 m_statWideLimited; // Statistic tracking // METHODS + // Use state that ExpandOkVisitor calculated + bool isImpure(AstNode* nodep) { + const bool impure = nodep->user2(); + if (impure) UINFO(9, " impure " << nodep << endl); + return impure; + } - bool doExpand(AstNode* nodep) { + bool doExpandWide(AstNode* nodep) { + if (isImpure(nodep)) return false; ++m_statWides; if (nodep->widthWords() <= v3Global.opt.expandLimit()) { m_statWideWords += nodep->widthWords(); @@ -225,7 +266,7 @@ private: bool expandWide(AstNodeAssign* nodep, AstConst* rhsp) { UINFO(8, " Wordize ASSIGN(CONST) " << nodep << endl); - if (!doExpand(nodep)) return false; + if (!doExpandWide(nodep)) return false; // -> {for each_word{ ASSIGN(WORDSEL(wide,#),WORDSEL(CONST,#))}} if (rhsp->num().isFourState()) { rhsp->v3warn(E_UNSUPPORTED, // LCOV_EXCL_LINE // impossible? @@ -241,7 +282,7 @@ private: //-------- Uniops bool expandWide(AstNodeAssign* nodep, AstVarRef* rhsp) { UINFO(8, " Wordize ASSIGN(VARREF) " << nodep << endl); - if (!doExpand(nodep)) return false; + if (!doExpandWide(nodep)) return false; for (int w = 0; w < nodep->widthWords(); ++w) { addWordAssign(nodep, w, newAstWordSelClone(rhsp, w)); } @@ -251,7 +292,7 @@ private: UINFO(8, " Wordize ASSIGN(ARRAYSEL) " << nodep << endl); UASSERT_OBJ(!VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType), nodep, "ArraySel with unpacked arrays should have been removed in V3Slice"); - if (!doExpand(nodep)) return false; + if (!doExpandWide(nodep)) return false; for (int w = 0; w < nodep->widthWords(); ++w) { addWordAssign(nodep, w, newAstWordSelClone(rhsp, w)); } @@ -260,7 +301,7 @@ private: bool expandWide(AstNodeAssign* nodep, AstNot* rhsp) { UINFO(8, " Wordize ASSIGN(NOT) " << nodep << endl); // -> {for each_word{ ASSIGN(WORDSEL(wide,#),NOT(WORDSEL(lhs,#))) }} - if (!doExpand(nodep)) return false; + if (!doExpandWide(nodep)) return false; FileLine* const fl = rhsp->fileline(); for (int w = 0; w < nodep->widthWords(); ++w) { addWordAssign(nodep, w, new AstNot{fl, newAstWordSelClone(rhsp->lhsp(), w)}); @@ -270,7 +311,7 @@ private: //-------- Biops bool expandWide(AstNodeAssign* nodep, AstAnd* rhsp) { UINFO(8, " Wordize ASSIGN(AND) " << nodep << endl); - if (!doExpand(nodep)) return false; + if (!doExpandWide(nodep)) return false; FileLine* const fl = nodep->fileline(); for (int w = 0; w < nodep->widthWords(); ++w) { addWordAssign(nodep, w, @@ -281,7 +322,7 @@ private: } bool expandWide(AstNodeAssign* nodep, AstOr* rhsp) { UINFO(8, " Wordize ASSIGN(OR) " << nodep << endl); - if (!doExpand(nodep)) return false; + if (!doExpandWide(nodep)) return false; FileLine* const fl = nodep->fileline(); for (int w = 0; w < nodep->widthWords(); ++w) { addWordAssign(nodep, w, @@ -292,7 +333,7 @@ private: } bool expandWide(AstNodeAssign* nodep, AstXor* rhsp) { UINFO(8, " Wordize ASSIGN(XOR) " << nodep << endl); - if (!doExpand(nodep)) return false; + if (!doExpandWide(nodep)) return false; FileLine* const fl = nodep->fileline(); for (int w = 0; w < nodep->widthWords(); ++w) { addWordAssign(nodep, w, @@ -304,7 +345,7 @@ private: //-------- Triops bool expandWide(AstNodeAssign* nodep, AstNodeCond* rhsp) { UINFO(8, " Wordize ASSIGN(COND) " << nodep << endl); - if (!doExpand(nodep)) return false; + if (!doExpandWide(nodep)) return false; FileLine* const fl = nodep->fileline(); for (int w = 0; w < nodep->widthWords(); ++w) { addWordAssign(nodep, w, @@ -322,6 +363,7 @@ private: if (nodep->isWide()) { // See under ASSIGN(EXTEND) } else { + if (isImpure(nodep)) return; AstNodeExpr* const lhsp = nodep->lhsp()->unlinkFrBack(); AstNodeExpr* newp = lhsp; if (nodep->isQuad()) { @@ -343,7 +385,7 @@ private: } bool expandWide(AstNodeAssign* nodep, AstExtend* rhsp) { UINFO(8, " Wordize ASSIGN(EXTEND) " << nodep << endl); - if (!doExpand(nodep)) return false; + if (!doExpandWide(nodep)) return false; AstNodeExpr* const rlhsp = rhsp->lhsp(); for (int w = 0; w < rlhsp->widthWords(); ++w) { addWordAssign(nodep, w, newAstWordSelClone(rlhsp, w)); @@ -365,6 +407,7 @@ private: } else if (nodep->isWide()) { // See under ASSIGN(WIDE) } else if (nodep->fromp()->isWide()) { + if (isImpure(nodep)) return; UINFO(8, " SEL(wide) " << nodep << endl); UASSERT_OBJ(nodep->widthConst() <= 64, nodep, "Inconsistent width"); // Selection amounts @@ -386,7 +429,7 @@ private: const uint32_t midMsbOffset = std::min(nodep->widthConst(), VL_EDATASIZE) - 1; AstNodeExpr* const midMsbp = new AstAdd{lfl, new AstConst{lfl, midMsbOffset}, - nodep->lsbp()->cloneTree(false)}; + nodep->lsbp()->cloneTree(true)}; AstNodeExpr* midwordp = // SEL(from,[midwordnum]) newWordSel(ffl, nodep->fromp()->cloneTree(true), midMsbp, 0); // newWordSel clones the index, so delete it @@ -414,7 +457,7 @@ private: if (nodep->widthConst() > VL_EDATASIZE) { const uint32_t hiMsbOffset = nodep->widthConst() - 1; AstNodeExpr* const hiMsbp = new AstAdd{lfl, new AstConst{lfl, hiMsbOffset}, - nodep->lsbp()->cloneTree(false)}; + nodep->lsbp()->cloneTree(true)}; AstNodeExpr* hiwordp = // SEL(from,[hiwordnum]) newWordSel(ffl, nodep->fromp()->cloneTree(true), hiMsbp); // newWordSel clones the index, so delete it @@ -439,15 +482,16 @@ private: newp->dtypeFrom(nodep); VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep); } else { // Long/Quad from Long/Quad + // No isImpure() check - can handle side effects in below UINFO(8, " SEL->SHIFT " << nodep << endl); FileLine* const fl = nodep->fileline(); AstNodeExpr* fromp = nodep->fromp()->unlinkFrBack(); AstNodeExpr* const lsbp = nodep->lsbp()->unlinkFrBack(); - if (nodep->isQuad() && !fromp->isQuad()) { fromp = new AstCCast{fl, fromp, nodep}; } + if (nodep->isQuad() && !fromp->isQuad()) fromp = new AstCCast{fl, fromp, nodep}; // {large}>>32 requires 64-bit shift operation; then cast AstNodeExpr* newp = new AstShiftR{fl, fromp, dropCondBound(lsbp), fromp->width()}; newp->dtypeFrom(fromp); - if (!nodep->isQuad() && fromp->isQuad()) { newp = new AstCCast{fl, newp, nodep}; } + if (!nodep->isQuad() && fromp->isQuad()) newp = new AstCCast{fl, newp, nodep}; newp->dtypeFrom(nodep); VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep); } @@ -455,7 +499,7 @@ private: bool expandWide(AstNodeAssign* nodep, AstSel* rhsp) { UASSERT_OBJ(nodep->widthMin() == rhsp->widthConst(), nodep, "Width mismatch"); - if (!doExpand(nodep)) return false; + if (!doExpandWide(nodep)) return false; if (VN_IS(rhsp->lsbp(), Const) && VL_BITBIT_E(rhsp->lsbConst()) == 0) { const int lsb = rhsp->lsbConst(); UINFO(8, " Wordize ASSIGN(SEL,align) " << nodep << endl); @@ -499,6 +543,7 @@ private: // rhsp: may be allones and can remove AND NOT gate // lsbp: constant or variable // Yuk. + if (isImpure(nodep)) return false; FileLine* const nfl = nodep->fileline(); FileLine* const lfl = lhsp->fileline(); const bool destwide = lhsp->fromp()->isWide(); @@ -649,13 +694,14 @@ private: if (nodep->isWide()) { // See under ASSIGN(WIDE) } else { + // No isImpure() check - can handle side effects in below UINFO(8, " CONCAT " << nodep << endl); FileLine* const fl = nodep->fileline(); AstNodeExpr* lhsp = nodep->lhsp()->unlinkFrBack(); AstNodeExpr* rhsp = nodep->rhsp()->unlinkFrBack(); const uint32_t rhsshift = rhsp->widthMin(); - if (nodep->isQuad() && !lhsp->isQuad()) { lhsp = new AstCCast{fl, lhsp, nodep}; } - if (nodep->isQuad() && !rhsp->isQuad()) { rhsp = new AstCCast{fl, rhsp, nodep}; } + if (nodep->isQuad() && !lhsp->isQuad()) lhsp = new AstCCast{fl, lhsp, nodep}; + if (nodep->isQuad() && !rhsp->isQuad()) rhsp = new AstCCast{fl, rhsp, nodep}; AstNodeExpr* const newp = new AstOr{ fl, new AstShiftL{fl, lhsp, new AstConst{fl, rhsshift}, nodep->width()}, rhsp}; newp->dtypeFrom(nodep); // Unsigned @@ -664,7 +710,7 @@ private: } bool expandWide(AstNodeAssign* nodep, AstConcat* rhsp) { UINFO(8, " Wordize ASSIGN(CONCAT) " << nodep << endl); - if (!doExpand(rhsp)) return false; + if (!doExpandWide(rhsp)) return false; FileLine* const fl = rhsp->fileline(); // Lhs or Rhs may be word, long, or quad. // newAstWordSelClone nicely abstracts the difference. @@ -686,6 +732,7 @@ private: if (nodep->isWide()) { // See under ASSIGN(WIDE) } else { + if (isImpure(nodep)) return; FileLine* const fl = nodep->fileline(); AstNodeExpr* lhsp = nodep->lhsp()->unlinkFrBack(); AstNodeExpr* newp; @@ -719,7 +766,7 @@ private: } bool expandWide(AstNodeAssign* nodep, AstReplicate* rhsp) { UINFO(8, " Wordize ASSIGN(REPLICATE) " << nodep << endl); - if (!doExpand(rhsp)) return false; + if (!doExpandWide(rhsp)) return false; FileLine* const fl = nodep->fileline(); AstNodeExpr* const lhsp = rhsp->lhsp(); const int lhswidth = lhsp->widthMin(); @@ -748,6 +795,7 @@ private: if (nodep->user1SetOnce()) return; // Process once iterateChildren(nodep); if (nodep->lhsp()->isWide()) { + if (isImpure(nodep)) return; UINFO(8, " Wordize EQ/NEQ " << nodep << endl); // -> (0=={or{for each_word{WORDSEL(lhs,#)^WORDSEL(rhs,#)}}} FileLine* const fl = nodep->fileline(); @@ -773,6 +821,7 @@ private: iterateChildren(nodep); FileLine* const fl = nodep->fileline(); if (nodep->lhsp()->isWide()) { + if (isImpure(nodep)) return; UINFO(8, " Wordize REDOR " << nodep << endl); // -> (0!={or{for each_word{WORDSEL(lhs,#)}}} AstNodeExpr* newp = nullptr; @@ -783,6 +832,7 @@ private: newp = new AstNeq{fl, new AstConst{fl, AstConst::SizedEData{}, 0}, newp}; VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep); } else { + // No isImpure() check - can handle side effects in below UINFO(8, " REDOR->EQ " << nodep << endl); AstNodeExpr* const lhsp = nodep->lhsp()->unlinkFrBack(); AstNodeExpr* const newp = new AstNeq{ @@ -795,6 +845,7 @@ private: iterateChildren(nodep); FileLine* const fl = nodep->fileline(); if (nodep->lhsp()->isWide()) { + if (isImpure(nodep)) return; UINFO(8, " Wordize REDAND " << nodep << endl); // -> (0!={and{for each_word{WORDSEL(lhs,#)}}} AstNodeExpr* newp = nullptr; @@ -814,6 +865,7 @@ private: newp}; VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep); } else { + // No isImpure() check - can handle side effects in below UINFO(8, " REDAND->EQ " << nodep << endl); AstNodeExpr* const lhsp = nodep->lhsp()->unlinkFrBack(); AstNodeExpr* const newp = new AstEq{fl, new AstConst{fl, wordMask(lhsp)}, lhsp}; @@ -824,6 +876,7 @@ private: if (nodep->user1SetOnce()) return; // Process once iterateChildren(nodep); if (nodep->lhsp()->isWide()) { + if (isImpure(nodep)) return; UINFO(8, " Wordize REDXOR " << nodep << endl); // -> (0!={redxor{for each_word{XOR(WORDSEL(lhs,#))}}} FileLine* const fl = nodep->fileline(); @@ -906,14 +959,14 @@ public: } }; -//---------------------------------------------------------------------- -// Top loop - //###################################################################### // Expand class functions void V3Expand::expandAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); - { ExpandVisitor{nodep}; } // Destruct before checking + { + ExpandOkVisitor okVisitor{nodep}; + ExpandVisitor{nodep}; + } // Destruct before checking V3Global::dumpCheckGlobalTree("expand", 0, dumpTreeLevel() >= 3); } From de3095e3b4c459306b57f1ba0976a0d177a4fbac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Boro=C5=84ski?= <94375110+kboronski-ant@users.noreply.github.com> Date: Mon, 22 May 2023 14:29:01 +0200 Subject: [PATCH 059/129] Fix missing class forward declarations (#4151) --- src/V3CUse.cpp | 35 +++++++++++++++++++++++----- src/V3EmitCBase.cpp | 21 +++++------------ src/V3EmitCBase.h | 15 ++++++++++++ src/V3EmitCHeaders.cpp | 16 +++++++++++-- test_regress/t/t_cuse_forward.pl | 17 ++++++++++++++ test_regress/t/t_cuse_forward.v | 39 ++++++++++++++++++++++++++++++++ 6 files changed, 120 insertions(+), 23 deletions(-) create mode 100755 test_regress/t/t_cuse_forward.pl create mode 100644 test_regress/t/t_cuse_forward.v diff --git a/src/V3CUse.cpp b/src/V3CUse.cpp index d9de9a10d..0bbab0886 100644 --- a/src/V3CUse.cpp +++ b/src/V3CUse.cpp @@ -45,12 +45,16 @@ class CUseVisitor final : public VNVisitor { const VNUser1InUse m_inuser1; // MEMBERS - bool m_impOnly = false; // In details needed only for implementation AstNodeModule* const m_modp; // Current module std::set> m_didUse; // What we already used + bool m_dtypesImplOnly = false; // METHODS void addNewUse(AstNode* nodep, VUseType useType, const string& name) { + if (m_dtypesImplOnly + && (useType == VUseType::INT_INCLUDE || useType == VUseType::INT_FWD_CLASS)) + return; + if (m_didUse.emplace(useType, name).second) { AstCUse* const newp = new AstCUse{nodep->fileline(), useType, name}; m_modp->addStmtsp(newp); @@ -61,12 +65,29 @@ class CUseVisitor final : public VNVisitor { // VISITORS void visit(AstClassRefDType* nodep) override { if (nodep->user1SetOnce()) return; // Process once - if (!m_impOnly) addNewUse(nodep, VUseType::INT_FWD_CLASS, nodep->classp()->name()); - // Need to include extends() when we implement, but no need for pointers to know - VL_RESTORER(m_impOnly); + addNewUse(nodep, VUseType::INT_FWD_CLASS, nodep->classp()->name()); + } + void visit(AstCFunc* nodep) override { + if (nodep->user1SetOnce()) return; // Process once + iterateAndNextNull(nodep->argsp()); + { - m_impOnly = true; - iterateChildren(nodep->classp()); // This also gets all extend classes + VL_RESTORER(m_dtypesImplOnly); + m_dtypesImplOnly = true; + + iterateAndNextNull(nodep->initsp()); + iterateAndNextNull(nodep->stmtsp()); + iterateAndNextNull(nodep->finalsp()); + } + } + void visit(AstCReturn* nodep) override { + if (nodep->user1SetOnce()) return; // Process once + if (m_dtypesImplOnly) { + for (AstNode* exprp = nodep->op1p(); exprp; exprp = exprp->nextp()) { + if (exprp->dtypep()) iterate(exprp->dtypep()); + } + } else { + iterateChildren(nodep); } } void visit(AstNodeDType* nodep) override { @@ -79,6 +100,8 @@ class CUseVisitor final : public VNVisitor { if (stypep && stypep->classOrPackagep()) { addNewUse(nodep, VUseType::INT_INCLUDE, stypep->classOrPackagep()->name()); iterateChildren(stypep); + } else if (AstClassRefDType* const classp = VN_CAST(nodep->skipRefp(), ClassRefDType)) { + addNewUse(nodep, VUseType::INT_FWD_CLASS, classp->name()); } } void visit(AstNode* nodep) override { diff --git a/src/V3EmitCBase.cpp b/src/V3EmitCBase.cpp index 1bec37b9c..a7779be62 100644 --- a/src/V3EmitCBase.cpp +++ b/src/V3EmitCBase.cpp @@ -224,21 +224,12 @@ void EmitCBaseVisitorConst::emitVarDecl(const AstVar* nodep, bool asRef) { } void EmitCBaseVisitorConst::emitModCUse(const AstNodeModule* modp, VUseType useType) { - string nl; - for (AstNode* itemp = modp->stmtsp(); itemp; itemp = itemp->nextp()) { - if (AstCUse* const usep = VN_CAST(itemp, CUse)) { - if (usep->useType() == useType) { - if (usep->useType().isInclude()) { - puts("#include \"" + prefixNameProtect(usep) + ".h\"\n"); - } - if (usep->useType().isFwdClass()) { - puts("class " + prefixNameProtect(usep) + ";\n"); - } - nl = "\n"; - } - } - } - puts(nl); + bool nl = false; + forModCUse(modp, useType, [&](string entry) { + puts(entry); + nl = true; + }); + if (nl) puts("\n"); } void EmitCBaseVisitorConst::emitTextSection(const AstNodeModule* modp, VNType type) { diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index 5ae0074c4..4be6b7b91 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -113,6 +113,21 @@ public: void emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp, bool withScope); void emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp, bool cLinkage = false); void emitVarDecl(const AstVar* nodep, bool asRef = false); + template + static void forModCUse(const AstNodeModule* modp, VUseType useType, F action) { + for (AstNode* itemp = modp->stmtsp(); itemp; itemp = itemp->nextp()) { + if (AstCUse* const usep = VN_CAST(itemp, CUse)) { + if (usep->useType() == useType) { + if (usep->useType().isInclude()) { + action("#include \"" + prefixNameProtect(usep) + ".h\"\n"); + } + if (usep->useType().isFwdClass()) { + action("class " + prefixNameProtect(usep) + ";\n"); + } + } + } + } + } void emitModCUse(const AstNodeModule* modp, VUseType useType); void emitTextSection(const AstNodeModule* modp, VNType type); diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp index 04eac47d7..4d2a77d60 100644 --- a/src/V3EmitCHeaders.cpp +++ b/src/V3EmitCHeaders.cpp @@ -22,6 +22,7 @@ #include "V3Global.h" #include +#include #include VL_DEFINE_DEBUG_FUNCTIONS; @@ -287,11 +288,9 @@ class EmitCHeader final : public EmitCConstInit { + ".h\"\n"); } } - emitModCUse(modp, VUseType::INT_INCLUDE); // Forward declarations required by this AstNodeModule puts("\nclass " + symClassName() + ";\n"); - emitModCUse(modp, VUseType::INT_FWD_CLASS); // From `systemc_header emitTextSection(modp, VNType::atScHdr); @@ -361,6 +360,19 @@ class EmitCHeader final : public EmitCConstInit { if (v3Global.opt.coverage()) puts("#include \"verilated_cov.h\"\n"); if (v3Global.usesTiming()) puts("#include \"verilated_timing.h\"\n"); + std::set cuse_set; + auto add_to_cuse_set = [&](string s) { cuse_set.insert(s); }; + + forModCUse(modp, VUseType::INT_INCLUDE, add_to_cuse_set); + forModCUse(modp, VUseType::INT_FWD_CLASS, add_to_cuse_set); + if (const AstClassPackage* const packagep = VN_CAST(modp, ClassPackage)) { + forModCUse(packagep->classp(), VUseType::INT_INCLUDE, add_to_cuse_set); + forModCUse(packagep->classp(), VUseType::INT_FWD_CLASS, add_to_cuse_set); + } + + for (const string& s : cuse_set) puts(s); + puts("\n"); + emitAll(modp); if (const AstClassPackage* const packagep = VN_CAST(modp, ClassPackage)) { diff --git a/test_regress/t/t_cuse_forward.pl b/test_regress/t/t_cuse_forward.pl new file mode 100755 index 000000000..f17d7f547 --- /dev/null +++ b/test_regress/t/t_cuse_forward.pl @@ -0,0 +1,17 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +compile( + ); + +ok(1); +1; diff --git a/test_regress/t/t_cuse_forward.v b/test_regress/t/t_cuse_forward.v new file mode 100644 index 000000000..c1178a2d7 --- /dev/null +++ b/test_regress/t/t_cuse_forward.v @@ -0,0 +1,39 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Baz; +endclass + +class Bar#(type T) extends T; +endclass + +class Foo; + typedef struct { + int field; + } Zee; + + task t1(); + // Refer to Baz CLASSREFDTYPE node in implementation (via CLASSEXTENDS) + Bar#(Baz) b = new; + endtask + // Refer to the very same Baz CLASSREFDTYPE node again, this time within interface + task t2(Bar#(Baz)::T b); + endtask +endclass + +class Moo; + // Use Foo::Zee to cause inclusion of Foo's header file + Foo::Zee z; +endclass + +module t(); + initial begin + // Use Moo in top module to add Moo to root, causing inclusion of Foo header into + // root header. + Moo moo; + moo = new; + end +endmodule From 59825282746c0f1143d188684ecdd53a1a4d8206 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 22 May 2023 20:32:20 -0400 Subject: [PATCH 060/129] Fix duplicate std:: declaration with -I (#4215). --- Changes | 1 + src/V3Options.cpp | 5 +++++ src/V3Os.cpp | 2 +- test_regress/t/t_flag_i_empty.pl | 18 ++++++++++++++++++ test_regress/t/t_flag_i_empty.v | 8 ++++++++ 5 files changed, 33 insertions(+), 1 deletion(-) create mode 100755 test_regress/t/t_flag_i_empty.pl create mode 100644 test_regress/t/t_flag_i_empty.v diff --git a/Changes b/Changes index 518265821..160b90632 100644 --- a/Changes +++ b/Changes @@ -31,6 +31,7 @@ Verilator 5.011 devel * Fix arrays of unpacked structs (#4173). [Risto Pejašinović] * Fix $fscanf of decimals overflowing variables (#4174). [Ahmed El-Mahmoudy] * Fix super.new missing data type (#4147). [Tudor Timi] +* Fix duplicate std:: declaration with -I (#4215). [Harald Pretl] * Fix detection of wire/reg duplicates. * Fix false IMPLICITSTATIC on package functions. diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 3b8a26040..9c309bc09 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -547,6 +547,11 @@ string V3Options::filePath(FileLine* fl, const string& modname, const string& la // Find a filename to read the specified module name, // using the incdir and libext's. // Return "" if not found. + if (modname[0] == '/') { + // If leading /, obey existing absolute path, so can find getStdPackagePath() + string exists = filePathCheckOneDir(modname, ""); + if (exists != "") return exists; + } for (const string& dir : m_impp->m_incDirUsers) { string exists = filePathCheckOneDir(modname, dir); if (exists != "") return exists; diff --git a/src/V3Os.cpp b/src/V3Os.cpp index 4a80f98ac..3fb7ec5ee 100644 --- a/src/V3Os.cpp +++ b/src/V3Os.cpp @@ -126,7 +126,7 @@ void V3Os::setenvStr(const string& envvar, const string& value, const string& wh string V3Os::filenameFromDirBase(const string& dir, const string& basename) { // Don't return ./{filename} because if filename was absolute, that makes it relative - if (dir == ".") { + if (dir.empty() || dir == ".") { return basename; } else { return dir + "/" + basename; diff --git a/test_regress/t/t_flag_i_empty.pl b/test_regress/t/t_flag_i_empty.pl new file mode 100755 index 000000000..8cee660a7 --- /dev/null +++ b/test_regress/t/t_flag_i_empty.pl @@ -0,0 +1,18 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +compile( + verilator_flags2 => ["-Wno-MODDUP -I t_flag_i_empty.v t_flag_i_empty.v"], + ); + +ok(1); +1; diff --git a/test_regress/t/t_flag_i_empty.v b/test_regress/t/t_flag_i_empty.v new file mode 100644 index 000000000..df8679e7d --- /dev/null +++ b/test_regress/t/t_flag_i_empty.v @@ -0,0 +1,8 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2016 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; +endmodule From 167a30be1cc4156954babb1f25ed82faf2df7609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Boro=C5=84ski?= <94375110+kboronski-ant@users.noreply.github.com> Date: Tue, 23 May 2023 15:01:57 +0200 Subject: [PATCH 061/129] Fix deep traversal of class inheritance timing (#4216) --- src/V3Timing.cpp | 52 ++++++++++++++++++---------- test_regress/t/t_suspendable_deep.pl | 18 ++++++++++ test_regress/t/t_suspendable_deep.v | 35 +++++++++++++++++++ 3 files changed, 87 insertions(+), 18 deletions(-) create mode 100755 test_regress/t/t_suspendable_deep.pl create mode 100644 test_regress/t/t_suspendable_deep.v diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index a49761636..184ba25d8 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -57,6 +57,8 @@ #include "V3SenTree.h" #include "V3UniqueNames.h" +#include + VL_DEFINE_DEBUG_FUNCTIONS; // ###################################################################### @@ -143,26 +145,40 @@ private: if (!m_classp) return; // If class method (possibly overrides another method) if (!m_classp->user1SetOnce()) m_classp->repairCache(); + // Go over overridden functions - for (auto* cextp = m_classp->extendsp(); cextp; - cextp = VN_AS(cextp->nextp(), ClassExtends)) { - // TODO: It is possible that a methods the same name in the base class is not - // actually overridden by our method. If this causes a problem, traverse to the - // root of the inheritance hierarchy and check if the original method is virtual or - // not. - if (!cextp->classp()->user1SetOnce()) cextp->classp()->repairCache(); - if (auto* const overriddenp - = VN_CAST(cextp->classp()->findMember(nodep->name()), CFunc)) { - if (overriddenp->user2()) { // If it's suspendable - nodep->user2(true); // Then we are also suspendable - // As both are suspendable already, there is no need to add it as our - // dependency or self to its dependencies + + std::queue extends; + if (m_classp->extendsp()) extends.push(m_classp->extendsp()); + + while (!extends.empty()) { + AstClassExtends* ext_list = extends.front(); + extends.pop(); + + for (AstClassExtends* cextp = ext_list; cextp; + cextp = VN_AS(cextp->nextp(), ClassExtends)) { + // TODO: It is possible that a methods the same name in the base class is not + // actually overridden by our method. If this causes a problem, traverse to + // the root of the inheritance hierarchy and check if the original method is + // virtual or not. + if (!cextp->classp()->user1SetOnce()) cextp->classp()->repairCache(); + if (AstCFunc* const overriddenp + = VN_CAST(cextp->classp()->findMember(nodep->name()), CFunc)) { + if (overriddenp->user2()) { // If it's suspendable + nodep->user2(true); // Then we are also suspendable + // As both are suspendable already, there is no need to add it as our + // dependency or self to its dependencies + } else { + // Make a dependency cycle, as being suspendable should propagate both + // up and down the inheritance tree + TimingDependencyVertex* const overriddenVxp + = getDependencyVertex(overriddenp); + new V3GraphEdge{&m_depGraph, vxp, overriddenVxp, 1}; + new V3GraphEdge{&m_depGraph, overriddenVxp, vxp, 1}; + } } else { - // Make a dependency cycle, as being suspendable should propagate both up - // and down the inheritance tree - TimingDependencyVertex* const overriddenVxp = getDependencyVertex(overriddenp); - new V3GraphEdge{&m_depGraph, vxp, overriddenVxp, 1}; - new V3GraphEdge{&m_depGraph, overriddenVxp, vxp, 1}; + AstClassExtends* more_extends = cextp->classp()->extendsp(); + if (more_extends) extends.push(more_extends); } } } diff --git a/test_regress/t/t_suspendable_deep.pl b/test_regress/t/t_suspendable_deep.pl new file mode 100755 index 000000000..e7824bce9 --- /dev/null +++ b/test_regress/t/t_suspendable_deep.pl @@ -0,0 +1,18 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +compile( + verilator_flags2 => ["--timing"], + ); + +ok(1); +1; diff --git a/test_regress/t/t_suspendable_deep.v b/test_regress/t/t_suspendable_deep.v new file mode 100644 index 000000000..32ecd0a4c --- /dev/null +++ b/test_regress/t/t_suspendable_deep.v @@ -0,0 +1,35 @@ +// DESCRIPTION: Verilator: Verilog Test module for specialized type default values +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +`timescale 1ns/1ns + +event evt; + +class Baz; + virtual task do_something(); endtask +endclass + +class Foo extends Baz; +endclass + +class Bar extends Foo; + virtual task do_something(); + @evt $display("Hello"); + endtask +endclass + +module top(); + initial begin + Bar bar; + bar = new; + + fork + #10 bar.do_something(); + #20 $display("world!"); + #10 ->evt; + join + end +endmodule From fb0d735f68428986d5ede4a62595890fcc82581e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Boro=C5=84ski?= <94375110+kboronski-ant@users.noreply.github.com> Date: Tue, 23 May 2023 20:02:40 +0200 Subject: [PATCH 062/129] Tests: Skip t_suspendable_deep if coroutines are not supported by CXX toolchain (#4217) --- test_regress/t/t_suspendable_deep.pl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/test_regress/t/t_suspendable_deep.pl b/test_regress/t/t_suspendable_deep.pl index e7824bce9..422d61e57 100755 --- a/test_regress/t/t_suspendable_deep.pl +++ b/test_regress/t/t_suspendable_deep.pl @@ -10,9 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -compile( - verilator_flags2 => ["--timing"], - ); +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--timing"], + ); +} ok(1); 1; From 19d0aabe7ad1e185254b70e2ce12122b3ca87905 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 23 May 2023 20:52:30 -0400 Subject: [PATCH 063/129] Internals: Fix extra cast on ExprStmt. --- src/V3AstNodeExpr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index bd54322c2..0216bbb3e 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -1106,7 +1106,7 @@ public: // METHODS string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } - bool cleanOut() const override { return false; } + bool cleanOut() const override { return true; } bool same(const AstNode*) const override { return true; } }; class AstFError final : public AstNodeExpr { From 426069a4dd72300e54724274716f7bc041a269eb Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 23 May 2023 21:26:29 -0400 Subject: [PATCH 064/129] Configure for faster C++ linking using 'mold', if it is installed. --- Changes | 1 + ci/ci-install.bash | 4 ++-- configure.ac | 5 +++++ docs/guide/install.rst | 3 ++- include/verilated.mk.in | 4 ++++ 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Changes b/Changes index 160b90632..1ebbc3f19 100644 --- a/Changes +++ b/Changes @@ -21,6 +21,7 @@ Verilator 5.011 devel * Support get_randstate/set_randstate class method function. * Add creating __inputs.vpp file with --debug (#4177). [Tudor Timi] * Optimize VPI callValueCbs (#4155). [Hennadii Chernyshchyk] +* Configure for faster C++ linking using 'mold', if it is installed. * Fix crash on duplicate imported modules (#3231). [Robert Balas] * Fix false WIDTHEXPAND on array declarations (#3959). [JOTEGO] * Fix marking overridden methods as coroutines (#4120) (#4169). [Krzysztof Bieganski, Antmicro Ltd] diff --git a/ci/ci-install.bash b/ci/ci-install.bash index d3372a798..648620c81 100755 --- a/ci/ci-install.bash +++ b/ci/ci-install.bash @@ -63,8 +63,8 @@ if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then sudo apt-get install ccache help2man libfl-dev if [ "$CI_RUNS_ON" != "ubuntu-22.04" ]; then # Some conflict of libunwind verison on 22.04, can live without it for now - sudo apt-get install libgoogle-perftools-dev || - sudo apt-get install libgoogle-perftools-dev + sudo apt-get install libgoogle-perftools-dev mold || + sudo apt-get install libgoogle-perftools-dev mold fi if [ "$CI_RUNS_ON" = "ubuntu-20.04" ] || [ "$CI_RUNS_ON" = "ubuntu-22.04" ]; then sudo apt-get install libsystemc libsystemc-dev || diff --git a/configure.ac b/configure.ac index 43bd263f1..3b8977d34 100644 --- a/configure.ac +++ b/configure.ac @@ -470,6 +470,10 @@ m4_foreach([ldflag], [ AC_SUBST(CFG_LDLIBS_THREADS) AC_SUBST(CFG_LDFLAGS_THREADS_CMAKE) +# If 'mold' is installed, use it to link for faster buildtimes +_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -fuse-ld=mold) +_MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_VERILATED, -fuse-ld=mold) + # When linking partially statically if test "$CFG_ENABLE_PARTIAL_STATIC" = "yes"; then _MY_LDLIBS_CHECK_OPT(CFG_LDFLAGS_SRC, -static-libgcc) @@ -480,6 +484,7 @@ else LTCMALLOC=-ltcmalloc_minimal fi AC_SUBST(CFG_LDFLAGS_SRC) +AC_SUBST(CFG_LDFLAGS_VERILATED) # The pthread library is required by tcmalloc, so add it if it exists. If it # does not, the tcmalloc check below will fail anyway, and linking against diff --git a/docs/guide/install.rst b/docs/guide/install.rst index 594773ae6..a862b4abb 100644 --- a/docs/guide/install.rst +++ b/docs/guide/install.rst @@ -104,6 +104,7 @@ for good performance: :: sudo apt-get install ccache # If present at build, needed for run + sudo apt-get install mold # If present at build, needed for run sudo apt-get install libgoogle-perftools-dev numactl The following is optional but is recommended for nicely rendered command line @@ -124,7 +125,7 @@ Those developing Verilator itself may also want these (see internals.rst): :: - sudo apt-get install gdb graphviz cmake clang clang-format-14 gprof lcov + sudo apt-get install clang clang-format-14 cmake gdb gprof graphviz lcov sudo apt-get install libclang-dev yapf3 sudo pip3 install clang sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe ruff cpan install Pod::Perldoc diff --git a/include/verilated.mk.in b/include/verilated.mk.in index 7a2d51ff6..4f138288b 100644 --- a/include/verilated.mk.in +++ b/include/verilated.mk.in @@ -31,6 +31,8 @@ CFG_CXXFLAGS_NO_UNUSED = @CFG_CXXFLAGS_NO_UNUSED@ CFG_CXXFLAGS_WEXTRA = @CFG_CXXFLAGS_WEXTRA@ # Compiler flags that enable coroutine support CFG_CXXFLAGS_COROUTINES = @CFG_CXXFLAGS_COROUTINES@ +# Linker flags +CFG_LDFLAGS_VERILATED = @CFG_LDFLAGS_VERILATED@ # Linker libraries for multithreading CFG_LDLIBS_THREADS = @CFG_LDLIBS_THREADS@ @@ -77,6 +79,8 @@ VPATH += .. VPATH += $(VERILATOR_ROOT)/include VPATH += $(VERILATOR_ROOT)/include/vltstd +LDFLAGS += $(CFG_LDFLAGS_VERILATED) + #OPT = -ggdb -DPRINTINITSTR -DDETECTCHANGE #OPT = -ggdb -DPRINTINITSTR CPPFLAGS += $(OPT) From 5704552053a172da300a6a68d83da9ffb7f40e92 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 23 May 2023 21:30:39 -0400 Subject: [PATCH 065/129] Fix ci for mold --- ci/ci-install.bash | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ci/ci-install.bash b/ci/ci-install.bash index 648620c81..89c0e1c30 100755 --- a/ci/ci-install.bash +++ b/ci/ci-install.bash @@ -63,13 +63,17 @@ if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then sudo apt-get install ccache help2man libfl-dev if [ "$CI_RUNS_ON" != "ubuntu-22.04" ]; then # Some conflict of libunwind verison on 22.04, can live without it for now - sudo apt-get install libgoogle-perftools-dev mold || - sudo apt-get install libgoogle-perftools-dev mold + sudo apt-get install libgoogle-perftools-dev || + sudo apt-get install libgoogle-perftools-dev fi if [ "$CI_RUNS_ON" = "ubuntu-20.04" ] || [ "$CI_RUNS_ON" = "ubuntu-22.04" ]; then sudo apt-get install libsystemc libsystemc-dev || sudo apt-get install libsystemc libsystemc-dev fi + if [ "$CI_RUNS_ON" = "ubuntu-22.04" ]; then + sudo apt-get install mold || + sudo apt-get install mold + fi if [ "$COVERAGE" = 1 ]; then yes yes | sudo cpan -fi Parallel::Forker fi From c8ca54ea31857199671c29084437cd4a6defaa5d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 23 May 2023 22:24:47 -0400 Subject: [PATCH 066/129] CI: Disable m32 on g++ --- .github/workflows/build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6e504dcfa..b909ed429 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -39,9 +39,10 @@ jobs: - os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }} - os: ${{ github.event_name == 'pull_request' && 'ubuntu-20.04' || 'do-not-exclude' }} - m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }} - # Build -m32 only on ubuntu-22.04 + # Build -m32 only on ubuntu-22.04 clang++ - {os: ubuntu-18.04, m32: 1} - {os: ubuntu-20.04, m32: 1} + - {cc: g++, m32: 1} include: # Build GCC 10 on ubuntu-20.04 - os: ubuntu-20.04 From d66e749ec88f204cf6564b3c1ac50d28ea4edcb0 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 23 May 2023 22:25:03 -0400 Subject: [PATCH 067/129] CI: Fix mold build --- ci/ci-install.bash | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/ci-install.bash b/ci/ci-install.bash index 89c0e1c30..96a223c81 100755 --- a/ci/ci-install.bash +++ b/ci/ci-install.bash @@ -61,7 +61,7 @@ if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then sudo apt-get update sudo apt-get install ccache help2man libfl-dev || sudo apt-get install ccache help2man libfl-dev - if [ "$CI_RUNS_ON" != "ubuntu-22.04" ]; then + if [ "$CI_RUNS_ON" = "ubuntu-20.04" ]; then # Some conflict of libunwind verison on 22.04, can live without it for now sudo apt-get install libgoogle-perftools-dev || sudo apt-get install libgoogle-perftools-dev @@ -106,8 +106,8 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then sudo apt-get install gdb gtkwave lcov libfl-dev ccache # Required for test_regress/t/t_dist_attributes.pl if [ "$CI_RUNS_ON" = "ubuntu-22.04" ]; then - sudo apt-get install libclang-dev || - sudo apt-get install libclang-dev + sudo apt-get install libclang-dev mold || + sudo apt-get install libclang-dev mold pip3 install clang==14.0 fi if [ "$CI_RUNS_ON" = "ubuntu-20.04" ] || [ "$CI_RUNS_ON" = "ubuntu-22.04" ]; then From a301a498f5a86d108d195d7c58cf1444b8adb1b7 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 23 May 2023 22:27:10 -0400 Subject: [PATCH 068/129] CI: Disable m32 on g++ --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b909ed429..c6ed5e88c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -42,7 +42,7 @@ jobs: # Build -m32 only on ubuntu-22.04 clang++ - {os: ubuntu-18.04, m32: 1} - {os: ubuntu-20.04, m32: 1} - - {cc: g++, m32: 1} + - {cc: gcc, m32: 1} include: # Build GCC 10 on ubuntu-20.04 - os: ubuntu-20.04 From 542eaab3dd17350508b012b6fc3746dee4570b2b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 23 May 2023 22:28:40 -0400 Subject: [PATCH 069/129] CI: Disable m32 on g++ --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c6ed5e88c..92dd1716d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -42,7 +42,7 @@ jobs: # Build -m32 only on ubuntu-22.04 clang++ - {os: ubuntu-18.04, m32: 1} - {os: ubuntu-20.04, m32: 1} - - {cc: gcc, m32: 1} + - {compiler: gcc, m32: 1} include: # Build GCC 10 on ubuntu-20.04 - os: ubuntu-20.04 From 09fb1174f137cbbcf2fd91b9755c05c9434bb728 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 23 May 2023 22:34:27 -0400 Subject: [PATCH 070/129] CI: Disable m32 on g++ --- .github/workflows/build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 92dd1716d..286d1d651 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -42,7 +42,8 @@ jobs: # Build -m32 only on ubuntu-22.04 clang++ - {os: ubuntu-18.04, m32: 1} - {os: ubuntu-20.04, m32: 1} - - {compiler: gcc, m32: 1} + - { cc: gcc, cxx: g++ } + m32: 1 include: # Build GCC 10 on ubuntu-20.04 - os: ubuntu-20.04 From 607f853bc7d4bf752152140d00bb4bbb772ee26d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 23 May 2023 22:35:07 -0400 Subject: [PATCH 071/129] CI: Disable m32 on g++ --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 286d1d651..706629ce2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -42,7 +42,7 @@ jobs: # Build -m32 only on ubuntu-22.04 clang++ - {os: ubuntu-18.04, m32: 1} - {os: ubuntu-20.04, m32: 1} - - { cc: gcc, cxx: g++ } + - compiler: { cc: gcc, cxx: g++ } m32: 1 include: # Build GCC 10 on ubuntu-20.04 From fd7515b0467407b90aa6db712e0f7899f6059286 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 23 May 2023 22:40:19 -0400 Subject: [PATCH 072/129] Tests: Cleanup scenarios lines. No test run change. --- test_regress/t/t_lib.pl | 5 +---- test_regress/t/t_lib_nolib.pl | 5 +---- test_regress/t/t_lib_prot.pl | 5 +---- test_regress/t/t_lib_prot_clk_gated.pl | 5 +---- test_regress/t/t_lib_prot_comb.pl | 5 +---- test_regress/t/t_lib_prot_shared.pl | 6 +----- 6 files changed, 6 insertions(+), 25 deletions(-) diff --git a/test_regress/t/t_lib.pl b/test_regress/t/t_lib.pl index ef6fcd3b2..de31f55b6 100755 --- a/test_regress/t/t_lib.pl +++ b/test_regress/t/t_lib.pl @@ -11,10 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios( - vlt => 1, - xsim => 1, - ); +scenarios(vlt => 1, xsim => 1); top_filename("t/t_lib_prot.v"); diff --git a/test_regress/t/t_lib_nolib.pl b/test_regress/t/t_lib_nolib.pl index 0a385f0cb..b463b16b6 100755 --- a/test_regress/t/t_lib_nolib.pl +++ b/test_regress/t/t_lib_nolib.pl @@ -11,10 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios( - vlt => 1, - xsim => 1, - ); +scenarios(vlt => 1, xsim => 1); $Self->{sim_time} = $Self->{benchmark} * 100 if $Self->{benchmark}; top_filename("t/t_lib_prot.v"); diff --git a/test_regress/t/t_lib_prot.pl b/test_regress/t/t_lib_prot.pl index 14c01dc7c..dddc68012 100755 --- a/test_regress/t/t_lib_prot.pl +++ b/test_regress/t/t_lib_prot.pl @@ -11,10 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios( - vlt => 1, - xsim => 1, - ); +scenarios(vlt => 1, xsim => 1); $Self->{sim_time} = $Self->{benchmark} * 100 if $Self->{benchmark}; diff --git a/test_regress/t/t_lib_prot_clk_gated.pl b/test_regress/t/t_lib_prot_clk_gated.pl index b1286cca2..787f69ad9 100755 --- a/test_regress/t/t_lib_prot_clk_gated.pl +++ b/test_regress/t/t_lib_prot_clk_gated.pl @@ -11,10 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios( - vlt => 1, - xsim => 1, - ); +scenarios(vlt => 1, xsim => 1); $Self->{sim_time} = $Self->{benchmark} * 100 if $Self->{benchmark}; diff --git a/test_regress/t/t_lib_prot_comb.pl b/test_regress/t/t_lib_prot_comb.pl index 73cfd8aef..961af3799 100755 --- a/test_regress/t/t_lib_prot_comb.pl +++ b/test_regress/t/t_lib_prot_comb.pl @@ -11,10 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios( - vlt => 1, - xsim => 1, - ); +scenarios(vlt => 1, xsim => 1); $Self->{sim_time} = $Self->{benchmark} * 100 if $Self->{benchmark}; diff --git a/test_regress/t/t_lib_prot_shared.pl b/test_regress/t/t_lib_prot_shared.pl index b7fab1e92..02d95a9e7 100755 --- a/test_regress/t/t_lib_prot_shared.pl +++ b/test_regress/t/t_lib_prot_shared.pl @@ -11,11 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios( - vlt => 1, - vltmt => 1, - xsim => 1, - ); +scenarios(vlt_all => 1, xsim => 1); top_filename("t/t_lib_prot.v"); $Self->{sim_time} = $Self->{benchmark} * 100 if $Self->{benchmark}; From ff324625e49a5f18a477e2479ae1854b71619b61 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 23 May 2023 23:04:24 -0400 Subject: [PATCH 073/129] CI: Disable m32 on g++ --- .github/workflows/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 706629ce2..8959e8ea1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -113,6 +113,8 @@ jobs: # Build -m32 only on ubuntu-22.04 - {os: ubuntu-18.04, m32: 1} - {os: ubuntu-20.04, m32: 1} + - compiler: { cc: gcc, cxx: g++ } + m32: 1 include: # Test with GCC 10 on ubuntu-20.04 without m32 - {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: dist-vlt-0} From 4f7e155e59ef0e207ba93446c18ce78836606232 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Wed, 24 May 2023 15:51:03 +0200 Subject: [PATCH 074/129] Fix class parameters of enum types (#4219) --- src/V3Param.cpp | 8 ++++++-- test_regress/t/t_class_param_enum.pl | 21 +++++++++++++++++++ test_regress/t/t_class_param_enum.v | 25 +++++++++++++++++++++++ test_regress/t/t_class_param_enum_bad.out | 11 ++++++++++ test_regress/t/t_class_param_enum_bad.pl | 19 +++++++++++++++++ test_regress/t/t_class_param_enum_bad.v | 24 ++++++++++++++++++++++ 6 files changed, 106 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_class_param_enum.pl create mode 100644 test_regress/t/t_class_param_enum.v create mode 100644 test_regress/t/t_class_param_enum_bad.out create mode 100755 test_regress/t/t_class_param_enum_bad.pl create mode 100644 test_regress/t/t_class_param_enum_bad.v diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 7ebafda9e..ba39ef6e6 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -307,7 +307,9 @@ class ParamProcessor final : public VNDeleter { } static string paramValueString(const AstNode* nodep) { - if (const AstRefDType* const refp = VN_CAST(nodep, RefDType)) { nodep = refp->skipRefp(); } + if (const AstRefDType* const refp = VN_CAST(nodep, RefDType)) { + nodep = refp->skipRefToEnump(); + } string key = nodep->name(); if (const AstIfaceRefDType* const ifrtp = VN_CAST(nodep, IfaceRefDType)) { if (ifrtp->cellp() && ifrtp->cellp()->modp()) { @@ -344,7 +346,9 @@ class ParamProcessor final : public VNDeleter { // TODO: This parameter value number lookup via a constructed key string is not // particularly robust for type parameters. We should really have a type // equivalence predicate function. - if (const AstRefDType* const refp = VN_CAST(nodep, RefDType)) nodep = refp->skipRefp(); + if (const AstRefDType* const refp = VN_CAST(nodep, RefDType)) { + nodep = refp->skipRefToEnump(); + } const string paramStr = paramValueString(nodep); // cppcheck-has-bug-suppress unreadVariable V3Hash hash = V3Hasher::uncachedHash(nodep) + paramStr; diff --git a/test_regress/t/t_class_param_enum.pl b/test_regress/t/t_class_param_enum.pl new file mode 100755 index 000000000..1aa73f80a --- /dev/null +++ b/test_regress/t/t_class_param_enum.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 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_param_enum.v b/test_regress/t/t_class_param_enum.v new file mode 100644 index 000000000..a8d499f47 --- /dev/null +++ b/test_regress/t/t_class_param_enum.v @@ -0,0 +1,25 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +typedef enum bit {A = 0, B = 1} enum_t; + +class Converter #(type T); + function int toInt(T t); + return int'(t); + endfunction +endclass + +module t; + initial begin + Converter#(enum_t) conv1 = new; + Converter#(bit) conv2 = new; + if (conv1.toInt(A) != 0) $stop; + if (conv2.toInt(1) != 1) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_param_enum_bad.out b/test_regress/t/t_class_param_enum_bad.out new file mode 100644 index 000000000..fd4e547e9 --- /dev/null +++ b/test_regress/t/t_class_param_enum_bad.out @@ -0,0 +1,11 @@ +%Error: t/t_class_param_enum_bad.v:20:31: Assign RHS expects a CLASSREFDTYPE 'Converter__Tz2', got CLASSREFDTYPE 'Converter__Tz1' + : ... In instance t + 20 | Converter#(bit) conv2 = conv1; + | ^~~~~ +%Error-ENUMVALUE: t/t_class_param_enum_bad.v:21:19: Implicit conversion to enum 'T' from 'logic[31:0]' (IEEE 1800-2017 6.19.3) + : ... In instance t + : ... Suggest use enum's mnemonic, or static cast + 21 | conv1.toInt(0); + | ^ + ... For error description see https://verilator.org/warn/ENUMVALUE?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_class_param_enum_bad.pl b/test_regress/t/t_class_param_enum_bad.pl new file mode 100755 index 000000000..430290c0a --- /dev/null +++ b/test_regress/t/t_class_param_enum_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 Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_param_enum_bad.v b/test_regress/t/t_class_param_enum_bad.v new file mode 100644 index 000000000..55b5e824c --- /dev/null +++ b/test_regress/t/t_class_param_enum_bad.v @@ -0,0 +1,24 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +typedef enum bit {A = 0, B = 1} enum_t; + +class Converter #(type T); + function int toInt(T t); + return int'(t); + endfunction +endclass + +module t; + initial begin + Converter#(enum_t) conv1 = new; + // enum types does not match with other types (sections 6.22.1 and 6.22.4 of IEEE Std 1800-2017) + // The assignment and the function call should throw an error. + Converter#(bit) conv2 = conv1; + conv1.toInt(0); + $stop; + end +endmodule From 0ece1554180abfe8cc134bebf59f4530e6c5cc4e Mon Sep 17 00:00:00 2001 From: Mariusz Glebocki Date: Thu, 25 May 2023 00:53:14 +0200 Subject: [PATCH 075/129] Internals: Move some includes to .cpp files. (#4224) --- src/V3Assert.cpp | 1 + src/V3Assert.h | 1 - src/V3Options.cpp | 1 + src/V3Options.h | 1 - 4 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 91ae114ca..6135eabde 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -20,6 +20,7 @@ #include "V3Assert.h" #include "V3Ast.h" +#include "V3Error.h" #include "V3Global.h" #include "V3Stats.h" diff --git a/src/V3Assert.h b/src/V3Assert.h index 0715dd405..dcf26756a 100644 --- a/src/V3Assert.h +++ b/src/V3Assert.h @@ -21,7 +21,6 @@ #include "verilatedos.h" #include "V3Ast.h" -#include "V3Error.h" //============================================================================ diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 9c309bc09..d6d3fec8e 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -23,6 +23,7 @@ #include "V3Error.h" #include "V3File.h" #include "V3Global.h" +#include "V3Mutex.h" #include "V3OptionParser.h" #include "V3Os.h" #include "V3PreShell.h" diff --git a/src/V3Options.h b/src/V3Options.h index 360c28b53..7e6b639b3 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -22,7 +22,6 @@ #include "V3Error.h" #include "V3LangCode.h" -#include "V3Mutex.h" #include #include From 8303938d0e82078b15f5d19302499eb651697db9 Mon Sep 17 00:00:00 2001 From: Mariusz Glebocki Date: Thu, 25 May 2023 13:35:14 +0200 Subject: [PATCH 076/129] Internals: Make mutex classes uncopyable. (#4223) --- include/verilated.h | 1 + src/V3Mutex.h | 1 + 2 files changed, 2 insertions(+) diff --git a/include/verilated.h b/include/verilated.h index a66472266..4ee19b681 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -175,6 +175,7 @@ public: /// Construct mutex (without locking it) VerilatedMutex() = default; ~VerilatedMutex() = default; + VL_UNCOPYABLE(VerilatedMutex); const VerilatedMutex& operator!() const { return *this; } // For -fthread_safety /// Acquire/lock mutex void lock() VL_ACQUIRE() VL_MT_SAFE { diff --git a/src/V3Mutex.h b/src/V3Mutex.h index 2d9e99eda..c5f3883a7 100644 --- a/src/V3Mutex.h +++ b/src/V3Mutex.h @@ -85,6 +85,7 @@ public: /// Construct mutex (without locking it) V3MutexImp() = default; ~V3MutexImp() = default; + VL_UNCOPYABLE(V3MutexImp); const V3MutexImp& operator!() const { return *this; } // For -fthread_safety /// Acquire/lock mutex void lock() VL_ACQUIRE() VL_MT_SAFE { From 42beaf467c4ed381085ae49bd210fb79a58cb937 Mon Sep 17 00:00:00 2001 From: Aleksander Kiryk Date: Thu, 25 May 2023 11:06:37 -0700 Subject: [PATCH 077/129] Tests: Add incomplete type definition test (#4230) --- test_regress/t/t_no_typedef_bad.out | 4 ++++ test_regress/t/t_no_typedef_bad.pl | 20 ++++++++++++++++++++ test_regress/t/t_no_typedef_bad.v | 11 +++++++++++ 3 files changed, 35 insertions(+) create mode 100644 test_regress/t/t_no_typedef_bad.out create mode 100755 test_regress/t/t_no_typedef_bad.pl create mode 100644 test_regress/t/t_no_typedef_bad.v diff --git a/test_regress/t/t_no_typedef_bad.out b/test_regress/t/t_no_typedef_bad.out new file mode 100644 index 000000000..8b5c328f7 --- /dev/null +++ b/test_regress/t/t_no_typedef_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_no_typedef_bad.v:10:4: Can't find typedef: 'sometype' + 10 | sometype p; + | ^~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_no_typedef_bad.pl b/test_regress/t/t_no_typedef_bad.pl new file mode 100755 index 000000000..8aaa0fb99 --- /dev/null +++ b/test_regress/t/t_no_typedef_bad.pl @@ -0,0 +1,20 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 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( + verilator_flags2 => ["--xml-only"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_no_typedef_bad.v b/test_regress/t/t_no_typedef_bad.v new file mode 100644 index 000000000..61cc81209 --- /dev/null +++ b/test_regress/t/t_no_typedef_bad.v @@ -0,0 +1,11 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +typedef sometype; + +module t(/*AUTOARG*/); + sometype p; +endmodule From bfa1f2d7ceecf8e4dd251ec22d9462a026da9187 Mon Sep 17 00:00:00 2001 From: Jiamin Zhu <43701209+Jomit626@users.noreply.github.com> Date: Fri, 26 May 2023 08:13:02 +0800 Subject: [PATCH 078/129] Fix missing assignment for wide unpacked structs (#4233) --- docs/CONTRIBUTORS | 1 + src/V3EmitCFunc.h | 1 + test_regress/t/t_structu_wide.pl | 22 ++++++++++++++++++++++ test_regress/t/t_structu_wide.v | 29 +++++++++++++++++++++++++++++ 4 files changed, 53 insertions(+) create mode 100755 test_regress/t/t_structu_wide.pl create mode 100644 test_regress/t/t_structu_wide.v diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 2baed846f..ba86f3b4d 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -73,6 +73,7 @@ Jiuyang Liu Joey Liu John Coiner John Demme +Jiamin Zhu Jonathan Drolet Jose Loyola Joseph Nwabueze diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index c95e8ed46..657f1d955 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -354,6 +354,7 @@ public: && !VN_IS(nodep->rhsp(), CMethodHard) // && !VN_IS(nodep->rhsp(), VarRef) // && !VN_IS(nodep->rhsp(), AssocSel) // + && !VN_IS(nodep->rhsp(), StructSel) // && !VN_IS(nodep->rhsp(), ArraySel)) { // Wide functions assign into the array directly, don't need separate assign statement m_wideTempRefp = VN_AS(nodep->lhsp(), VarRef); diff --git a/test_regress/t/t_structu_wide.pl b/test_regress/t/t_structu_wide.pl new file mode 100755 index 000000000..e039728bc --- /dev/null +++ b/test_regress/t/t_structu_wide.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + verilator_flags2 => [ '-DWIDE_WIDTH=128' ], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_structu_wide.v b/test_regress/t/t_structu_wide.v new file mode 100644 index 000000000..11858ba44 --- /dev/null +++ b/test_regress/t/t_structu_wide.v @@ -0,0 +1,29 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Jomit626. +// SPDX-License-Identifier: CC0-1.0 + +`ifndef WIDE_WIDTH +`define WIDE_WIDTH 128 +`endif + +module t (); + typedef struct { + bit [`WIDE_WIDTH-1:0] data; + } wide_t; + + logic [`WIDE_WIDTH-1:0] ldata; + wide_t wide_0; + + initial begin + wide_0.data = `WIDE_WIDTH'hda7ada7a; + ldata = wide_0.data; + + if (ldata != `WIDE_WIDTH'hda7ada7a) + $stop(); + + $write("*-* All Finished *-*\n"); + $finish(); + end +endmodule From 519792d02b470a698b306a6571bf0b1ca7ac8540 Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Fri, 26 May 2023 02:20:44 +0200 Subject: [PATCH 079/129] Fix to commit coroutines immediately on `wait` statements (#4229) Event-triggered coroutines live in two stages: 'uncommitted' and 'ready'. First they land in 'uncommitted', meaning they can't be resumed yet. Only after coroutines from the 'ready' queue are resumed, the 'uncommitted' ones are moved to the 'ready' queue, and can be resumed. This is to avoid self-triggering in situations like waiting for an event immediately after triggering it. However, there is an issue with `wait` statements. If you have a `wait(b)`, it's being translated into a loop that awaits a change in `b` as long as `b` is false. If `b` is false at first, the coroutine is put into the `uncommitted` queue. If `b` is set to true before it's committed, the coroutine won't get resumed. This patch fixes that by immediately committing event controls created from `wait` statements. That means the coroutine from the example above will get resumed from now on. --- include/verilated_timing.cpp | 5 +-- include/verilated_timing.h | 10 ++++-- src/V3SchedTiming.cpp | 8 ++++- src/V3Timing.cpp | 13 +++++-- test_regress/t/t_lint_wait_bad.out | 8 ++--- test_regress/t/t_lint_wait_bad.pl | 2 +- .../t/{t_timing_wait.pl => t_timing_wait1.pl} | 0 .../t/{t_timing_wait.v => t_timing_wait1.v} | 0 test_regress/t/t_timing_wait2.out | 4 +++ test_regress/t/t_timing_wait2.pl | 29 +++++++++++++++ test_regress/t/t_timing_wait2.v | 35 +++++++++++++++++++ 11 files changed, 100 insertions(+), 14 deletions(-) rename test_regress/t/{t_timing_wait.pl => t_timing_wait1.pl} (100%) rename test_regress/t/{t_timing_wait.v => t_timing_wait1.v} (100%) create mode 100644 test_regress/t/t_timing_wait2.out create mode 100755 test_regress/t/t_timing_wait2.pl create mode 100644 test_regress/t/t_timing_wait2.v diff --git a/include/verilated_timing.cpp b/include/verilated_timing.cpp index f644ed64f..d3fa2cf1b 100644 --- a/include/verilated_timing.cpp +++ b/include/verilated_timing.cpp @@ -95,8 +95,9 @@ void VlTriggerScheduler::resume(const char* eventDescription) { VL_DEBUG_IF(dump(eventDescription); VL_DBG_MSGF(" Resuming processes waiting for %s\n", eventDescription);); #endif - for (auto& susp : m_ready) susp.resume(); - m_ready.clear(); + std::swap(m_ready, m_resumeQueue); + for (VlCoroutineHandle& coro : m_resumeQueue) coro.resume(); + m_resumeQueue.clear(); commit(eventDescription); } diff --git a/include/verilated_timing.h b/include/verilated_timing.h index 019573185..14d570449 100644 --- a/include/verilated_timing.h +++ b/include/verilated_timing.h @@ -207,6 +207,10 @@ class VlTriggerScheduler final { // (not resumable) VlCoroutineVec m_ready; // Coroutines that can be resumed (all coros from m_uncommitted are // moved here in commit()) + VlCoroutineVec m_resumeQueue; // Coroutines being resumed by resume(); kept as a field to + // avoid reallocation. Resumed coroutines are moved to + // m_resumeQueue to allow adding coroutines to m_ready + // during resume(). Outside of resume() should always be empty. public: // METHODS @@ -220,8 +224,8 @@ public: void dump(const char* eventDescription) const; #endif // Used by coroutines for co_awaiting a certain trigger - auto trigger(const char* eventDescription = VL_UNKNOWN, const char* filename = VL_UNKNOWN, - int lineno = 0) { + auto trigger(bool commit, const char* eventDescription = VL_UNKNOWN, + const char* filename = VL_UNKNOWN, int lineno = 0) { VL_DEBUG_IF(VL_DBG_MSGF(" Suspending process waiting for %s at %s:%d\n", eventDescription, filename, lineno);); struct Awaitable { @@ -234,7 +238,7 @@ public: } void await_resume() const {} }; - return Awaitable{m_uncommitted, VlFileLineDebug{filename, lineno}}; + return Awaitable{commit ? m_ready : m_uncommitted, VlFileLineDebug{filename, lineno}}; } }; diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp index cc5eba6b9..e0d3e908d 100644 --- a/src/V3SchedTiming.cpp +++ b/src/V3SchedTiming.cpp @@ -166,7 +166,13 @@ TimingKit prepareTiming(AstNetlist* const netlistp) { flp, new AstVarRef{flp, schedulerp, VAccess::READWRITE}, "resume"}; resumep->dtypeSetVoid(); if (schedulerp->dtypep()->basicp()->isTriggerScheduler()) { - if (methodp->pinsp()) resumep->addPinsp(methodp->pinsp()->cloneTree(false)); + UASSERT_OBJ(methodp->pinsp(), methodp, + "Trigger method should have pins from V3Timing"); + // The first pin is the commit boolean, the rest (if any) should be debug info + // See V3Timing for details + if (AstNode* const dbginfop = methodp->pinsp()->nextp()) { + resumep->addPinsp(static_cast(dbginfop)->cloneTree(false)); + } } else if (schedulerp->dtypep()->basicp()->isDynamicTriggerScheduler()) { auto* const postp = resumep->cloneTree(false); postp->name("doPostUpdates"); diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index 184ba25d8..8f4cf323c 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -237,6 +237,9 @@ private: // to this sentree // Ast{NodeProcedure,CFunc,Begin}::user2() -> bool. Set true if process/task // is suspendable + // Ast{EventControl}::user2() -> bool. Set true if event control + // should immediately be + // committed // AstSenTree::user2() -> AstCExpr*. Debug info passed to the // timing schedulers // const VNUser1InUse m_user1InUse; (Allocated for use in SuspendableVisitor) @@ -709,6 +712,9 @@ private: flp, new AstVarRef{flp, getCreateTriggerSchedulerp(sensesp), VAccess::WRITE}, "trigger"}; triggerMethodp->dtypeSetVoid(); + // If it should be committed immediately, pass true, otherwise false + triggerMethodp->addPinsp(nodep->user2() ? new AstConst{flp, AstConst::BitTrue{}} + : new AstConst{flp, AstConst::BitFalse{}}); addEventDebugInfo(triggerMethodp, sensesp); // Create the co_await AstCAwait* const awaitp = new AstCAwait{flp, triggerMethodp, sensesp}; @@ -835,9 +841,10 @@ private: AstSenItem* const senItemsp = varRefpsToSenItemsp(condp); UASSERT_OBJ(senItemsp, nodep, "No varrefs in wait statement condition"); // Put the event control in a while loop with the wait expression as condition - auto* const loopp - = new AstWhile{flp, new AstLogNot{flp, condp}, - new AstEventControl{flp, new AstSenTree{flp, senItemsp}, nullptr}}; + AstEventControl* const controlp + = new AstEventControl{flp, new AstSenTree{flp, senItemsp}, nullptr}; + controlp->user2(true); // Commit immediately + AstWhile* const loopp = new AstWhile{flp, new AstLogNot{flp, condp}, controlp}; if (stmtsp) AstNode::addNext(loopp, stmtsp); nodep->replaceWith(loopp); } diff --git a/test_regress/t/t_lint_wait_bad.out b/test_regress/t/t_lint_wait_bad.out index 3b06a1c50..908d043be 100644 --- a/test_regress/t/t_lint_wait_bad.out +++ b/test_regress/t/t_lint_wait_bad.out @@ -1,15 +1,15 @@ -%Warning-WAITCONST: t/t_timing_wait.v:48:12: Wait statement condition is constant +%Warning-WAITCONST: t/t_timing_wait1.v:48:12: Wait statement condition is constant 48 | wait(1); | ^ ... For warning description see https://verilator.org/warn/WAITCONST?v=latest ... Use "/* verilator lint_off WAITCONST */" and lint_on around source to disable this message. -%Warning-WAITCONST: t/t_timing_wait.v:50:14: Wait statement condition is constant +%Warning-WAITCONST: t/t_timing_wait1.v:50:14: Wait statement condition is constant 50 | wait(0 < 1) $write("*-* All Finished *-*\n"); | ^ -%Warning-WAITCONST: t/t_timing_wait.v:54:17: Wait statement condition is constant +%Warning-WAITCONST: t/t_timing_wait1.v:54:17: Wait statement condition is constant 54 | initial wait(0) $stop; | ^ -%Warning-WAITCONST: t/t_timing_wait.v:55:19: Wait statement condition is constant +%Warning-WAITCONST: t/t_timing_wait1.v:55:19: Wait statement condition is constant 55 | initial wait(1 == 0) $stop; | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_wait_bad.pl b/test_regress/t/t_lint_wait_bad.pl index 7500d4750..b92ab79f3 100755 --- a/test_regress/t/t_lint_wait_bad.pl +++ b/test_regress/t/t_lint_wait_bad.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -top_filename("t/t_timing_wait.v"); +top_filename("t/t_timing_wait1.v"); lint( verilator_flags2 => ["--timing"], diff --git a/test_regress/t/t_timing_wait.pl b/test_regress/t/t_timing_wait1.pl similarity index 100% rename from test_regress/t/t_timing_wait.pl rename to test_regress/t/t_timing_wait1.pl diff --git a/test_regress/t/t_timing_wait.v b/test_regress/t/t_timing_wait1.v similarity index 100% rename from test_regress/t/t_timing_wait.v rename to test_regress/t/t_timing_wait1.v diff --git a/test_regress/t/t_timing_wait2.out b/test_regress/t/t_timing_wait2.out new file mode 100644 index 000000000..3916a7dbf --- /dev/null +++ b/test_regress/t/t_timing_wait2.out @@ -0,0 +1,4 @@ +2 +1 +0 +*-* All Finished *-* diff --git a/test_regress/t/t_timing_wait2.pl b/test_regress/t/t_timing_wait2.pl new file mode 100755 index 000000000..3860b2943 --- /dev/null +++ b/test_regress/t/t_timing_wait2.pl @@ -0,0 +1,29 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 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); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --timing --main"], + make_main => 0, + ); + + execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_wait2.v b/test_regress/t/t_timing_wait2.v new file mode 100644 index 000000000..0bb5ec6b5 --- /dev/null +++ b/test_regress/t/t_timing_wait2.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, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t; + bit s[3:0] = {0, 0, 0, 0}; + + initial begin + wait (s[1]); + s[0] = 1; + $display("0"); + end + + initial begin + wait (s[2]); + s[1] = 1; + $display("1"); + #1 $write("*-* All Finished *-*\n"); + $finish; + end + + initial begin + wait (s[3]); + s[2] = 1; + $display("2"); + end + + initial begin + s[3] = 1; + end + + initial #2 $stop; // timeout +endmodule From cfce92645f2dfa194184ed4b4e23518abb5a938a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 26 May 2023 18:01:11 -0400 Subject: [PATCH 080/129] Tests: Check equality of complex types. --- test_regress/t/t_array_type_methods.v | 5 +++++ test_regress/t/t_assoc_method.v | 5 +++++ test_regress/t/t_dynarray_method.v | 5 +++++ test_regress/t/t_queue_method.v | 5 +++++ 4 files changed, 20 insertions(+) diff --git a/test_regress/t/t_array_type_methods.v b/test_regress/t/t_array_type_methods.v index 1ee503146..ca6d5e204 100644 --- a/test_regress/t/t_array_type_methods.v +++ b/test_regress/t/t_array_type_methods.v @@ -14,6 +14,7 @@ module t (/*AUTOARG*/ input clk; logic [3:0] foo [1:0]; + logic [3:0] fooe [1:0]; initial begin foo[0] = 4'b0101; foo[1] = 4'b0011; @@ -24,6 +25,10 @@ module t (/*AUTOARG*/ `checkh(foo.sum, 4'b1000); `checkh(foo.product, 4'b1111); + fooe[0] = 4'b0101; + fooe[1] = 4'b0011; + if (foo != fooe) $stop; + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_assoc_method.v b/test_regress/t/t_assoc_method.v index e4d87f611..0bb9f707c 100644 --- a/test_regress/t/t_assoc_method.v +++ b/test_regress/t/t_assoc_method.v @@ -139,6 +139,11 @@ module t (/*AUTOARG*/); i = qe.xor(); `checkh(i, 32'b0); + q = '{10:1, 11:2}; + qe = '{10:1, 11:2}; + `checkh(q == qe, 1'b1); + `checkh(q != qe, 1'b0); + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_dynarray_method.v b/test_regress/t/t_dynarray_method.v index 3142782b5..76b56012f 100644 --- a/test_regress/t/t_dynarray_method.v +++ b/test_regress/t/t_dynarray_method.v @@ -165,6 +165,11 @@ module t (/*AUTOARG*/); `checkh(qi.size, 1); `checkh(qi[0], 2); + d = '{1, 2}; + de = '{1, 2}; + `checkh(d == de, 1'b1); + `checkh(d != de, 1'b0); + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_queue_method.v b/test_regress/t/t_queue_method.v index 24c90e470..59c4dc4a5 100644 --- a/test_regress/t/t_queue_method.v +++ b/test_regress/t/t_queue_method.v @@ -188,6 +188,11 @@ module t (/*AUTOARG*/); i = qe.xor; `checkh(i, 32'b0); + q = '{1, 2}; + qe = '{1, 2}; + `checkh(q == qe, 1'b1); + `checkh(q != qe, 1'b0); + $write("*-* All Finished *-*\n"); $finish; end From 5efe9367d2c84f2e67b6e555584650a5435021dd Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 27 May 2023 07:00:26 -0400 Subject: [PATCH 081/129] Fix SystemC signal copy macro use (#4135). --- Changes | 1 + src/V3DfgAstToDfg.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/Changes b/Changes index 1ebbc3f19..46ffccb0b 100644 --- a/Changes +++ b/Changes @@ -25,6 +25,7 @@ Verilator 5.011 devel * Fix crash on duplicate imported modules (#3231). [Robert Balas] * Fix false WIDTHEXPAND on array declarations (#3959). [JOTEGO] * Fix marking overridden methods as coroutines (#4120) (#4169). [Krzysztof Bieganski, Antmicro Ltd] +* Fix SystemC signal copy macro use (#4135). [Josep Sans] * Fix duplicate static names in blocks in functions (#4144) (#4160). [Stefan Wallentowitz] * Fix initialization order of initial static after function/task (#4159). [Kamil Rakoczy, Antmicro Ltd] * Fix linking AstRefDType if it has parameterized class ref (#4164) (#4170). [Ryszard Rozak, Antmicro Ltd] diff --git a/src/V3DfgAstToDfg.cpp b/src/V3DfgAstToDfg.cpp index 1afaaddff..78a598742 100644 --- a/src/V3DfgAstToDfg.cpp +++ b/src/V3DfgAstToDfg.cpp @@ -437,6 +437,7 @@ class AstToDfgVisitor final : public VNVisitor { void visit(AstCell* nodep) override { markReferenced(nodep); } void visit(AstNodeProcedure* nodep) override { markReferenced(nodep); } void visit(AstVar* nodep) override { + if (nodep->isSc()) return; // No need to (and in fact cannot) handle variables with unsupported dtypes if (!DfgVertex::isSupportedDType(nodep->dtypep())) return; // Mark ports as having external references From 7f12ad9d91cc49eb36a4d68c744299b383b5924c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 27 May 2023 07:15:32 -0400 Subject: [PATCH 082/129] Commentary: Changes update --- Changes | 14 +++++++++++++- docs/spelling.txt | 5 +++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Changes b/Changes index 46ffccb0b..7ae45eb62 100644 --- a/Changes +++ b/Changes @@ -18,7 +18,9 @@ Verilator 5.011 devel **Minor:** -* Support get_randstate/set_randstate class method function. +* Support inside expressions with strings and doubles (#4138) (#4139). [Krzysztof Boroński] +* Support get_randstate/set_randstate class method functions. +* Add NEWERSTD warning when using feature in newer language standard (#4168) (#4172). [Ethan Sifferman] * Add creating __inputs.vpp file with --debug (#4177). [Tudor Timi] * Optimize VPI callValueCbs (#4155). [Hennadii Chernyshchyk] * Configure for faster C++ linking using 'mold', if it is installed. @@ -33,7 +35,17 @@ Verilator 5.011 devel * Fix arrays of unpacked structs (#4173). [Risto Pejašinović] * Fix $fscanf of decimals overflowing variables (#4174). [Ahmed El-Mahmoudy] * Fix super.new missing data type (#4147). [Tudor Timi] +* Fix missing class forward declarations (#4151). [Krzysztof Boroński] +* Fix hashes of instances of parameterized classes (#4182). [Ryszard Rozak, Antmicro Ltd] +* Fix forced assignments that override non-continuous assignments (#4183) (#4192). [Krzysztof Bieganski, Antmicro Ltd] +* Fix wide structure VL_TOSTRING_W generation (#4188) (#4189). [Aylon Chaim Porat] +* Fix references to members of parameterized base classes (#4196). [Ryszard Rozak, Antmicro Ltd] +* Fix dotted references in parameterized classes (#4206). [Ryszard Rozak, Antmicro Ltd] +* Fix bit selections under parameterized classes (#4210). [Ryszard Rozak, Antmicro Ltd] * Fix duplicate std:: declaration with -I (#4215). [Harald Pretl] +* Fix deep traversal of class inheritance timing (#4216). [Krzysztof Boroński] +* Fix class parameters of enum types (#4219). [Ryszard Rozak, Antmicro Ltd] +* Fix missing assignment for wide unpacked structs (#4233). [Jiamin Zhu] * Fix detection of wire/reg duplicates. * Fix false IMPLICITSTATIC on package functions. diff --git a/docs/spelling.txt b/docs/spelling.txt index 85817af63..2dca6d079 100644 --- a/docs/spelling.txt +++ b/docs/spelling.txt @@ -260,6 +260,7 @@ Prateek Pre Preprocess Pretet +Pretl Priyadharshini Pullup Pulver @@ -472,6 +473,7 @@ constexpr constpool coredump coroutine +coroutines countbits countones cout @@ -792,6 +794,7 @@ qrq radix randc randcase +randstate rarr rdtsc reStructuredText @@ -897,6 +900,7 @@ typedefs typename uint un +unbased undef undefineall undriven @@ -967,3 +971,4 @@ ypq yurivict zdave Øyvind + From f407d442d44fe500012b8465ea2dba0adf1b9e63 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 27 May 2023 09:43:23 -0400 Subject: [PATCH 083/129] Commentary --- src/V3Branch.cpp | 6 ++++-- src/V3Delayed.cpp | 14 +++++++------- src/V3Localize.cpp | 8 ++++---- src/V3Name.cpp | 4 ++-- src/V3PairingHeap.h | 2 +- src/V3Premit.cpp | 8 ++++---- 6 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/V3Branch.cpp b/src/V3Branch.cpp index 019f442c5..e84e041b5 100644 --- a/src/V3Branch.cpp +++ b/src/V3Branch.cpp @@ -45,10 +45,12 @@ private: // AstFTask::user1() -> int. Number of references const VNUser1InUse m_inuser1; - // STATE + // STATE - across all visitors + std::vector m_cfuncsp; // List of all tasks + + // STATE - for current visit position (use VL_RESTORER) int m_likely = false; // Excuses for branch likely taken int m_unlikely = false; // Excuses for branch likely not taken - std::vector m_cfuncsp; // List of all tasks // METHODS diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index c65ad784e..760026163 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -92,6 +92,13 @@ private: const VNUser4InUse m_inuser4; const VNUser5InUse m_inuser5; + // STATE - across all visitors + std::unordered_map m_scopeVecMap; // Next var number for each scope + std::set m_timingDomains; // Timing resume domains + using VarMap = std::map, AstVar*>; + VarMap m_modVarMap; // Table of new var names created under module + VDouble0 m_statSharedSet; // Statistic tracking + // STATE - for current visit position (use VL_RESTORER) AstActive* m_activep = nullptr; // Current activate const AstCFunc* m_cfuncp = nullptr; // Current public C Function @@ -103,13 +110,6 @@ private: bool m_inSuspendableOrFork = false; // True in suspendable processes and forks bool m_ignoreBlkAndNBlk = false; // Suppress delayed assignment BLKANDNBLK - // STATE - across all visitors - std::unordered_map m_scopeVecMap; // Next var number for each scope - std::set m_timingDomains; // Timing resume domains - using VarMap = std::map, AstVar*>; - VarMap m_modVarMap; // Table of new var names created under module - VDouble0 m_statSharedSet; // Statistic tracking - // METHODS const AstNode* containingAssignment(const AstNode* nodep) { diff --git a/src/V3Localize.cpp b/src/V3Localize.cpp index a47d9d173..586e8940e 100644 --- a/src/V3Localize.cpp +++ b/src/V3Localize.cpp @@ -57,14 +57,14 @@ private: AstUser4Allocator> m_references; - // STATE - for current visit position (use VL_RESTORER) - AstCFunc* m_cfuncp = nullptr; // Current active function - uint32_t m_nodeDepth = 0; // Node depth under m_cfuncp - // STATE - across all visitors std::vector m_varScopeps; // List of variables to consider for localization VDouble0 m_statLocVars; // Statistic tracking + // STATE - for current visit position (use VL_RESTORER) + AstCFunc* m_cfuncp = nullptr; // Current active function + uint32_t m_nodeDepth = 0; // Node depth under m_cfuncp + // METHODS bool isOptimizable(AstVarScope* nodep) { return !nodep->user1() || // Not marked as not optimizable, or ... diff --git a/src/V3Name.cpp b/src/V3Name.cpp index c6b9b6c68..cf4bec4f0 100644 --- a/src/V3Name.cpp +++ b/src/V3Name.cpp @@ -42,8 +42,8 @@ private: // AstVar::user1() -> bool. Set true if already processed const VNUser1InUse m_inuser1; - // STATE - const AstNodeModule* m_modp = nullptr; + // STATE - for current visit position (use VL_RESTORER) + const AstNodeModule* m_modp = nullptr; // Current module // METHODS void rename(AstNode* nodep, bool addPvt) { diff --git a/src/V3PairingHeap.h b/src/V3PairingHeap.h index 494b6da99..9e6bc041a 100644 --- a/src/V3PairingHeap.h +++ b/src/V3PairingHeap.h @@ -26,7 +26,7 @@ // Pairing heap (max-heap) with increase key and delete. // // While this is written as a generic data structure, it's interface and -// implementation is finely tuned for it's use by V3Parm_tition, and is critical +// implementation is finely tuned for use by V3Partition, and is critical // to Verilation performance, so be very careful changing anything or adding any // new operations that would impact either memory usage, or performance of the // existing operations. This data structure is fully deterministic, meaning diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 0e1dbdd4b..2a3d09db1 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -53,6 +53,10 @@ private: const VNUser1InUse m_inuser1; const VNUser2InUse m_inuser2; + // STATE - across all visitors + V3UniqueNames m_tempNames; // For generating unique temporary variable names + VDouble0 m_extractedToConstPool; // Statistic tracking + // STATE - for current visit position (use VL_RESTORER) AstCFunc* m_cfuncp = nullptr; // Current block AstNode* m_stmtp = nullptr; // Current statement @@ -61,10 +65,6 @@ private: AstTraceInc* m_inTracep = nullptr; // Inside while loop, special statement additions bool m_assignLhs = false; // Inside assignment lhs, don't breakup extracts - // STATE - across all visitors - V3UniqueNames m_tempNames; // For generating unique temporary variable names - VDouble0 m_extractedToConstPool; // Statistic tracking - // METHODS bool assignNoTemp(AstNodeAssign* nodep) { return (VN_IS(nodep->lhsp(), VarRef) && !AstVar::scVarRecurse(nodep->lhsp()) From cf685782610a0c91323550a2c587915d546e8c41 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 27 May 2023 09:45:49 -0400 Subject: [PATCH 084/129] Internals: Cleanup V3SplitAs VL_RESTORED. No functional change intended. --- src/V3SplitAs.cpp | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/V3SplitAs.cpp b/src/V3SplitAs.cpp index f5faf37f2..c00e33d8f 100644 --- a/src/V3SplitAs.cpp +++ b/src/V3SplitAs.cpp @@ -34,23 +34,16 @@ VL_DEFINE_DEBUG_FUNCTIONS; -//###################################################################### - -class SplitAsBaseVisitor VL_NOT_FINAL : public VNVisitor { -public: - // METHODS -}; - //###################################################################### // Find all split variables in a block -class SplitAsFindVisitor final : public SplitAsBaseVisitor { +class SplitAsFindVisitor final : public VNVisitor { private: - // STATE + // STATE - across all visitors AstVarScope* m_splitVscp = nullptr; // Variable we want to split // METHODS - void visit(AstVarRef* nodep) override { + void visit(AstVarRef* nodep) { if (nodep->access().isWriteOrRW() && !m_splitVscp && nodep->varp()->attrIsolateAssign()) { m_splitVscp = nodep->varScopep(); } @@ -68,11 +61,12 @@ public: //###################################################################### // Remove nodes not containing proper references -class SplitAsCleanVisitor final : public SplitAsBaseVisitor { +class SplitAsCleanVisitor final : public VNVisitor { private: - // STATE - AstVarScope* const m_splitVscp; // Variable we want to split + // STATE - across all visitors + const AstVarScope* const m_splitVscp; // Variable we want to split const bool m_modeMatch; // Remove matching Vscp, else non-matching + // STATE - for current visit position (use VL_RESTORER) bool m_keepStmt = false; // Current Statement must be preserved bool m_matches = false; // Statement below has matching lvalue reference @@ -89,6 +83,7 @@ private: UINFO(6, " CL STMT " << nodep << endl); const bool oldKeep = m_keepStmt; { + VL_RESTORER(m_matches); m_matches = false; m_keepStmt = false; @@ -122,14 +117,15 @@ public: //###################################################################### // SplitAs class functions -class SplitAsVisitor final : public SplitAsBaseVisitor { +class SplitAsVisitor final : public VNVisitor { private: // NODE STATE // AstAlways::user() -> bool. True if already processed const VNUser1InUse m_inuser1; - // STATE + // STATE - across all visitors VDouble0 m_statSplits; // Statistic tracking + // STATE - for current visit position (use VL_RESTORER) AstVarScope* m_splitVscp = nullptr; // Variable we want to split // METHODS @@ -154,6 +150,7 @@ private: void visit(AstAlways* nodep) override { // Are there any lvalue references below this? // There could be more than one. So, we process the first one found first. + VL_RESTORER(m_splitVscp); const AstVarScope* lastSplitVscp = nullptr; while (!nodep->user1()) { // Find any splittable variables From 5573bdb219e65705fd85072d397696421f62e134 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 27 May 2023 10:43:04 -0400 Subject: [PATCH 085/129] Internals: Cleanup V3SplitAs VL_RESTORED. No functional change intended. --- src/V3SplitAs.cpp | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/V3SplitAs.cpp b/src/V3SplitAs.cpp index c00e33d8f..34b4957fa 100644 --- a/src/V3SplitAs.cpp +++ b/src/V3SplitAs.cpp @@ -43,7 +43,7 @@ private: AstVarScope* m_splitVscp = nullptr; // Variable we want to split // METHODS - void visit(AstVarRef* nodep) { + void visit(AstVarRef* nodep) override { if (nodep->access().isWriteOrRW() && !m_splitVscp && nodep->varp()->attrIsolateAssign()) { m_splitVscp = nodep->varScopep(); } @@ -125,24 +125,20 @@ private: // STATE - across all visitors VDouble0 m_statSplits; // Statistic tracking - // STATE - for current visit position (use VL_RESTORER) - AstVarScope* m_splitVscp = nullptr; // Variable we want to split // METHODS - void splitAlways(AstAlways* nodep) { - UINFO(3, "Split " << nodep << endl); - UINFO(3, " For " << m_splitVscp << endl); + void splitAlways(AstAlways* nodep, AstVarScope* splitVscp) { if (debug() >= 9) nodep->dumpTree("- in: "); // Duplicate it and link in AstAlways* const newp = nodep->cloneTree(false); newp->user1(true); // So we don't clone it again nodep->addNextHere(newp); { // Delete stuff we don't want in old - const SplitAsCleanVisitor visitor{nodep, m_splitVscp, false}; + const SplitAsCleanVisitor visitor{nodep, splitVscp, false}; if (debug() >= 9) nodep->dumpTree("- out0: "); } { // Delete stuff we don't want in new - const SplitAsCleanVisitor visitor{newp, m_splitVscp, true}; + const SplitAsCleanVisitor visitor{newp, splitVscp, true}; if (debug() >= 9) newp->dumpTree("- out1: "); } } @@ -150,21 +146,22 @@ private: void visit(AstAlways* nodep) override { // Are there any lvalue references below this? // There could be more than one. So, we process the first one found first. - VL_RESTORER(m_splitVscp); const AstVarScope* lastSplitVscp = nullptr; while (!nodep->user1()) { // Find any splittable variables const SplitAsFindVisitor visitor{nodep}; - m_splitVscp = visitor.splitVscp(); - if (m_splitVscp && m_splitVscp == lastSplitVscp) { - // We did this last time! Something's stuck! - nodep->v3fatalSrc("Infinite loop in isolate_assignments removal for: " - << m_splitVscp->prettyNameQ()); - } - lastSplitVscp = m_splitVscp; + AstVarScope* const splitVscp = visitor.splitVscp(); // Now isolate the always - if (m_splitVscp) { - splitAlways(nodep); + if (splitVscp) { + UINFO(3, "Split " << nodep << endl); + UINFO(3, " For " << splitVscp << endl); + if (splitVscp == lastSplitVscp) { + // We did this last time! Something's stuck! + nodep->v3fatalSrc("Infinite loop in isolate_assignments removal for: " + << splitVscp->prettyNameQ()); + } + lastSplitVscp = splitVscp; + splitAlways(nodep, splitVscp); ++m_statSplits; } else { nodep->user1(true); From 70b82f1aec696c52342f368cd169b74531e533b7 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 27 May 2023 11:46:25 -0400 Subject: [PATCH 086/129] Internals: V3Dead cleanups. No functional change. --- src/V3Dead.cpp | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index b0d798ab1..73b7f69a3 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -62,9 +62,10 @@ private: // TYPES using AssignMap = std::multimap; - // STATE - AstNodeModule* m_modp = nullptr; // Current module - AstSelLoopVars* m_selloopvarsp = nullptr; // Current loop vars + // STATE - across all visitors + const bool m_elimUserVars; // Allow removal of user's vars + const bool m_elimDTypes; // Allow removal of DTypes + const bool m_elimCells; // Allow removal of Cells // List of all encountered to avoid another loop through tree std::vector m_varsp; std::vector m_dtypesp; @@ -73,13 +74,13 @@ private: std::vector m_cellsp; std::vector m_classesp; std::vector m_typedefsp; - AssignMap m_assignMap; // List of all simple assignments for each variable - const bool m_elimUserVars; // Allow removal of user's vars - const bool m_elimDTypes; // Allow removal of DTypes - const bool m_elimCells; // Allow removal of Cells bool m_sideEffect = false; // Side effects discovered in assign RHS + // STATE - for current visit position (use VL_RESTORER) + AstNodeModule* m_modp = nullptr; // Current module + AstSelLoopVars* m_selloopvarsp = nullptr; // Current loop vars + // METHODS void checkAll(AstNode* nodep) { @@ -107,18 +108,16 @@ private: void visit(AstNodeModule* nodep) override { if (m_modp) m_modp->user1Inc(); // e.g. Class under Package VL_RESTORER(m_modp); - { - m_modp = nodep; - if (!nodep->dead()) { - iterateChildren(nodep); - checkAll(nodep); - if (AstClass* const classp = VN_CAST(nodep, Class)) { - if (classp->extendsp()) classp->extendsp()->user1Inc(); - if (classp->classOrPackagep()) classp->classOrPackagep()->user1Inc(); - m_classesp.push_back(classp); - // TODO we don't reclaim dead classes yet - graph implementation instead? - classp->user1Inc(); - } + m_modp = nodep; + if (!nodep->dead()) { + iterateChildren(nodep); + checkAll(nodep); + if (AstClass* const classp = VN_CAST(nodep, Class)) { + if (classp->extendsp()) classp->extendsp()->user1Inc(); + if (classp->classOrPackagep()) classp->classOrPackagep()->user1Inc(); + m_classesp.push_back(classp); + // TODO we don't reclaim dead classes yet - graph implementation instead? + classp->user1Inc(); } } } From 10696527011185040b263b1cfd925a5905578fed Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 27 May 2023 12:43:40 -0400 Subject: [PATCH 087/129] Fix some AstExprStmt handling issues, towards side effect fixes. --- src/V3Dead.cpp | 8 +++++++- src/V3EmitV.cpp | 15 +++++++++++++++ src/V3Gate.cpp | 10 ++++++++++ src/V3Simulate.h | 3 ++- src/V3Slice.cpp | 3 ++- src/V3SplitAs.cpp | 12 ++++++++++++ 6 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index 73b7f69a3..197b6658c 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -78,6 +78,7 @@ private: bool m_sideEffect = false; // Side effects discovered in assign RHS // STATE - for current visit position (use VL_RESTORER) + bool m_inAssign = false; // Currently in an assign AstNodeModule* m_modp = nullptr; // Current module AstSelLoopVars* m_selloopvarsp = nullptr; // Current loop vars @@ -281,9 +282,13 @@ private: // See if simple assignments to variables may be eliminated because // that variable is never used. // Similar code in V3Life - VL_RESTORER(m_sideEffect); + const bool assignInAssign = m_inAssign; // Might be Assign(..., ExprStmt(Assign), ...) { + VL_RESTORER(m_inAssign); + VL_RESTORER(m_sideEffect); + m_inAssign = true; m_sideEffect = false; + if (assignInAssign) m_sideEffect = true; iterateAndNextNull(nodep->rhsp()); checkAll(nodep); // Has to be direct assignment without any EXTRACTing. @@ -298,6 +303,7 @@ private: } iterateNull(nodep->timingControlp()); } + if (assignInAssign) m_sideEffect = true; // Parent assign shouldn't optimize } //----- diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 67c0a274a..8314ec15c 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -424,6 +424,12 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst { iterateAndNextConstNull(nodep->exprsp()); puts(")"); } + void visit(AstExprStmt* nodep) override { + putfs(nodep, "$_EXPRSTMT(\n"); + iterateAndNextConstNull(nodep->stmtsp()); + putbs(", "); + puts(");\n"); + } void visit(AstCMethodHard* nodep) override { iterateConst(nodep->fromp()); @@ -434,6 +440,15 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst { } puts(")"); } + void visit(AstCMethodCall* nodep) override { + iterateConst(nodep->fromp()); + puts("." + nodep->name() + "("); + for (AstNode* pinp = nodep->argsp(); pinp; pinp = pinp->nextp()) { + if (pinp != nodep->argsp()) puts(", "); + iterateConst(pinp); + } + puts(")"); + } // Operators virtual void emitVerilogFormat(AstNode* nodep, const string& format, AstNode* lhsp = nullptr, diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 09cc696d8..252a68ce4 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -333,6 +333,7 @@ private: AstActive* m_activep = nullptr; // Current active bool m_activeReducible = true; // Is activation block reducible? bool m_inSenItem = false; // Underneath AstSenItem; any varrefs are clocks + bool m_inExprStmt = false; // Underneath ExprStmt; don't optimize LHS vars bool m_inSlow = false; // Inside a slow structure std::vector m_optimized; // Logic blocks optimized @@ -498,6 +499,10 @@ private: // the weight will increase if (nodep->access().isWriteOrRW()) { new V3GraphEdge{&m_graph, m_logicVertexp, vvertexp, 1}; + if (m_inExprStmt) { + m_logicVertexp->clearReducibleAndDedupable("LHS var in ExprStmt"); + m_logicVertexp->setConsumed("LHS var in ExprStmt"); + } } if (nodep->access().isReadOrRW()) { new V3GraphEdge{&m_graph, vvertexp, m_logicVertexp, 1}; @@ -513,6 +518,11 @@ private: iterateNewStmt(nodep, "User C Function", "User C Function"); } void visit(AstClocking* nodep) override { iterateNewStmt(nodep, nullptr, nullptr); } + void visit(AstExprStmt* nodep) override { + VL_RESTORER(m_inExprStmt); + m_inExprStmt = true; + iterateChildren(nodep); + } void visit(AstSenItem* nodep) override { VL_RESTORER(m_inSenItem); m_inSenItem = true; diff --git a/src/V3Simulate.h b/src/V3Simulate.h index 1feb44580..fa28b67b8 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -886,7 +886,8 @@ private: iterateAndNextConstNull(nodep->stmtsp()); if (!optimizable()) return; iterateAndNextConstNull(nodep->resultp()); - newValue(nodep, fetchValue(nodep->resultp())); + if (!optimizable()) return; + if (!m_checkOnly) newValue(nodep, fetchValue(nodep->resultp())); } void visit(AstJumpBlock* nodep) override { diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp index 0546bff76..e4aa7407f 100644 --- a/src/V3Slice.cpp +++ b/src/V3Slice.cpp @@ -112,7 +112,8 @@ class SliceVisitor final : public VNVisitor { : offset)); newp = new AstArraySel{nodep->fileline(), snodep->fromp()->cloneTree(false), leOffset}; } else if (VN_IS(nodep, ArraySel) || VN_IS(nodep, NodeVarRef) || VN_IS(nodep, NodeSel) - || VN_IS(nodep, CMethodHard) || VN_IS(nodep, MemberSel)) { + || VN_IS(nodep, CMethodHard) || VN_IS(nodep, MemberSel) + || VN_IS(nodep, ExprStmt)) { UINFO(9, " cloneSel(" << elements << "," << offset << ") " << nodep << endl); const int leOffset = !arrayp->rangep()->ascending() ? arrayp->rangep()->elementsConst() - 1 - offset diff --git a/src/V3SplitAs.cpp b/src/V3SplitAs.cpp index 34b4957fa..24bf6f831 100644 --- a/src/V3SplitAs.cpp +++ b/src/V3SplitAs.cpp @@ -48,6 +48,12 @@ private: m_splitVscp = nodep->varScopep(); } } + void visit(AstExprStmt* nodep) override { + // A function call inside the splitting assignment + // We need to presume the whole call is preserved (if the upper statement is) + // This will break if the m_splitVscp is a "ref" argument to the function, + // but little we can do. + } void visit(AstNode* nodep) override { iterateChildren(nodep); } public: @@ -102,6 +108,12 @@ private: m_keepStmt = oldKeep || m_keepStmt; UINFO(9, " upKeep=" << m_keepStmt << " STMT " << nodep << endl); } + void visit(AstExprStmt* nodep) override { + // A function call inside the splitting assignment + // We need to presume the whole call is preserved (if the upper statement is) + // This will break if the m_splitVscp is a "ref" argument to the function, + // but little we can do. + } void visit(AstNode* nodep) override { iterateChildren(nodep); } public: From dfd3907787caba81abe510b6dfdec217334e74f4 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Mon, 29 May 2023 09:35:53 +0200 Subject: [PATCH 088/129] Mark AstMemberSel as clean (#4236) --- src/V3AstNodeExpr.h | 2 +- test_regress/t/t_struct_assign.v | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 0216bbb3e..3027259f5 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -1450,7 +1450,7 @@ public: void name(const string& name) override { m_name = name; } string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } - bool cleanOut() const override { return false; } + bool cleanOut() const override { return true; } bool same(const AstNode* samep) const override { return true; } // dtype comparison does it int instrCount() const override { return widthInstrs(); } AstVar* varp() const { return m_varp; } diff --git a/test_regress/t/t_struct_assign.v b/test_regress/t/t_struct_assign.v index c0dc33341..75939c37b 100644 --- a/test_regress/t/t_struct_assign.v +++ b/test_regress/t/t_struct_assign.v @@ -9,7 +9,12 @@ module t (/*AUTOARG*/); int fst, snd; } pair_t; + class Cls; + pair_t p; + endclass + pair_t a, b; + Cls c = new; initial begin a.fst = 1; @@ -21,6 +26,15 @@ module t (/*AUTOARG*/); $display("(%d, %d) (%d, %d)", a.fst, a.snd, b.fst, b.snd); $display("%%p=%p", a); + + c.p.fst = 5; + if (c.p.fst != 5) $stop; + a = c.p; + if (a.fst != 5) $stop; + c.p = b; + if (c.p.fst != 3) $stop; + if (c.p.snd != 4) $stop; + $write("*-* All Finished *-*\n"); $finish; end From 1c0739db10cd5aa02dd495aca1f592269b76481a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Risto=20Peja=C5=A1inovi=C4=87?= Date: Mon, 29 May 2023 18:08:39 +0200 Subject: [PATCH 089/129] Fix unpacked struct == and != operators (#4234) (#4240) --- src/V3EmitCHeaders.cpp | 23 ++++++++++++ test_regress/t/t_unpacked_struct_eq.pl | 21 +++++++++++ test_regress/t/t_unpacked_struct_eq.v | 51 ++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100755 test_regress/t/t_unpacked_struct_eq.pl create mode 100644 test_regress/t/t_unpacked_struct_eq.v diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp index 4d2a77d60..abda6f4f1 100644 --- a/src/V3EmitCHeaders.cpp +++ b/src/V3EmitCHeaders.cpp @@ -22,7 +22,9 @@ #include "V3Global.h" #include +#include #include +#include #include VL_DEFINE_DEBUG_FUNCTIONS; @@ -236,6 +238,27 @@ class EmitCHeader final : public EmitCConstInit { puts(itemp->dtypep()->cType(itemp->nameProtect(), false, false)); puts(";\n"); } + + puts("\nbool operator==(const " + EmitCBase::prefixNameProtect(sdtypep) + "& rhs){\n"); + puts("return "); + for (const AstMemberDType* itemp = sdtypep->membersp(); itemp; + itemp = VN_AS(itemp->nextp(), MemberDType)) { + if (itemp != sdtypep->membersp()) puts("\n && "); + if (AstUnpackArrayDType* const adtypep + = VN_CAST(itemp->subDTypep(), UnpackArrayDType)) { + for (uint32_t i = 0; i < adtypep->arrayUnpackedElements(); i++) { + if (i != 0) puts("\n && "); + puts(itemp->nameProtect() + "[" + std::to_string(i) + "U] == " + "rhs." + + itemp->nameProtect() + "[" + std::to_string(i) + "U]"); + } + } else { + puts(itemp->nameProtect() + " == " + "rhs." + itemp->nameProtect()); + } + } + puts(";\n"); + puts("}\n"); + puts("bool operator!=(const " + EmitCBase::prefixNameProtect(sdtypep) + "& rhs){\n"); + puts("return !(*this == rhs);\n}\n"); puts("};\n"); } void emitStructs(const AstNodeModule* modp) { diff --git a/test_regress/t/t_unpacked_struct_eq.pl b/test_regress/t/t_unpacked_struct_eq.pl new file mode 100755 index 000000000..a17622844 --- /dev/null +++ b/test_regress/t/t_unpacked_struct_eq.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2004 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_unpacked_struct_eq.v b/test_regress/t/t_unpacked_struct_eq.v new file mode 100644 index 000000000..726922e24 --- /dev/null +++ b/test_regress/t/t_unpacked_struct_eq.v @@ -0,0 +1,51 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Use this file as a template for submitting bugs, etc. +// This module takes a single clock input, and should either +// $write("*-* All Finished *-*\n"); +// $finish; +// on success, or $stop. +// +// The code as shown applies a random vector to the Test +// module, then calculates a CRC on the Test module's outputs. +// +// **If you do not wish for your code to be released to the public +// please note it here, otherwise:** +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + typedef struct { + string txt; + struct { + logic m0; + logic [3:0] m1; + } sub; + logic [7:0] arr[2]; + } struct_t; + struct_t s1; + struct_t s2; + + assign {s1.sub.m0, s1.sub.m1} = {1'b0, 4'h5}; + assign {s2.sub.m0, s2.sub.m1} = {1'b0, 4'h5}; + assign s1.txt = "text"; + assign s2.txt = "text"; + assign s1.arr[0] = 8'h77; + assign s2.arr[0] = 8'h77; + assign s1.arr[1] = 8'h33; + assign s2.arr[1] = 8'h33; + + initial begin + if(s1 != s2) begin + $fatal; + end + if(s1 == s2) begin + $write("*-* All Finished *-*\n"); + $finish; + end else begin + $fatal; + end + end +endmodule From e9135598b3bbf5dddb9295f8a4697db82e220b53 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 29 May 2023 18:51:27 -0400 Subject: [PATCH 090/129] Fix method calls on function return values. --- Changes | 1 + src/V3LinkDot.cpp | 4 ++++ test_regress/t/t_class_func_dot.pl | 21 ++++++++++++++++++++ test_regress/t/t_class_func_dot.v | 31 ++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+) create mode 100755 test_regress/t/t_class_func_dot.pl create mode 100644 test_regress/t/t_class_func_dot.v diff --git a/Changes b/Changes index 7ae45eb62..3a9fc7aba 100644 --- a/Changes +++ b/Changes @@ -48,6 +48,7 @@ Verilator 5.011 devel * Fix missing assignment for wide unpacked structs (#4233). [Jiamin Zhu] * Fix detection of wire/reg duplicates. * Fix false IMPLICITSTATIC on package functions. +* Fix method calls on function return values. Verilator 5.010 2023-04-30 diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index d6a5121f2..9a922fc2c 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -3040,6 +3040,10 @@ private: nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); return; + } else if (m_ds.m_dotp && m_ds.m_dotPos == DP_SCOPE) { + // HERE function() . method_called_on_function_return_value() + m_ds.m_dotPos = DP_MEMBER; + m_ds.m_dotText = ""; } else { checkNoDot(nodep); } diff --git a/test_regress/t/t_class_func_dot.pl b/test_regress/t/t_class_func_dot.pl new file mode 100755 index 000000000..aabcde63e --- /dev/null +++ b/test_regress/t/t_class_func_dot.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_func_dot.v b/test_regress/t/t_class_func_dot.v new file mode 100644 index 000000000..4844009a0 --- /dev/null +++ b/test_regress/t/t_class_func_dot.v @@ -0,0 +1,31 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Cls_report_object; + string m_msg; + function string get_msg; + return m_msg; + endfunction +endclass + +function Cls_report_object get_report_object; + Cls_report_object c; + c = new; + c.m_msg = "hello"; + return c; +endfunction + +module t (/*AUTOARG*/); + + string s; + + initial begin + Cls_report_object _local_report_object; + s = get_report_object().get_msg(); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From ba82d43ca18677b017579a93430940252eaf4aa5 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Tue, 30 May 2023 14:59:00 +0200 Subject: [PATCH 091/129] Support for condition operator on class objects (#4214) --- src/V3Ast.h | 1 + src/V3AstInlines.h | 4 ++ src/V3Cast.cpp | 25 ++++++++ src/V3Const.cpp | 4 +- src/V3EmitCFunc.h | 4 +- src/V3Width.cpp | 45 +++++++++++++- test_regress/t/t_class_assign_cond.pl | 21 +++++++ test_regress/t/t_class_assign_cond.v | 70 ++++++++++++++++++++++ test_regress/t/t_class_assign_cond_bad.out | 21 +++++++ test_regress/t/t_class_assign_cond_bad.pl | 19 ++++++ test_regress/t/t_class_assign_cond_bad.v | 27 +++++++++ 11 files changed, 236 insertions(+), 5 deletions(-) create mode 100755 test_regress/t/t_class_assign_cond.pl create mode 100644 test_regress/t/t_class_assign_cond.v create mode 100644 test_regress/t/t_class_assign_cond_bad.out create mode 100755 test_regress/t/t_class_assign_cond_bad.pl create mode 100644 test_regress/t/t_class_assign_cond_bad.v diff --git a/src/V3Ast.h b/src/V3Ast.h index 8dc154695..960a3c69a 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1817,6 +1817,7 @@ public: // ACCESSORS for specific types // Alas these can't be virtual or they break when passed a nullptr + inline bool isClassHandleValue() const; inline bool isZero() const; inline bool isOne() const; inline bool isNeqZero() const; diff --git a/src/V3AstInlines.h b/src/V3AstInlines.h index 9ca54f137..d2325c14b 100644 --- a/src/V3AstInlines.h +++ b/src/V3AstInlines.h @@ -41,6 +41,10 @@ bool AstNode::isString() const VL_MT_STABLE { } bool AstNode::isSigned() const VL_MT_STABLE { return dtypep() && dtypep()->isSigned(); } +bool AstNode::isClassHandleValue() const { + return (VN_IS(this, Const) && VN_AS(this, Const)->num().isNull()) + || VN_IS(dtypep(), ClassRefDType); +} bool AstNode::isZero() const { return (VN_IS(this, Const) && VN_AS(this, Const)->num().isEqZero()); } diff --git a/src/V3Cast.cpp b/src/V3Cast.cpp index 7c3d47c53..b976b5324 100644 --- a/src/V3Cast.cpp +++ b/src/V3Cast.cpp @@ -122,6 +122,31 @@ private: if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp()); if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp()); } + void visit(AstNodeCond* nodep) override { + // All class types are castable to each other. If they are of different types, + // a compilation error will be thrown, so an explicit cast is required. Types were + // already checked by V3Width and dtypep of a condition operator is a type of their + // common base class, so both classes can be safetly casted. + const AstClassRefDType* const thenClassDtypep + = VN_CAST(nodep->thenp()->dtypep(), ClassRefDType); + const AstClassRefDType* const elseClassDtypep + = VN_CAST(nodep->elsep()->dtypep(), ClassRefDType); + const bool castRequired = thenClassDtypep && elseClassDtypep + && (thenClassDtypep->classp() != elseClassDtypep->classp()); + if (castRequired) { + const AstClass* const commonBaseClassp + = VN_AS(nodep->dtypep(), ClassRefDType)->classp(); + if (thenClassDtypep->classp() != commonBaseClassp) { + AstNodeExpr* thenp = nodep->thenp()->unlinkFrBack(); + nodep->thenp(new AstCCast{thenp->fileline(), thenp, nodep}); + } + if (elseClassDtypep->classp() != commonBaseClassp) { + AstNodeExpr* elsep = nodep->elsep()->unlinkFrBack(); + nodep->elsep(new AstCCast{elsep->fileline(), elsep, nodep}); + } + } + visit(static_cast(nodep)); + } void visit(AstNodeTriop* nodep) override { iterateChildren(nodep); nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1() | nodep->thsp()->user1()); diff --git a/src/V3Const.cpp b/src/V3Const.cpp index a5413c1ec..f0656eaa5 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -3405,9 +3405,9 @@ private: TREEOPS("AstCond {$lhsp.isNeqZero}", "replaceWIteratedRhs(nodep)"); TREEOP ("AstCond{$condp.castNot, $thenp, $elsep}", "AstCond{$condp->castNot()->lhsp(), $elsep, $thenp}"); TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp.isAllOnes, $elsep}", "AstLogOr {$condp, $elsep}"); // a?1:b == a||b - TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp, $elsep.isZero}", "AstLogAnd{$condp, $thenp}"); // a?b:0 == a&&b + TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp, $elsep.isZero, !$elsep.isClassHandleValue}", "AstLogAnd{$condp, $thenp}"); // a?b:0 == a&&b TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp, $elsep.isAllOnes}", "AstLogOr {AstNot{$condp}, $thenp}"); // a?b:1 == ~a||b - TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp.isZero, $elsep}", "AstLogAnd{AstNot{$condp}, $elsep}"); // a?0:b == ~a&&b + TREEOP ("AstNodeCond{$condp.width1, $thenp.width1, $thenp.isZero, !$thenp.isClassHandleValue, $elsep}", "AstLogAnd{AstNot{$condp}, $elsep}"); // a?0:b == ~a&&b TREEOP ("AstNodeCond{!$condp.width1, operandBoolShift(nodep->condp())}", "replaceBoolShift(nodep->condp())"); // Prefer constants on left, since that often needs a shift, it lets // constant red remove the shift diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 657f1d955..165413aab 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -1044,7 +1044,9 @@ public: } void visit(AstCCast* nodep) override { // Extending a value of the same word width is just a NOP. - if (nodep->size() <= VL_IDATASIZE) { + if (const AstClassRefDType* const classDtypep = VN_CAST(nodep->dtypep(), ClassRefDType)) { + puts("(" + classDtypep->cType("", false, false) + ")("); + } else if (nodep->size() <= VL_IDATASIZE) { puts("(IData)("); } else { puts("(QData)("); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 241e886da..95f3c3915 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -503,9 +503,26 @@ private: // the size of this subexpression only. // Second call (final()) m_vup->width() is probably the expression size, so // the expression includes the size of the output too. - if (nodep->thenp()->dtypep()->skipRefp() == nodep->elsep()->dtypep()->skipRefp()) { + const AstNodeDType* const thenDTypep = nodep->thenp()->dtypep(); + const AstNodeDType* const elseDTypep = nodep->elsep()->dtypep(); + if (thenDTypep->skipRefp() == elseDTypep->skipRefp()) { // TODO might need a broader equation, use the Castable function? - nodep->dtypeFrom(nodep->thenp()->dtypep()); + nodep->dtypeFrom(thenDTypep); + } else if (nodep->thenp()->isClassHandleValue() + || nodep->elsep()->isClassHandleValue()) { + AstNodeDType* commonClassTypep = nullptr; + if (nodep->thenp()->isClassHandleValue() && nodep->elsep()->isClassHandleValue()) { + // Get the most-deriving class type that both arguments can be casted to. + commonClassTypep = getCommonClassTypep(nodep->thenp(), nodep->elsep()); + } + if (commonClassTypep) { + nodep->dtypep(commonClassTypep); + } else { + nodep->v3error("Incompatible types of operands of condition operator: " + << thenDTypep->prettyTypeName() << " and " + << elseDTypep->prettyTypeName()); + nodep->dtypeFrom(thenDTypep); + } } else if (nodep->thenp()->isDouble() || nodep->elsep()->isDouble()) { nodep->dtypeSetDouble(); } else if (nodep->thenp()->isString() || nodep->elsep()->isString()) { @@ -7309,6 +7326,30 @@ private: if (nodep->subDTypep()) return hasOpenArrayIterateDType(nodep->subDTypep()->skipRefp()); return false; } + AstNodeDType* getCommonClassTypep(AstNode* nodep1, AstNode* nodep2) { + // Return the class type that both nodep1 and nodep2 are castable to. + // If both are null, return the type of null constant. + // If one is a class and one is null, return AstClassRefDType that points to that class. + // If no common class type exists, return nullptr. + + // First handle cases with null values and when one class is a super class of the other. + if (VN_IS(nodep1, Const)) std::swap(nodep1, nodep2); + const Castable castable = computeCastable(nodep1->dtypep(), nodep2->dtypep(), nodep2); + if (castable == SAMEISH || castable == COMPATIBLE) { + return nodep1->dtypep()->cloneTree(false); + } else if (castable == DYNAMIC_CLASS) { + return nodep2->dtypep()->cloneTree(false); + } + + AstClassRefDType* classDtypep1 = VN_CAST(nodep1->dtypep(), ClassRefDType); + while (classDtypep1) { + const Castable castable = computeCastable(classDtypep1, nodep2->dtypep(), nodep2); + if (castable == COMPATIBLE) return classDtypep1->cloneTree(false); + AstClassExtends* const extendsp = classDtypep1->classp()->extendsp(); + classDtypep1 = extendsp ? VN_AS(extendsp->dtypep(), ClassRefDType) : nullptr; + } + return nullptr; + } //---------------------------------------------------------------------- // METHODS - casting diff --git a/test_regress/t/t_class_assign_cond.pl b/test_regress/t/t_class_assign_cond.pl new file mode 100755 index 000000000..1aa73f80a --- /dev/null +++ b/test_regress/t/t_class_assign_cond.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 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_assign_cond.v b/test_regress/t/t_class_assign_cond.v new file mode 100644 index 000000000..4d78e3a68 --- /dev/null +++ b/test_regress/t/t_class_assign_cond.v @@ -0,0 +1,70 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Cls; + int f; + function new(int x); + f = x; + endfunction +endclass + +class ExtendCls extends Cls; + function new(int x); + super.new(x); + endfunction +endclass + +class AnotherExtendCls extends Cls; + function new(int x); + super.new(x); + endfunction +endclass + +class ExtendExtendCls extends ExtendCls; + function new(int x); + super.new(x); + endfunction +endclass + +module t (/*AUTOARG*/); + initial begin + Cls cls1 = null, cls2 = null; + ExtendCls ext_cls = null; + AnotherExtendCls an_ext_cls = null; + ExtendExtendCls ext_ext_cls = null; + + cls1 = (cls1 == null) ? cls2 : cls1; + if (cls1 != null) $stop; + + cls1 = new(1); + cls1 = (cls1 == null) ? cls2 : cls1; + if (cls1.f != 1) $stop; + + cls1 = (cls1 != null) ? cls2 : cls1; + if (cls1 != null) $stop; + + cls1 = new(1); + cls2 = new(2); + cls1 = (cls1 != null) ? cls2 : cls1; + if (cls1.f != 2) $stop; + + cls1 = null; + cls1 = (ext_cls != null) ? ext_cls : cls2; + if (cls1.f != 2) $stop; + + ext_cls = new(3); + cls1 = (ext_cls != null) ? ext_cls : cls2; + if (cls1.f != 3) $stop; + + ext_ext_cls = new(4); + an_ext_cls = new(5); + cls1 = (ext_ext_cls.f != 4) ? ext_ext_cls : an_ext_cls; + if (cls1.f != 5) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_assign_cond_bad.out b/test_regress/t/t_class_assign_cond_bad.out new file mode 100644 index 000000000..d0d347f17 --- /dev/null +++ b/test_regress/t/t_class_assign_cond_bad.out @@ -0,0 +1,21 @@ +%Error: t/t_class_assign_cond_bad.v:22:25: Incompatible types of operands of condition operator: CLASSREFDTYPE 'Cls1' and CLASSREFDTYPE 'Cls2' + : ... In instance t + 22 | c1 = (c1 != null) ? c1 : c2; + | ^ +%Error: t/t_class_assign_cond_bad.v:23:10: Assign RHS expects a CLASSREFDTYPE 'Cls1', got CLASSREFDTYPE 'Cls2' + : ... In instance t + 23 | c1 = (c1 != null) ? c2 : c2; + | ^ +%Error: t/t_class_assign_cond_bad.v:24:25: Incompatible types of operands of condition operator: BASICDTYPE 'logic' and CLASSREFDTYPE 'Cls2' + : ... In instance t + 24 | c2 = (c1 == null) ? 1'b1 : c2; + | ^ +%Error: t/t_class_assign_cond_bad.v:24:10: Assign RHS expects a CLASSREFDTYPE 'Cls2', got BASICDTYPE 'logic' + : ... In instance t + 24 | c2 = (c1 == null) ? 1'b1 : c2; + | ^ +%Error: t/t_class_assign_cond_bad.v:25:29: Incompatible types of operands of condition operator: CLASSREFDTYPE 'ExtCls1' and CLASSREFDTYPE 'Cls1' + : ... In instance t + 25 | ext_c1 = (c1 == null) ? ext_c1 : c1; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_class_assign_cond_bad.pl b/test_regress/t/t_class_assign_cond_bad.pl new file mode 100755 index 000000000..430290c0a --- /dev/null +++ b/test_regress/t/t_class_assign_cond_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 Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_assign_cond_bad.v b/test_regress/t/t_class_assign_cond_bad.v new file mode 100644 index 000000000..a016c832d --- /dev/null +++ b/test_regress/t/t_class_assign_cond_bad.v @@ -0,0 +1,27 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Cls1; +endclass + +class Cls2; +endclass + +class ExtCls1; +endclass + +module t (/*AUTOARG*/); + Cls1 c1; + Cls2 c2; + ExtCls1 ext_c1; + + initial begin + c1 = (c1 != null) ? c1 : c2; + c1 = (c1 != null) ? c2 : c2; + c2 = (c1 == null) ? 1'b1 : c2; + ext_c1 = (c1 == null) ? ext_c1 : c1; + end +endmodule From 77502aeb9733e58216cd66db88ff498f53cee54b Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Tue, 30 May 2023 15:00:10 +0200 Subject: [PATCH 092/129] Add warning that timing controls in DPI exports are unsupported (#4238) Signed-off-by: Krzysztof Bieganski --- src/V3Timing.cpp | 30 ++++++++++++------- test_regress/t/t_timing_dpi.pl | 28 ----------------- ..._timing_dpi.cpp => t_timing_dpi_unsup.cpp} | 0 test_regress/t/t_timing_dpi_unsup.out | 5 ++++ test_regress/t/t_timing_dpi_unsup.pl | 22 ++++++++++++++ .../{t_timing_dpi.v => t_timing_dpi_unsup.v} | 10 +++---- 6 files changed, 51 insertions(+), 44 deletions(-) delete mode 100755 test_regress/t/t_timing_dpi.pl rename test_regress/t/{t_timing_dpi.cpp => t_timing_dpi_unsup.cpp} (100%) create mode 100644 test_regress/t/t_timing_dpi_unsup.out create mode 100755 test_regress/t/t_timing_dpi_unsup.pl rename test_regress/t/{t_timing_dpi.v => t_timing_dpi_unsup.v} (79%) diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index 8f4cf323c..6772f95f0 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -568,17 +568,25 @@ private: } void visit(AstCFunc* nodep) override { iterateChildren(nodep); - if (nodep->user2()) { - nodep->rtnType("VlCoroutine"); - // If in a class, create a shared pointer to 'this' - if (m_classp) nodep->addInitsp(new AstCStmt{nodep->fileline(), "VL_KEEP_THIS;\n"}); - if (!nodep->exists([](AstCAwait*) { return true; })) { - // It's a coroutine but has no awaits (a class method that overrides/is - // overridden by a suspendable, but doesn't have any awaits itself). Add a - // co_return at the end (either that or a co_await is required in a - // coroutine) - nodep->addStmtsp(new AstCStmt{nodep->fileline(), "co_return;\n"}); - } + if (!nodep->user2()) return; + nodep->rtnType("VlCoroutine"); + // If in a class, create a shared pointer to 'this' + if (m_classp) nodep->addInitsp(new AstCStmt{nodep->fileline(), "VL_KEEP_THIS;\n"}); + AstNode* firstCoStmtp = nullptr; // First co_* statement in the function + nodep->exists([&](AstCAwait* const awaitp) -> bool { return (firstCoStmtp = awaitp); }); + if (!firstCoStmtp) { + // It's a coroutine but has no awaits (a class method that overrides/is + // overridden by a suspendable, but doesn't have any awaits itself). Add a + // co_return at the end (either that or a co_await is required in a + // coroutine) + firstCoStmtp = new AstCStmt{nodep->fileline(), "co_return;\n"}; + nodep->addStmtsp(firstCoStmtp); + } + if (nodep->dpiExportImpl()) { + // A DPI-exported coroutine won't be able to block the calling code + // Error on the await node; fall back to the function node + firstCoStmtp->v3warn(E_UNSUPPORTED, + "Unsupported: Timing controls inside DPI-exported tasks"); } } void visit(AstNodeCCall* nodep) override { diff --git a/test_regress/t/t_timing_dpi.pl b/test_regress/t/t_timing_dpi.pl deleted file mode 100755 index 2c494cced..000000000 --- a/test_regress/t/t_timing_dpi.pl +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env perl -if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } -# DESCRIPTION: Verilator: Verilog Test driver/expect definition -# -# This file ONLY is placed under the Creative Commons Public Domain, for -# any use, without warranty, 2023 by Toru Niina. -# SPDX-License-Identifier: CC0-1.0 - - -scenarios(vlt => 1); - -if (!$Self->have_coroutines) { - skip("No coroutine support") -} -else { - compile( - v_flags2 => ["t/t_timing_dpi.cpp"], - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); - - execute( - check_finished => 1, - ); -} - -ok(1); -1 diff --git a/test_regress/t/t_timing_dpi.cpp b/test_regress/t/t_timing_dpi_unsup.cpp similarity index 100% rename from test_regress/t/t_timing_dpi.cpp rename to test_regress/t/t_timing_dpi_unsup.cpp diff --git a/test_regress/t/t_timing_dpi_unsup.out b/test_regress/t/t_timing_dpi_unsup.out new file mode 100644 index 000000000..c4cc70ed0 --- /dev/null +++ b/test_regress/t/t_timing_dpi_unsup.out @@ -0,0 +1,5 @@ +%Error-UNSUPPORTED: t/t_timing_dpi_unsup.v:28:19: Unsupported: Timing controls inside DPI-exported tasks + 28 | repeat(n) @(negedge clk); + | ^ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_timing_dpi_unsup.pl b/test_regress/t/t_timing_dpi_unsup.pl new file mode 100755 index 000000000..a6399f3f7 --- /dev/null +++ b/test_regress/t/t_timing_dpi_unsup.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 2023 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); + +top_filename("t/t_timing_dpi_unsup.v"); + +lint( + verilator_flags2 => ["--timing"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_timing_dpi.v b/test_regress/t/t_timing_dpi_unsup.v similarity index 79% rename from test_regress/t/t_timing_dpi.v rename to test_regress/t/t_timing_dpi_unsup.v index 63d3bd43d..996ef1e39 100644 --- a/test_regress/t/t_timing_dpi.v +++ b/test_regress/t/t_timing_dpi_unsup.v @@ -24,19 +24,19 @@ module t; export "DPI-C" task tb_sv_wait; task automatic tb_sv_wait(input int n); - `WRITE_VERBOSE("tb_sv_wait start..."); + `WRITE_VERBOSE("tb_sv_wait start...\n"); repeat(n) @(negedge clk); - `WRITE_VERBOSE("tb_sv_wait done!"); + `WRITE_VERBOSE("tb_sv_wait done!\n"); endtask always #halfcycle clk = ~clk; initial begin - `WRITE_VERBOSE("test start"); + `WRITE_VERBOSE("test start\n"); repeat(10) @(posedge clk); - `WRITE_VERBOSE("calling tb_c_wait..."); + `WRITE_VERBOSE("calling tb_c_wait...\n"); tb_c_wait(); - `WRITE_VERBOSE("tb_c_wait finish"); + `WRITE_VERBOSE("tb_c_wait finish\n"); repeat(10) @(posedge clk); $write("*-* All Finished *-*\n"); $finish; From 4f1f487ae4ea0811883e78d287941a4d8abbad19 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Tue, 30 May 2023 15:02:59 +0200 Subject: [PATCH 093/129] Fix function calls in with statements (#4245) --- src/V3AstNodeExpr.h | 4 +-- src/V3Clean.cpp | 6 +++- src/V3EmitCFunc.h | 5 ++- src/V3Task.cpp | 9 +++++ test_regress/t/t_array_query_with.v | 52 ++++++++++++++++++++--------- 5 files changed, 55 insertions(+), 21 deletions(-) diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 3027259f5..3ccd63be5 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -2122,14 +2122,14 @@ class AstWith final : public AstNodeExpr { // Children: expression (equation establishing the with) // @astgen op1 := indexArgRefp : AstLambdaArgRef // @astgen op2 := valueArgRefp : AstLambdaArgRef - // @astgen op3 := exprp : AstNodeExpr + // @astgen op3 := exprp : List[AstNode] public: AstWith(FileLine* fl, AstLambdaArgRef* indexArgRefp, AstLambdaArgRef* valueArgRefp, AstNodeExpr* exprp) : ASTGEN_SUPER_With(fl) { this->indexArgRefp(indexArgRefp); this->valueArgRefp(valueArgRefp); - this->exprp(exprp); + this->addExprp(exprp); } ASTGEN_MEMBERS_AstWith; bool same(const AstNode* /*samep*/) const override { return true; } diff --git a/src/V3Clean.cpp b/src/V3Clean.cpp index 218517aa0..303480fd2 100644 --- a/src/V3Clean.cpp +++ b/src/V3Clean.cpp @@ -298,7 +298,11 @@ private: } void visit(AstWith* nodep) override { iterateChildren(nodep); - ensureCleanAndNext(nodep->exprp()); + setClean(nodep, true); + } + void visit(AstCReturn* nodep) override { + iterateChildren(nodep); + ensureClean(nodep->lhsp()); setClean(nodep, true); } void visit(AstIntfRef* nodep) override { diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 165413aab..3a4f0c683 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -476,10 +476,9 @@ public: if (auto* const argrefp = nodep->valueArgRefp()) { putbs(argrefp->dtypep()->cType(argrefp->nameProtect(), false, false)); } - // Probably fragile, V3Task may need to convert to a AstCReturn - puts(") { return "); + puts(") {\n"); iterateAndNextConstNull(nodep->exprp()); - puts("; }\n"); + puts("}\n"); } void visit(AstNodeCase* nodep) override { // LCOV_EXCL_LINE // In V3Case... diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 9bc068a19..95691ce4f 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -1371,6 +1371,15 @@ private: iterateChildren(nodep); } } + void visit(AstWith* nodep) override { + if (nodep->user1SetOnce()) { + // Make sure that the return expression is converted only once + return; + } + AstNodeExpr* const withExprp = VN_AS(nodep->exprp()->unlinkFrBack(), NodeExpr); + nodep->addExprp(new AstCReturn{withExprp->fileline(), withExprp}); + iterateChildren(nodep); + } void visit(AstScope* nodep) override { m_scopep = nodep; m_insStmtp = nullptr; diff --git a/test_regress/t/t_array_query_with.v b/test_regress/t/t_array_query_with.v index bb4fa6137..d69ddfa42 100644 --- a/test_regress/t/t_array_query_with.v +++ b/test_regress/t/t_array_query_with.v @@ -4,11 +4,24 @@ // any use, without warranty, 2022 by Antmicro Ltd. // SPDX-License-Identifier: CC0-1.0 -module t (/*AUTOARG*/ - clk - ); +class Cls; + static function bit get_true(); + return 1'b1; + endfunction - input clk; + static function bit test_find_index_in_class(); + if (get_true) begin + int q[$] = {0, -1, 3, 1, 4, 1}; + int found_idx[$]; + found_idx = q.find_index(node) with (node == 1); + return found_idx[0] == 3; + end + return 0; + endfunction +endclass + +module t (/*AUTOARG*/ + ); function bit test_find; string bar[$]; @@ -31,22 +44,31 @@ module t (/*AUTOARG*/ return first_even_idx[0] == 1; endfunction + function bit is_even(int a); + return a % 2 == 0; + endfunction + + function static bit test_find_first_index_by_func; + int q[] = {1, 2, 3, 4, 5, 6}; + int first_even_idx[$] = q.find_first_index(x) with (is_even(x)); + return first_even_idx[0] == 1; + endfunction + function automatic bit test_sort; int q[] = {-5, 2, -3, 0, 4}; q.sort(x) with (x >= 0 ? x : -x); return q[1] == 2; endfunction - always @(posedge clk) begin - bit [3:0] results = {test_find(), test_find_index(), - test_find_first_index(), test_sort()}; - if (results == '1) begin - $write("*-* All Finished *-*\n"); - $finish; - end - else begin - $write("Results: %b\n", results); - $stop; - end + initial begin + if (!test_find()) $stop; + if (!test_find_index()) $stop; + if (!test_find_first_index()) $stop; + if (!test_find_first_index_by_func()) $stop; + if (!test_sort()) $stop; + if (!Cls::test_find_index_in_class()) $stop; + + $write("*-* All Finished *-*\n"); + $finish; end endmodule From 338acabe2b54432b447ec06e326911f3ecf2c36a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Risto=20Peja=C5=A1inovi=C4=87?= Date: Wed, 31 May 2023 05:44:48 +0200 Subject: [PATCH 094/129] Fix AstStructSel clean when data type is structure (#4241) (#4244) --- src/V3Clean.cpp | 5 +++++ test_regress/t/t_unpacked_struct_eq.v | 5 ++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/V3Clean.cpp b/src/V3Clean.cpp index 303480fd2..f69d0e153 100644 --- a/src/V3Clean.cpp +++ b/src/V3Clean.cpp @@ -234,6 +234,11 @@ private: operandTriop(nodep); setClean(nodep, nodep->cleanOut()); } + void visit(AstStructSel* nodep) override { + iterateChildren(nodep); + AstStructDType* dtypep = VN_CAST(nodep->dtypep()->skipRefp(), StructDType); + setClean(nodep, dtypep && !dtypep->packed()); + } void visit(AstUCFunc* nodep) override { iterateChildren(nodep); computeCppWidth(nodep); diff --git a/test_regress/t/t_unpacked_struct_eq.v b/test_regress/t/t_unpacked_struct_eq.v index 726922e24..5757cae2e 100644 --- a/test_regress/t/t_unpacked_struct_eq.v +++ b/test_regress/t/t_unpacked_struct_eq.v @@ -38,9 +38,8 @@ module t; assign s2.arr[1] = 8'h33; initial begin - if(s1 != s2) begin - $fatal; - end + if(s1 != s2) $stop; + if(s1.sub != s2.sub) $stop; if(s1 == s2) begin $write("*-* All Finished *-*\n"); $finish; From 7f471d862e47895303378b94807021a074b49ad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Risto=20Peja=C5=A1inovi=C4=87?= Date: Wed, 31 May 2023 14:34:34 +0200 Subject: [PATCH 095/129] Fix operator == for unpacked struct, if elements are VlUnpacked arrays (#4247) --- include/verilated_types.h | 3 +++ src/V3EmitCHeaders.cpp | 18 +++++---------- test_regress/t/t_unpacked_struct_eq.v | 33 ++++++++++++++++++++------- 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/include/verilated_types.h b/include/verilated_types.h index 39e487bb7..494af9be8 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -1066,6 +1066,9 @@ struct VlUnpacked final { // Similar to 'neq' above, *this = that used for change detection void assign(const VlUnpacked& that) { *this = that; } + bool operator==(const VlUnpacked& that) const { return !neq(that); } + bool operator!=(const VlUnpacked& that) { return neq(that); } + // Dumping. Verilog: str = $sformatf("%p", assoc) std::string to_string() const { std::string out = "'{"; diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp index abda6f4f1..04e38e172 100644 --- a/src/V3EmitCHeaders.cpp +++ b/src/V3EmitCHeaders.cpp @@ -17,6 +17,7 @@ #include "config_build.h" #include "verilatedos.h" +#include "V3Ast.h" #include "V3EmitC.h" #include "V3EmitCConstInit.h" #include "V3Global.h" @@ -239,25 +240,18 @@ class EmitCHeader final : public EmitCConstInit { puts(";\n"); } - puts("\nbool operator==(const " + EmitCBase::prefixNameProtect(sdtypep) + "& rhs){\n"); + puts("\nbool operator==(const " + EmitCBase::prefixNameProtect(sdtypep) + + "& rhs) const {\n"); puts("return "); for (const AstMemberDType* itemp = sdtypep->membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) { if (itemp != sdtypep->membersp()) puts("\n && "); - if (AstUnpackArrayDType* const adtypep - = VN_CAST(itemp->subDTypep(), UnpackArrayDType)) { - for (uint32_t i = 0; i < adtypep->arrayUnpackedElements(); i++) { - if (i != 0) puts("\n && "); - puts(itemp->nameProtect() + "[" + std::to_string(i) + "U] == " + "rhs." - + itemp->nameProtect() + "[" + std::to_string(i) + "U]"); - } - } else { - puts(itemp->nameProtect() + " == " + "rhs." + itemp->nameProtect()); - } + puts(itemp->nameProtect() + " == " + "rhs." + itemp->nameProtect()); } puts(";\n"); puts("}\n"); - puts("bool operator!=(const " + EmitCBase::prefixNameProtect(sdtypep) + "& rhs){\n"); + puts("bool operator!=(const " + EmitCBase::prefixNameProtect(sdtypep) + + "& rhs) const {\n"); puts("return !(*this == rhs);\n}\n"); puts("};\n"); } diff --git a/test_regress/t/t_unpacked_struct_eq.v b/test_regress/t/t_unpacked_struct_eq.v index 5757cae2e..384f10801 100644 --- a/test_regress/t/t_unpacked_struct_eq.v +++ b/test_regress/t/t_unpacked_struct_eq.v @@ -17,30 +17,47 @@ // SPDX-License-Identifier: CC0-1.0 module t; + typedef struct{ + logic [31:0] subarr[4]; + } arr_str_t; typedef struct { string txt; struct { logic m0; logic [3:0] m1; + logic [7:0] arr[2][3]; + arr_str_t str[5]; } sub; - logic [7:0] arr[2]; } struct_t; struct_t s1; struct_t s2; + struct_t s3; assign {s1.sub.m0, s1.sub.m1} = {1'b0, 4'h5}; assign {s2.sub.m0, s2.sub.m1} = {1'b0, 4'h5}; assign s1.txt = "text"; assign s2.txt = "text"; - assign s1.arr[0] = 8'h77; - assign s2.arr[0] = 8'h77; - assign s1.arr[1] = 8'h33; - assign s2.arr[1] = 8'h33; + + assign {s1.sub.arr[0][0], s2.sub.arr[0][0]} = {8'h01, 8'h01}; + assign {s1.sub.arr[0][1], s2.sub.arr[0][1]} = {8'h02, 8'h02}; + assign {s1.sub.arr[0][2], s2.sub.arr[0][2]} = {8'h03, 8'h03}; + assign {s1.sub.arr[1][0], s2.sub.arr[1][0]} = {8'h04, 8'h04}; + assign {s1.sub.arr[1][1], s2.sub.arr[1][1]} = {8'h05, 8'h05}; + assign {s1.sub.arr[1][2], s2.sub.arr[1][2]} = {8'h06, 8'h06}; + + assign {s3.sub.m0, s3.sub.m1} = {1'b0, 4'h5}; + assign s3.txt = "text"; + + assign s3.sub.arr[0][0] = 8'h01; + assign s3.sub.arr[0][1] = 8'h02; + assign s3.sub.arr[0][2] = 8'h03; + assign s3.sub.arr[1][0] = 8'h24; // One mismatch + assign s3.sub.arr[1][1] = 8'h05; + assign s3.sub.arr[1][2] = 8'h06; initial begin - if(s1 != s2) $stop; - if(s1.sub != s2.sub) $stop; - if(s1 == s2) begin + if(s3 == s1) $stop; + if(s1 == s2 && s3 != s1) begin $write("*-* All Finished *-*\n"); $finish; end else begin From df2746de7174b38fba5e6a1e653243a725c72d87 Mon Sep 17 00:00:00 2001 From: Don Williamson Date: Wed, 31 May 2023 17:02:26 +0100 Subject: [PATCH 096/129] Add --main-top-name option for C main TOP name (#4235) (#4249) --- bin/verilator | 1 + docs/CONTRIBUTORS | 1 + docs/guide/exe_verilator.rst | 7 +++++ src/V3EmitCMain.cpp | 10 ++++++- src/V3Options.cpp | 1 + src/V3Options.h | 2 ++ test_regress/t/t_flag_main_top_name.pl | 28 ++++++++++++++++++++ test_regress/t/t_flag_main_top_name.v | 22 +++++++++++++++ test_regress/t/t_flag_main_top_name_empty.pl | 28 ++++++++++++++++++++ 9 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 test_regress/t/t_flag_main_top_name.pl create mode 100644 test_regress/t/t_flag_main_top_name.v create mode 100644 test_regress/t/t_flag_main_top_name_empty.pl diff --git a/bin/verilator b/bin/verilator index 5bab12f33..65acaf2f8 100755 --- a/bin/verilator +++ b/bin/verilator @@ -372,6 +372,7 @@ detailed descriptions of these arguments. --make Generate scripts for specified build tool -MAKEFLAGS Arguments to pass to make during --build --main Generate C++ main() file + --main-top-name Specify top name passed to Verilated model in generated C++ main --max-num-width Maximum number width (default: 64K) --Mdir Name of output object directory --MMD Create .d dependency files diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index ba86f3b4d..d82c05948 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -25,6 +25,7 @@ David Horton David Metz David Stanford David Turner +Don Williamson Drew Ranck Drew Taussig Driss Hafdi diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index 5bc6c0474..a4d0af876 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -808,6 +808,13 @@ Summary: See also :vlopt:`--binary`. +.. option:: --main-top-name + + Specify the name passed to the Verilated model being constructed, in the + generated C++ main() function. + + If the string ``"-"`` is used, no top level scope is added. + .. option:: --max-num-width Set the maximum number literal width (e.g., in 1024'd22 this diff --git a/src/V3EmitCMain.cpp b/src/V3EmitCMain.cpp index 10216025b..3ea952903 100644 --- a/src/V3EmitCMain.cpp +++ b/src/V3EmitCMain.cpp @@ -51,6 +51,14 @@ private: // Not defining main_time/vl_time_stamp, so v3Global.opt.addCFlags("-DVL_TIME_CONTEXT"); // On MSVC++ anyways + // Optional main top name argument, with empty string replacement + string topArg; + string topName = v3Global.opt.mainTopName(); + if (!topName.empty()) { + if (topName == "-") topName = ""; + topArg = ", \"" + topName + "\""; + } + // Heavily commented output, as users are likely to look at or copy this code ofp()->putsHeader(); puts("// DESCRIPTION: main() calling loop, created with Verilator --main\n"); @@ -71,7 +79,7 @@ private: puts("// Construct the Verilated model, from Vtop.h generated from Verilating\n"); puts("const std::unique_ptr<" + topClassName() + "> topp{new " + topClassName() - + "{contextp.get()}};\n"); + + "{contextp.get()" + topArg + "}};\n"); puts("\n"); puts("// Simulate until $finish\n"); diff --git a/src/V3Options.cpp b/src/V3Options.cpp index d6d3fec8e..219c8e30c 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -1279,6 +1279,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-l2-name", Set, &m_l2Name); DECL_OPTION("-no-l2name", CbCall, [this]() { m_l2Name = ""; }).undocumented(); // Historical DECL_OPTION("-l2name", CbCall, [this]() { m_l2Name = "v"; }).undocumented(); // Historical + DECL_OPTION("-main-top-name", Set, &m_mainTopName); DECL_OPTION("-MAKEFLAGS", CbVal, callStrSetter(&V3Options::addMakeFlags)); DECL_OPTION("-MMD", OnOff, &m_makeDepend); diff --git a/src/V3Options.h b/src/V3Options.h index 7e6b639b3..fea00aaf8 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -330,6 +330,7 @@ private: string m_flags; // main switch: -f {name} string m_l2Name; // main switch: --l2name; "" for top-module's name string m_libCreate; // main switch: --lib-create {lib_name} + string m_mainTopName; // main switch: --main-top-name string m_makeDir; // main switch: -Mdir string m_modPrefix; // main switch: --mod-prefix string m_pipeFilter; // main switch: --pipe-filter @@ -567,6 +568,7 @@ public: } return libName; } + string mainTopName() const { return m_mainTopName; } string makeDir() const VL_MT_SAFE { return m_makeDir; } string modPrefix() const VL_MT_SAFE { return m_modPrefix; } string pipeFilter() const { return m_pipeFilter; } diff --git a/test_regress/t/t_flag_main_top_name.pl b/test_regress/t/t_flag_main_top_name.pl new file mode 100644 index 000000000..876acdd1c --- /dev/null +++ b/test_regress/t/t_flag_main_top_name.pl @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Don Williamson and 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); + +top_filename("t/t_flag_main_top_name.v"); + +compile( + verilator_flags => ["-Mdir $Self->{obj_dir}", "--exe", "--build", "--main"], + verilator_flags2 => ["--top-module top", "--main-top-name ALTOP"], + verilator_make_cmake => 0, + verilator_make_gmake => 0, + make_main => 0, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_flag_main_top_name.v b/test_regress/t/t_flag_main_top_name.v new file mode 100644 index 000000000..ced845c9a --- /dev/null +++ b/test_regress/t/t_flag_main_top_name.v @@ -0,0 +1,22 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2023 by Don Williamson and Wilson Snyder. This program is free software; you +// can redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +module top; + string scope; + initial begin + scope = $sformatf("%m"); + $write("[%0t] In %s\n", $time, scope); + `ifdef MAIN_TOP_NAME_EMPTY + if (scope != "top") $stop; + `else + if (scope != "ALTOP.top") $stop; + `endif + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_flag_main_top_name_empty.pl b/test_regress/t/t_flag_main_top_name_empty.pl new file mode 100644 index 000000000..bd3cc906f --- /dev/null +++ b/test_regress/t/t_flag_main_top_name_empty.pl @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Don Williamson and 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); + +top_filename("t/t_flag_main_top_name.v"); + +compile( + verilator_flags => ["-Mdir $Self->{obj_dir}", "--exe", "--build", "--main"], + verilator_flags2 => ["--top-module top", "--main-top-name -", "-DMAIN_TOP_NAME_EMPTY"], + verilator_make_cmake => 0, + verilator_make_gmake => 0, + make_main => 0, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; From 205cae963b86b82e23057f7f2188ca667aee87b3 Mon Sep 17 00:00:00 2001 From: github action Date: Wed, 31 May 2023 16:03:33 +0000 Subject: [PATCH 097/129] Apply 'make format' --- test_regress/t/t_flag_main_top_name.pl | 0 test_regress/t/t_flag_main_top_name_empty.pl | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 test_regress/t/t_flag_main_top_name.pl mode change 100644 => 100755 test_regress/t/t_flag_main_top_name_empty.pl diff --git a/test_regress/t/t_flag_main_top_name.pl b/test_regress/t/t_flag_main_top_name.pl old mode 100644 new mode 100755 diff --git a/test_regress/t/t_flag_main_top_name_empty.pl b/test_regress/t/t_flag_main_top_name_empty.pl old mode 100644 new mode 100755 From 15f8ebc5621a019b8c7c288f7fa88b14fd42bf97 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Thu, 1 Jun 2023 03:18:32 +0200 Subject: [PATCH 098/129] Fix static methods with prototypes (#4220) --- src/V3LinkDot.cpp | 11 ++++++++++- test_regress/t/t_class_extern.v | 6 ++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 9a922fc2c..eeb29ba06 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -3250,7 +3250,16 @@ private: UINFO(5, " " << nodep << endl); checkNoDot(nodep); if (nodep->isExternDef()) { - if (!m_curSymp->findIdFallback("extern " + nodep->name())) { + if (const VSymEnt* const foundp + = m_curSymp->findIdFallback("extern " + nodep->name())) { + const AstNodeFTask* const funcProtop = VN_AS(foundp->nodep(), NodeFTask); + // Copy specifiers. + // External definition cannot have any specifiers, so no value will be overwritten. + nodep->isHideLocal(funcProtop->isHideLocal()); + nodep->isHideProtected(funcProtop->isHideProtected()); + nodep->isVirtual(funcProtop->isVirtual()); + nodep->lifetime(funcProtop->lifetime()); + } else { nodep->v3error("extern not found that declares " + nodep->prettyNameQ()); } } diff --git a/test_regress/t/t_class_extern.v b/test_regress/t/t_class_extern.v index 94a71825f..0cddfdc3f 100644 --- a/test_regress/t/t_class_extern.v +++ b/test_regress/t/t_class_extern.v @@ -9,6 +9,7 @@ class Cls; extern function int ext_f_np; extern function int ext_f_p(); extern function int ext_f_i(int in); + extern static function int get_1(); extern task ext_t_np; extern task ext_t_p(); extern task ext_t_i(int in); @@ -26,6 +27,10 @@ function int Cls::ext_f_i(int in); return in+1; endfunction +function int Cls::get_1(); + return 1; +endfunction + task Cls::ext_t_np(); $write("*-* All Finished *-*\n"); endtask @@ -46,5 +51,6 @@ module t (/*AUTOARG*/); if (c.ext_f_np() != 1) $stop; if (c.ext_f_p() != 2) $stop; if (c.ext_f_i(10) != 11) $stop; + if (Cls::get_1() != 1) $stop; end endmodule From 9cc218db3eaa1b275f89714c0e8e371b96e500ca Mon Sep 17 00:00:00 2001 From: Adrien Le Masle <14968086+adrienlemasle@users.noreply.github.com> Date: Thu, 1 Jun 2023 13:43:17 +0100 Subject: [PATCH 099/129] Fix incorrect multi-driven lint warning (#4231) (#4248) --- src/V3DfgAstToDfg.cpp | 25 +++++----- test_regress/t/t_incorrect_multi_driven.pl | 21 ++++++++ test_regress/t/t_incorrect_multi_driven.v | 56 ++++++++++++++++++++++ 3 files changed, 91 insertions(+), 11 deletions(-) create mode 100755 test_regress/t/t_incorrect_multi_driven.pl create mode 100644 test_regress/t/t_incorrect_multi_driven.v diff --git a/src/V3DfgAstToDfg.cpp b/src/V3DfgAstToDfg.cpp index 78a598742..da265a1ff 100644 --- a/src/V3DfgAstToDfg.cpp +++ b/src/V3DfgAstToDfg.cpp @@ -334,17 +334,20 @@ class AstToDfgVisitor final : public VNVisitor { const uint32_t bEnd = b.m_lsb + bWidth; const uint32_t overlapEnd = std::min(aEnd, bEnd) - 1; - varp->varp()->v3warn( // - MULTIDRIVEN, - "Bits [" // - << overlapEnd << ":" << b.m_lsb << "] of signal " - << varp->varp()->prettyNameQ() - << " have multiple combinational drivers\n" - << a.m_fileline->warnOther() << "... Location of first driver\n" - << a.m_fileline->warnContextPrimary() << '\n' - << b.m_fileline->warnOther() << "... Location of other driver\n" - << b.m_fileline->warnContextSecondary() << varp->varp()->warnOther() - << "... Only the first driver will be respected"); + if (a.m_fileline->operatorCompare(*b.m_fileline) != 0) { + varp->varp()->v3warn( // + MULTIDRIVEN, + "Bits [" // + << overlapEnd << ":" << b.m_lsb << "] of signal " + << varp->varp()->prettyNameQ() + << " have multiple combinational drivers\n" + << a.m_fileline->warnOther() << "... Location of first driver\n" + << a.m_fileline->warnContextPrimary() << '\n' + << b.m_fileline->warnOther() << "... Location of other driver\n" + << b.m_fileline->warnContextSecondary() + << varp->varp()->warnOther() + << "... Only the first driver will be respected"); + } // If the first driver completely covers the range of the second driver, // we can just delete the second driver completely, otherwise adjust the diff --git a/test_regress/t/t_incorrect_multi_driven.pl b/test_regress/t/t_incorrect_multi_driven.pl new file mode 100755 index 000000000..0fc71f8e9 --- /dev/null +++ b/test_regress/t/t_incorrect_multi_driven.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 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +top_filename("t/t_incorrect_multi_driven.v"); + +lint( + fails => 0 + ); + +ok(1); +1; diff --git a/test_regress/t/t_incorrect_multi_driven.v b/test_regress/t/t_incorrect_multi_driven.v new file mode 100644 index 000000000..3020398db --- /dev/null +++ b/test_regress/t/t_incorrect_multi_driven.v @@ -0,0 +1,56 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Adrien Le Masle. +// SPDX-License-Identifier: CC0-1.0 + +interface test_if #(parameter int AA = 2, BB=5); + + logic [AA-1 : 0] a; + logic [BB-1 : 0] b; + logic c; + logic d; + + modport slave (input a, + input b, + input c, + input d); + + modport master (output a, + output b, + output c, + output d); + +endinterface : test_if + +module test + (input logic [28:0] a, + output logic [28:0] b); + + always_comb begin + b = a; + end +endmodule + +module multi_driven + ( + input logic [20-1 : 0] data_in, + output logic [20-1 : 0] data_out, + test_if.slave test_if_in, + test_if.master test_if_out + ); + + test test_inst + ( + .a({data_in, + test_if_in.a, + test_if_in.b, + test_if_in.c, + test_if_in.d}), + .b({data_out, + test_if_out.a, + test_if_out.b, + test_if_out.c, + test_if_out.d})); + +endmodule; From db7935faf386b48a41361179bfff90f3a7e48570 Mon Sep 17 00:00:00 2001 From: Aleksander Kiryk Date: Thu, 1 Jun 2023 07:02:08 -0700 Subject: [PATCH 100/129] Add std::process class (#4212) --- include/verilated_std.sv | 81 ++++++++++++++------ include/verilated_timing.cpp | 11 ++- include/verilated_timing.h | 105 ++++++++++++++++++++------ src/V3Ast.h | 26 +++++-- src/V3AstNodeDType.h | 1 + src/V3AstNodeOther.h | 17 ++++- src/V3AstNodes.cpp | 4 + src/V3Cast.cpp | 3 +- src/V3EmitCBase.cpp | 4 + src/V3EmitCFunc.cpp | 11 +++ src/V3Order.cpp | 3 + src/V3Sched.cpp | 1 + src/V3SchedTiming.cpp | 36 ++++++++- src/V3Task.cpp | 3 + src/V3Timing.cpp | 97 ++++++++++++++++++------ src/V3Width.cpp | 52 +++++++++---- test_regress/t/t_process.out | 5 +- test_regress/t/t_process.pl | 19 +++-- test_regress/t/t_process.v | 2 + test_regress/t/t_process_bad.pl | 2 +- test_regress/t/t_process_finished.pl | 27 +++++++ test_regress/t/t_process_finished.v | 24 ++++++ test_regress/t/t_process_fork.out | 11 +++ test_regress/t/t_process_fork.pl | 28 +++++++ test_regress/t/t_process_fork.v | 30 ++++++++ test_regress/t/t_process_kill.pl | 27 +++++++ test_regress/t/t_process_kill.v | 31 ++++++++ test_regress/t/t_process_notiming.out | 54 +++++++++++++ test_regress/t/t_process_notiming.pl | 22 ++++++ test_regress/t/t_process_rand.pl | 27 +++++++ test_regress/t/t_process_rand.v | 52 +++++++++++++ test_regress/t/t_process_std.pl | 19 +++-- 32 files changed, 714 insertions(+), 121 deletions(-) create mode 100755 test_regress/t/t_process_finished.pl create mode 100644 test_regress/t/t_process_finished.v create mode 100644 test_regress/t/t_process_fork.out create mode 100755 test_regress/t/t_process_fork.pl create mode 100644 test_regress/t/t_process_fork.v create mode 100755 test_regress/t/t_process_kill.pl create mode 100644 test_regress/t/t_process_kill.v create mode 100644 test_regress/t/t_process_notiming.out create mode 100755 test_regress/t/t_process_notiming.pl create mode 100755 test_regress/t/t_process_rand.pl create mode 100644 test_regress/t/t_process_rand.v diff --git a/include/verilated_std.sv b/include/verilated_std.sv index 9a1153c76..bb7fe1be8 100644 --- a/include/verilated_std.sv +++ b/include/verilated_std.sv @@ -26,10 +26,6 @@ // verilator lint_off TIMESCALEMOD // verilator lint_off UNUSEDSIGNAL package std; - // The process class is not implemented, but it's predeclared here, - // so the linter accepts references to it. - typedef class process; - class mailbox #(type T); protected int m_bound; protected T m_queue[$]; @@ -45,7 +41,7 @@ package std; task put(T message); `ifdef VERILATOR_TIMING if (m_bound != 0) - wait (m_queue.size() < m_bound); + wait (m_queue.size() < m_bound); m_queue.push_back(message); `endif endtask @@ -117,43 +113,80 @@ package std; endclass class process; - typedef enum { FINISHED, RUNNING, WAITING, SUSPENDED, KILLED } state; - static process _s_global_process; + typedef enum { + FINISHED = 0, + RUNNING = 1, + WAITING = 2, + SUSPENDED = 3, + KILLED = 4 + } state; + +`ifdef VERILATOR_TIMING + // Width visitor changes it to VlProcessRef + protected chandle m_process; +`endif + static function process self(); - // Unsupported, emulating with single process' state - if (!_s_global_process) _s_global_process = new; - return _s_global_process; + process p = new; +`ifdef VERILATOR_TIMING + $c(p.m_process, " = vlProcess;"); +`endif + return p; endfunction + + protected function void set_status(state s); +`ifdef VERILATOR_TIMING + $c(m_process, "->state(", s, ");"); +`endif + endfunction + function state status(); - // Unsupported, emulating with single process' state +`ifdef VERILATOR_TIMING + return state'($c(m_process, "->state()")); +`else return RUNNING; +`endif endfunction + function void kill(); - $error("std::process::kill() not supported"); + set_status(KILLED); endfunction - task await(); - $error("std::process::await() not supported"); - endtask + function void suspend(); $error("std::process::suspend() not supported"); endfunction + function void resume(); - $error("std::process::resume() not supported"); + set_status(RUNNING); endfunction - // When really implemented, srandom must operates on the process, but for + + task await(); +`ifdef VERILATOR_TIMING + wait (status() == FINISHED || status() == KILLED); +`endif + endtask + + // When really implemented, srandom must operate on the process, but for // now rely on the srandom() that is automatically generated for all // classes. + // // function void srandom(int seed); // endfunction + + // The methods below work only if set_randstate is never applied to + // a state string created before another such string. Full support + // could use VlRNG class to store the state per process in VlProcess + // objects. function string get_randstate(); - // Could operate on all proceses for now - // No error, as harmless until set_randstate is called - return "NOT_SUPPORTED"; + string s; + + s.itoa($random); // Get a random number + set_randstate(s); // Pretend it's the state of RNG + return s; endfunction - function void set_randstate(string randstate); - $error("std::process::set_randstate() not supported"); - // Could operate on all proceses for now + + function void set_randstate(string s); + $urandom(s.atoi()); // Set the seed using a string endfunction endclass - endpackage diff --git a/include/verilated_timing.cpp b/include/verilated_timing.cpp index d3fa2cf1b..30b3fbf7f 100644 --- a/include/verilated_timing.cpp +++ b/include/verilated_timing.cpp @@ -30,7 +30,16 @@ void VlCoroutineHandle::resume() { // main process if (VL_LIKELY(m_coro)) { VL_DEBUG_IF(VL_DBG_MSGF(" Resuming: "); dump();); - m_coro(); + if (m_process) { // If process state is managed with std::process + if (m_process->state() == VlProcess::KILLED) { + m_coro.destroy(); + } else { + m_process->state(VlProcess::RUNNING); + m_coro(); + } + } else { + m_coro(); + } m_coro = nullptr; } } diff --git a/include/verilated_timing.h b/include/verilated_timing.h index 14d570449..1e63009c5 100644 --- a/include/verilated_timing.h +++ b/include/verilated_timing.h @@ -86,6 +86,36 @@ public: #endif }; +//=================================================================== +// VlProcess stores metadata of running processes + +class VlProcess final { + // MEMBERS + int m_state; // Current state of the process + +public: + // TYPES + enum : int { // Type int for compatibility with $c + FINISHED = 0, + RUNNING = 1, + WAITING = 2, + SUSPENDED = 3, + KILLED = 4, + }; + + // CONSTRUCTORS + VlProcess() + : m_state{RUNNING} {} + + // METHODS + int state() { return m_state; } + void state(int s) { m_state = s; } +}; + +using VlProcessRef = std::shared_ptr; + +inline std::string VL_TO_STRING(const VlProcessRef& p) { return std::string("process"); } + //============================================================================= // VlCoroutineHandle is a non-copyable (but movable) coroutine handle. On resume, the handle is // cleared, as we assume that either the coroutine has finished and deleted itself, or, if it got @@ -96,25 +126,38 @@ class VlCoroutineHandle final { // MEMBERS std::coroutine_handle<> m_coro; // The wrapped coroutine handle + VlProcessRef m_process; // Data of the suspended process, null if not needed VlFileLineDebug m_fileline; public: // CONSTRUCTORS // Construct - VlCoroutineHandle() - : m_coro{nullptr} {} - VlCoroutineHandle(std::coroutine_handle<> coro, VlFileLineDebug fileline) + VlCoroutineHandle(VlProcessRef process) + : m_coro{nullptr} + , m_process{process} { + if (m_process) m_process->state(VlProcess::WAITING); + } + VlCoroutineHandle(std::coroutine_handle<> coro, VlProcessRef process, VlFileLineDebug fileline) : m_coro{coro} - , m_fileline{fileline} {} + , m_process{process} + , m_fileline{fileline} { + if (m_process) m_process->state(VlProcess::WAITING); + } // Move the handle, leaving a nullptr VlCoroutineHandle(VlCoroutineHandle&& moved) : m_coro{std::exchange(moved.m_coro, nullptr)} + , m_process{moved.m_process} , m_fileline{moved.m_fileline} {} // Destroy if the handle isn't null ~VlCoroutineHandle() { // Usually these coroutines should get resumed; we only need to clean up if we destroy a // model with some coroutines suspended - if (VL_UNLIKELY(m_coro)) m_coro.destroy(); + if (VL_UNLIKELY(m_coro)) { + m_coro.destroy(); + if (m_process && m_process->state() != VlProcess::KILLED) { + m_process->state(VlProcess::FINISHED); + } + } } // METHODS // Move the handle, leaving a null handle @@ -122,7 +165,7 @@ public: m_coro = std::exchange(moved.m_coro, nullptr); return *this; } - // Resume the coroutine if the handle isn't null + // Resume the coroutine if the handle isn't null and the process isn't killed void resume(); #ifdef VL_DEBUG void dump() const; @@ -173,21 +216,24 @@ public: void dump() const; #endif // Used by coroutines for co_awaiting a certain simulation time - auto delay(uint64_t delay, const char* filename = VL_UNKNOWN, int lineno = 0) { + auto delay(uint64_t delay, VlProcessRef process, const char* filename = VL_UNKNOWN, + int lineno = 0) { struct Awaitable { + VlProcessRef process; // Data of the suspended process, null if not needed VlDelayedCoroutineQueue& queue; uint64_t delay; VlFileLineDebug fileline; bool await_ready() const { return false; } // Always suspend void await_suspend(std::coroutine_handle<> coro) { - queue.push_back({delay, VlCoroutineHandle{coro, fileline}}); + queue.push_back({delay, VlCoroutineHandle{coro, process, fileline}}); // Move last element to the proper place in the max-heap std::push_heap(queue.begin(), queue.end()); } void await_resume() const {} }; - return Awaitable{m_queue, m_context.time() + delay, VlFileLineDebug{filename, lineno}}; + return Awaitable{process, m_queue, m_context.time() + delay, + VlFileLineDebug{filename, lineno}}; } }; @@ -224,21 +270,23 @@ public: void dump(const char* eventDescription) const; #endif // Used by coroutines for co_awaiting a certain trigger - auto trigger(bool commit, const char* eventDescription = VL_UNKNOWN, + auto trigger(bool commit, VlProcessRef process, const char* eventDescription = VL_UNKNOWN, const char* filename = VL_UNKNOWN, int lineno = 0) { VL_DEBUG_IF(VL_DBG_MSGF(" Suspending process waiting for %s at %s:%d\n", eventDescription, filename, lineno);); struct Awaitable { VlCoroutineVec& suspended; // Coros waiting on trigger + VlProcessRef process; // Data of the suspended process, null if not needed VlFileLineDebug fileline; bool await_ready() const { return false; } // Always suspend void await_suspend(std::coroutine_handle<> coro) { - suspended.emplace_back(coro, fileline); + suspended.emplace_back(coro, process, fileline); } void await_resume() const {} }; - return Awaitable{commit ? m_ready : m_uncommitted, VlFileLineDebug{filename, lineno}}; + return Awaitable{commit ? m_ready : m_uncommitted, process, + VlFileLineDebug{filename, lineno}}; } }; @@ -271,18 +319,19 @@ class VlDynamicTriggerScheduler final { // with destructive post updates, e.g. named events) // METHODS - auto awaitable(VlCoroutineVec& queue, const char* filename, int lineno) { + auto awaitable(VlProcessRef process, VlCoroutineVec& queue, const char* filename, int lineno) { struct Awaitable { + VlProcessRef process; // Data of the suspended process, null if not needed VlCoroutineVec& suspended; // Coros waiting on trigger VlFileLineDebug fileline; bool await_ready() const { return false; } // Always suspend void await_suspend(std::coroutine_handle<> coro) { - suspended.emplace_back(coro, fileline); + suspended.emplace_back(coro, process, fileline); } void await_resume() const {} }; - return Awaitable{queue, VlFileLineDebug{filename, lineno}}; + return Awaitable{process, queue, VlFileLineDebug{filename, lineno}}; } public: @@ -296,23 +345,26 @@ public: void dump() const; #endif // Used by coroutines for co_awaiting trigger evaluation - auto evaluation(const char* eventDescription, const char* filename, int lineno) { + auto evaluation(VlProcessRef process, const char* eventDescription, const char* filename, + int lineno) { VL_DEBUG_IF(VL_DBG_MSGF(" Suspending process waiting for %s at %s:%d\n", eventDescription, filename, lineno);); - return awaitable(m_suspended, filename, lineno); + return awaitable(process, m_suspended, filename, lineno); } // Used by coroutines for co_awaiting the trigger post update step - auto postUpdate(const char* eventDescription, const char* filename, int lineno) { + auto postUpdate(VlProcessRef process, const char* eventDescription, const char* filename, + int lineno) { VL_DEBUG_IF( VL_DBG_MSGF(" Process waiting for %s at %s:%d awaiting the post update step\n", eventDescription, filename, lineno);); - return awaitable(m_post, filename, lineno); + return awaitable(process, m_post, filename, lineno); } // Used by coroutines for co_awaiting the resumption step (in 'act' eval) - auto resumption(const char* eventDescription, const char* filename, int lineno) { + auto resumption(VlProcessRef process, const char* eventDescription, const char* filename, + int lineno) { VL_DEBUG_IF(VL_DBG_MSGF(" Process waiting for %s at %s:%d awaiting resumption\n", eventDescription, filename, lineno);); - return awaitable(m_triggered, filename, lineno); + return awaitable(process, m_triggered, filename, lineno); } }; @@ -342,24 +394,27 @@ class VlForkSync final { public: // Create the join object and set the counter to the specified number - void init(size_t count) { m_join.reset(new VlJoin{count, {}}); } + void init(size_t count, VlProcessRef process) { m_join.reset(new VlJoin{count, {process}}); } // Called whenever any of the forked processes finishes. If the join counter reaches 0, the // main process gets resumed void done(const char* filename = VL_UNKNOWN, int lineno = 0); // Used by coroutines for co_awaiting a join - auto join(const char* filename = VL_UNKNOWN, int lineno = 0) { + auto join(VlProcessRef process, const char* filename = VL_UNKNOWN, int lineno = 0) { assert(m_join); VL_DEBUG_IF( VL_DBG_MSGF(" Awaiting join of fork at: %s:%d\n", filename, lineno);); struct Awaitable { + VlProcessRef process; // Data of the suspended process, null if not needed const std::shared_ptr join; // Join to await on VlFileLineDebug fileline; bool await_ready() { return join->m_counter == 0; } // Suspend if join still exists - void await_suspend(std::coroutine_handle<> coro) { join->m_susp = {coro, fileline}; } + void await_suspend(std::coroutine_handle<> coro) { + join->m_susp = {coro, process, fileline}; + } void await_resume() const {} }; - return Awaitable{m_join, VlFileLineDebug{filename, lineno}}; + return Awaitable{process, m_join, VlFileLineDebug{filename, lineno}}; } }; diff --git a/src/V3Ast.h b/src/V3Ast.h index 960a3c69a..b871314c0 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -461,6 +461,7 @@ public: TRIGGER_SCHEDULER, DYNAMIC_TRIGGER_SCHEDULER, FORK_SYNC, + PROCESS_REFERENCE, // Unsigned and two state; fundamental types UINT32, UINT64, @@ -493,6 +494,7 @@ public: "VlTriggerScheduler", "VlDynamicTriggerScheduler", "VlFork", + "VlProcessRef", "IData", "QData", "LOGIC_IMPLICIT", @@ -500,13 +502,20 @@ public: return names[m_e]; } const char* dpiType() const { - static const char* const names[] - = {"%E-unk", "svBit", "char", "void*", "char", - "int", "%E-integer", "svLogic", "long long", "double", - "short", "%E-time", "const char*", "%E-untyped", "dpiScope", - "const char*", "%E-mtaskstate", "%E-triggervec", "%E-dly-sched", "%E-trig-sched", - "%E-dyn-sched", "%E-fork", "IData", "QData", "%E-logic-implct", - " MAX"}; + static const char* const names[] = {"%E-unk", "svBit", + "char", "void*", + "char", "int", + "%E-integer", "svLogic", + "long long", "double", + "short", "%E-time", + "const char*", "%E-untyped", + "dpiScope", "const char*", + "%E-mtaskstate", "%E-triggervec", + "%E-dly-sched", "%E-trig-sched", + "%E-dyn-sched", "%E-fork", + "%E-proc-ref", "IData", + "QData", "%E-logic-implct", + " MAX"}; return names[m_e]; } static void selfTest() { @@ -545,6 +554,7 @@ public: case TRIGGER_SCHEDULER: return 0; // opaque case DYNAMIC_TRIGGER_SCHEDULER: return 0; // opaque case FORK_SYNC: return 0; // opaque + case PROCESS_REFERENCE: return 0; // opaque case UINT32: return 32; case UINT64: return 64; default: return 0; @@ -584,7 +594,7 @@ public: return (m_e == EVENT || m_e == STRING || m_e == SCOPEPTR || m_e == CHARPTR || m_e == MTASKSTATE || m_e == TRIGGERVEC || m_e == DELAY_SCHEDULER || m_e == TRIGGER_SCHEDULER || m_e == DYNAMIC_TRIGGER_SCHEDULER || m_e == FORK_SYNC - || m_e == DOUBLE || m_e == UNTYPED); + || m_e == PROCESS_REFERENCE || m_e == DOUBLE || m_e == UNTYPED); } bool isDouble() const VL_MT_SAFE { return m_e == DOUBLE; } bool isEvent() const { return m_e == EVENT; } diff --git a/src/V3AstNodeDType.h b/src/V3AstNodeDType.h index c06e761c0..a74eeec6f 100644 --- a/src/V3AstNodeDType.h +++ b/src/V3AstNodeDType.h @@ -438,6 +438,7 @@ public: bool isEvent() const VL_MT_SAFE { return keyword() == VBasicDTypeKwd::EVENT; } bool isTriggerVec() const VL_MT_SAFE { return keyword() == VBasicDTypeKwd::TRIGGERVEC; } bool isForkSync() const VL_MT_SAFE { return keyword() == VBasicDTypeKwd::FORK_SYNC; } + bool isProcessRef() const VL_MT_SAFE { return keyword() == VBasicDTypeKwd::PROCESS_REFERENCE; } bool isDelayScheduler() const VL_MT_SAFE { return keyword() == VBasicDTypeKwd::DELAY_SCHEDULER; } diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 1070c83f9..497b545cb 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -86,6 +86,7 @@ private: bool m_recursive : 1; // Recursive or part of recursion bool m_underGenerate : 1; // Under generate (for warning) bool m_virtual : 1; // Virtual method in class + bool m_fromStd : 1; // Part of std VLifetime m_lifetime; // Lifetime protected: AstNodeFTask(VNType t, FileLine* fl, const string& name, AstNode* stmtsp) @@ -110,7 +111,8 @@ protected: , m_pureVirtual{false} , m_recursive{false} , m_underGenerate{false} - , m_virtual{false} { + , m_virtual{false} + , m_fromStd{false} { addStmtsp(stmtsp); cname(name); // Might be overridden by dpi import/export } @@ -170,6 +172,8 @@ public: bool underGenerate() const { return m_underGenerate; } void isVirtual(bool flag) { m_virtual = flag; } bool isVirtual() const { return m_virtual; } + void isFromStd(bool flag) { m_fromStd = flag; } + bool isFromStd() const { return m_fromStd; } void lifetime(const VLifetime& flag) { m_lifetime = flag; } VLifetime lifetime() const { return m_lifetime; } bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); } @@ -272,10 +276,13 @@ public: class AstNodeProcedure VL_NOT_FINAL : public AstNode { // IEEE procedure: initial, final, always // @astgen op2 := stmtsp : List[AstNode] // Note: op1 is used in some sub-types only - bool m_suspendable = false; // Is suspendable by a Delay, EventControl, etc. + bool m_suspendable : 1; // Is suspendable by a Delay, EventControl, etc. + bool m_needProcess : 1; // Implements part of a process that allocates std::process protected: AstNodeProcedure(VNType t, FileLine* fl, AstNode* stmtsp) : AstNode{t, fl} { + m_needProcess = false; + m_suspendable = false; addStmtsp(stmtsp); } @@ -286,6 +293,8 @@ public: bool isJustOneBodyStmt() const { return stmtsp() && !stmtsp()->nextp(); } bool isSuspendable() const { return m_suspendable; } void setSuspendable() { m_suspendable = true; } + bool needProcess() const { return m_needProcess; } + void setNeedProcess() { m_needProcess = true; } }; class AstNodeRange VL_NOT_FINAL : public AstNode { // A range, sized or unsized @@ -576,6 +585,7 @@ private: bool m_dpiImportPrototype : 1; // This is the DPI import prototype (i.e.: provided by user) bool m_dpiImportWrapper : 1; // Wrapper for invoking DPI import prototype from generated code bool m_dpiTraceInit : 1; // DPI trace_init + bool m_needProcess : 1; // Implements part of a process that allocates std::process public: AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType = "") : ASTGEN_SUPER_CFunc(fl) { @@ -595,6 +605,7 @@ public: m_isLoose = false; m_isInline = false; m_isVirtual = false; + m_needProcess = false; m_entryPoint = false; m_pure = false; m_dpiContext = false; @@ -663,6 +674,8 @@ public: void isInline(bool flag) { m_isInline = flag; } bool isVirtual() const { return m_isVirtual; } void isVirtual(bool flag) { m_isVirtual = flag; } + bool needProcess() const { return m_needProcess; } + void setNeedProcess() { m_needProcess = true; } bool entryPoint() const { return m_entryPoint; } void entryPoint(bool flag) { m_entryPoint = flag; } bool pure() const { return m_pure; } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index eccb2d504..ab7225d87 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -784,6 +784,8 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const VL_M info.m_type = "VlDynamicTriggerScheduler"; } else if (bdtypep->isForkSync()) { info.m_type = "VlForkSync"; + } else if (bdtypep->isProcessRef()) { + info.m_type = "VlProcessRef"; } else if (bdtypep->isEvent()) { info.m_type = "VlEvent"; } else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width @@ -1352,6 +1354,7 @@ void AstNode::dump(std::ostream& str) const { void AstNodeProcedure::dump(std::ostream& str) const { this->AstNode::dump(str); if (isSuspendable()) str << " [SUSP]"; + if (needProcess()) str << " [NPRC]"; } void AstAlways::dump(std::ostream& str) const { @@ -2294,6 +2297,7 @@ void AstCFunc::dump(std::ostream& str) const { if (isDestructor()) str << " [DTOR]"; if (isVirtual()) str << " [VIRT]"; if (isCoroutine()) str << " [CORO]"; + if (needProcess()) str << " [NPRC]"; } const char* AstCAwait::broken() const { BROKEN_RTN(m_sensesp && !m_sensesp->brokeExists()); diff --git a/src/V3Cast.cpp b/src/V3Cast.cpp index b976b5324..eaecd7320 100644 --- a/src/V3Cast.cpp +++ b/src/V3Cast.cpp @@ -186,7 +186,8 @@ private: && !VN_IS(backp, NodeCCall) && !VN_IS(backp, CMethodHard) && !VN_IS(backp, SFormatF) && !VN_IS(backp, ArraySel) && !VN_IS(backp, StructSel) && !VN_IS(backp, RedXor) && (nodep->varp()->basicp() && !nodep->varp()->basicp()->isTriggerVec() - && !nodep->varp()->basicp()->isForkSync()) + && !nodep->varp()->basicp()->isForkSync() + && !nodep->varp()->basicp()->isProcessRef()) && backp->width() && castSize(nodep) != castSize(nodep->varp())) { // Cast vars to IData first, else below has upper bits wrongly set // CData x=3; out = (QData)(x<<30); diff --git a/src/V3EmitCBase.cpp b/src/V3EmitCBase.cpp index a7779be62..5a173f38b 100644 --- a/src/V3EmitCBase.cpp +++ b/src/V3EmitCBase.cpp @@ -79,6 +79,10 @@ string EmitCBaseVisitorConst::cFuncArgs(const AstCFunc* nodep) { args += prefixNameProtect(EmitCParentModule::get(nodep)); args += "* vlSelf"; } + if (nodep->needProcess()) { + if (!args.empty()) args += ", "; + args += "VlProcessRef vlProcess"; + } if (!nodep->argTypes().empty()) { if (!args.empty()) args += ", "; args += nodep->argTypes(); diff --git a/src/V3EmitCFunc.cpp b/src/V3EmitCFunc.cpp index 9160e5068..195e41ea8 100644 --- a/src/V3EmitCFunc.cpp +++ b/src/V3EmitCFunc.cpp @@ -417,6 +417,15 @@ void EmitCFunc::emitCCallArgs(const AstNodeCCall* nodep, const string& selfPoint puts(selfPointer); comma = true; } + if (nodep->funcp()->needProcess()) { + if (comma) puts(", "); + if (VN_IS(nodep->backp(), CAwait)) { + puts("vlProcess"); + } else { + puts("std::make_shared()"); + } + comma = true; + } if (!nodep->argTypes().empty()) { if (comma) puts(", "); puts(nodep->argTypes()); @@ -695,6 +704,8 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, const string& varNameP return ""; } else if (basicp && basicp->isForkSync()) { return ""; + } else if (basicp && basicp->isProcessRef()) { + return ""; } else if (basicp && basicp->isDelayScheduler()) { return ""; } else if (basicp && basicp->isTriggerScheduler()) { diff --git a/src/V3Order.cpp b/src/V3Order.cpp index 13f1490a2..ae0365019 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -1214,9 +1214,11 @@ AstActive* OrderProcess::processMoveOneLogic(const OrderLogicVertex* lvertexp, // Process procedures per statement (unless profCFuncs), so we can split CFuncs within // procedures. Everything else is handled in one go bool suspendable = false; + bool needProcess = false; bool slow = m_slow; if (AstNodeProcedure* const procp = VN_CAST(nodep, NodeProcedure)) { suspendable = procp->isSuspendable(); + needProcess = procp->needProcess(); if (suspendable) slow = slow && !VN_IS(procp, Always); nodep = procp->stmtsp(); pushDeletep(procp); @@ -1241,6 +1243,7 @@ AstActive* OrderProcess::processMoveOneLogic(const OrderLogicVertex* lvertexp, const string name = cfuncName(modp, domainp, scopep, nodep); newFuncpr = new AstCFunc{nodep->fileline(), name, scopep, suspendable ? "VlCoroutine" : ""}; + if (needProcess) newFuncpr->setNeedProcess(); newFuncpr->isStatic(false); newFuncpr->isLoose(true); newFuncpr->slow(slow); diff --git a/src/V3Sched.cpp b/src/V3Sched.cpp index fc26a192d..78f09d44b 100644 --- a/src/V3Sched.cpp +++ b/src/V3Sched.cpp @@ -247,6 +247,7 @@ void orderSequentially(AstCFunc* funcp, const LogicByScope& lbs) { subFuncp = createNewSubFuncp(scopep); subFuncp->name(subFuncp->name() + "__" + cvtToStr(scopep->user2Inc())); subFuncp->rtnType("VlCoroutine"); + if (procp->needProcess()) subFuncp->setNeedProcess(); if (VN_IS(procp, Always)) { subFuncp->slow(false); FileLine* const flp = procp->fileline(); diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp index e0d3e908d..ec816bc70 100644 --- a/src/V3SchedTiming.cpp +++ b/src/V3SchedTiming.cpp @@ -155,6 +155,19 @@ TimingKit prepareTiming(AstNetlist* const netlistp) { std::vector m_writtenBySuspendable; // METHODS + // Add arguments to a resume() call based on arguments in the suspending call + void addResumePins(AstCMethodHard* const resumep, AstNodeExpr* pinsp) { + AstCExpr* const exprp = VN_CAST(pinsp, CExpr); + AstText* const textp = VN_CAST(exprp->exprsp(), Text); + if (textp) { + // The first argument, vlProcess, isn't used by any of resume() methods, skip it + if ((pinsp = VN_CAST(pinsp->nextp(), NodeExpr))) { + resumep->addPinsp(pinsp->cloneTree(false)); + } + } else { + resumep->addPinsp(pinsp->cloneTree(false)); + } + } // Create an active with a timing scheduler resume() call void createResumeActive(AstCAwait* const awaitp) { auto* const methodp = VN_AS(awaitp->exprp(), CMethodHard); @@ -171,7 +184,8 @@ TimingKit prepareTiming(AstNetlist* const netlistp) { // The first pin is the commit boolean, the rest (if any) should be debug info // See V3Timing for details if (AstNode* const dbginfop = methodp->pinsp()->nextp()) { - resumep->addPinsp(static_cast(dbginfop)->cloneTree(false)); + if (methodp->pinsp()) + addResumePins(resumep, static_cast(dbginfop)); } } else if (schedulerp->dtypep()->basicp()->isDynamicTriggerScheduler()) { auto* const postp = resumep->cloneTree(false); @@ -262,6 +276,7 @@ void transformForks(AstNetlist* const netlistp) { // STATE bool m_inClass = false; // Are we in a class? bool m_beginHasAwaits = false; // Does the current begin have awaits? + bool m_beginNeedProcess = false; // Does the current begin have process::self dependency? AstFork* m_forkp = nullptr; // Current fork AstCFunc* m_funcp = nullptr; // Current function @@ -348,8 +363,9 @@ void transformForks(AstNetlist* const netlistp) { UASSERT_OBJ(m_forkp, nodep, "Begin outside of a fork"); // Start with children, so later we only find awaits that are actually in this begin m_beginHasAwaits = false; + m_beginNeedProcess = false; iterateChildrenConst(nodep); - if (m_beginHasAwaits) { + if (m_beginHasAwaits || m_beginNeedProcess) { UASSERT_OBJ(!nodep->name().empty(), nodep, "Begin needs a name"); // Create a function to put this begin's statements in FileLine* const flp = nodep->fileline(); @@ -372,9 +388,19 @@ void transformForks(AstNetlist* const netlistp) { } // Put the begin's statements in the function, delete the begin newfuncp->addStmtsp(nodep->stmtsp()->unlinkFrBackWithNext()); + if (m_beginNeedProcess) { + newfuncp->setNeedProcess(); + newfuncp->addStmtsp(new AstCStmt{nodep->fileline(), + "vlProcess->state(VlProcess::FINISHED);\n"}); + } + if (!m_beginHasAwaits) { + // co_return at the end (either that or a co_await is required in a coroutine + newfuncp->addStmtsp(new AstCStmt{nodep->fileline(), "co_return;\n"}); + } remapLocals(newfuncp, callp); } else { - // No awaits, just inline the forked process + // The begin has neither awaits nor a process::self call, just inline the + // statements nodep->replaceWith(nodep->stmtsp()->unlinkFrBackWithNext()); } VL_DO_DANGLING(nodep->deleteTree(), nodep); @@ -383,6 +409,10 @@ void transformForks(AstNetlist* const netlistp) { m_beginHasAwaits = true; iterateChildrenConst(nodep); } + void visit(AstCCall* nodep) override { + if (nodep->funcp()->needProcess()) m_beginNeedProcess = true; + iterateChildrenConst(nodep); + } //-------------------- void visit(AstNodeExpr*) override {} // Accelerate diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 95691ce4f..5f1e195ce 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -1316,6 +1316,9 @@ private: } } + // Mark the fact that this function allocates std::process + if (nodep->isFromStd() && nodep->name() == "self") cfuncp->setNeedProcess(); + // Delete rest of cloned task and return new func VL_DO_DANGLING(pushDeletep(nodep), nodep); if (debug() >= 9) cfuncp->dumpTree("- userFunc: "); diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index 6772f95f0..fa9305000 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -61,6 +61,16 @@ VL_DEFINE_DEBUG_FUNCTIONS; +// ###################################################################### + +enum TimingFlag : uint8_t { + // Properties of flags with higher numbers include properties of flags with + // lower numbers + T_NORM = 0, // Normal non-suspendable process + T_SUSP = 1, // Suspendable + T_PROC = 2 // Suspendable with process metadata +}; + // ###################################################################### // Detect nodes affected by timing @@ -94,8 +104,10 @@ private: // AstClass::user1() -> bool. Set true if the class // member cache has been // refreshed. - // Ast{NodeProcedure,CFunc,Begin}::user2() -> bool. Set true if process/task is - // suspendable + // Ast{NodeProcedure,CFunc,Begin}::user2() -> int. Set to >= T_SUSP if + // process/task suspendable + // and to T_PROC if it + // needs process metadata. // Ast{NodeProcedure,CFunc,Begin}::user3() -> DependencyVertex*. Vertex in m_depGraph const VNUser1InUse m_user1InUse; const VNUser2InUse m_user2InUse; @@ -113,15 +125,23 @@ private: if (!nodep->user3p()) nodep->user3p(new TimingDependencyVertex{&m_depGraph, nodep}); return nodep->user3u().to(); } - // Propagate suspendable flag to all nodes that depend on the given one - void propagateSuspendable(TimingDependencyVertex* const vxp) { + // Set timing flag of a node + bool setTimingFlag(AstNode* nodep, int flag) { + // Properties of flags with higher numbers include properties of flags with lower + // numbers, so modify nodep->user2() only if it will increase. + if (nodep->user2() < flag) { + nodep->user2(flag); + return true; + } + return false; + } + // Propagate suspendable/needProcess flag to all nodes that depend on the given one + void propagateTimingFlags(TimingDependencyVertex* const vxp) { + auto* const parentp = vxp->nodep(); for (V3GraphEdge* edgep = vxp->inBeginp(); edgep; edgep = edgep->inNextp()) { auto* const depVxp = static_cast(edgep->fromp()); AstNode* const depp = depVxp->nodep(); - if (!depp->user2()) { - depp->user2(true); - propagateSuspendable(depVxp); - } + if (setTimingFlag(depp, parentp->user2())) propagateTimingFlags(depVxp); } } @@ -142,6 +162,7 @@ private: m_procp = nodep; iterateChildren(nodep); TimingDependencyVertex* const vxp = getDependencyVertex(nodep); + if (nodep->needProcess()) nodep->user2(T_PROC); if (!m_classp) return; // If class method (possibly overrides another method) if (!m_classp->user1SetOnce()) m_classp->repairCache(); @@ -162,15 +183,13 @@ private: // the root of the inheritance hierarchy and check if the original method is // virtual or not. if (!cextp->classp()->user1SetOnce()) cextp->classp()->repairCache(); - if (AstCFunc* const overriddenp + if (auto* const overriddenp = VN_CAST(cextp->classp()->findMember(nodep->name()), CFunc)) { - if (overriddenp->user2()) { // If it's suspendable - nodep->user2(true); // Then we are also suspendable - // As both are suspendable already, there is no need to add it as our - // dependency or self to its dependencies - } else { - // Make a dependency cycle, as being suspendable should propagate both - // up and down the inheritance tree + setTimingFlag(nodep, overriddenp->user2()); + if (nodep->user2() + < T_PROC) { // Add a vertex only if the flag can still change + // Make a dependency cycle, as being suspendable should propagate both up + // and down the inheritance tree TimingDependencyVertex* const overriddenVxp = getDependencyVertex(overriddenp); new V3GraphEdge{&m_depGraph, vxp, overriddenVxp, 1}; @@ -184,11 +203,8 @@ private: } } void visit(AstNodeCCall* nodep) override { - if (nodep->funcp()->user2()) { - m_procp->user2(true); - // Both the caller and the callee are suspendable, no need to make dependency edges - // between them - } else { + setTimingFlag(m_procp, nodep->funcp()->user2()); + if (m_procp->user2() < T_PROC) { // Add a vertex only if the flag can still change TimingDependencyVertex* const procVxp = getDependencyVertex(m_procp); TimingDependencyVertex* const funcVxp = getDependencyVertex(nodep->funcp()); new V3GraphEdge{&m_depGraph, procVxp, funcVxp, 1}; @@ -203,7 +219,7 @@ private: void visit(AstNode* nodep) override { if (nodep->isTimingControl()) { v3Global.setUsesTiming(); - if (m_procp) m_procp->user2(true); + if (m_procp) m_procp->user2(T_SUSP); } iterateChildren(nodep); } @@ -218,7 +234,7 @@ public: m_depGraph.removeTransitiveEdges(); for (V3GraphVertex* vxp = m_depGraph.verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { TimingDependencyVertex* const depVxp = static_cast(vxp); - if (depVxp->nodep()->user2()) propagateSuspendable(depVxp); + if (depVxp->nodep()->user2()) propagateTimingFlags(depVxp); } if (dumpGraphLevel() >= 6) m_depGraph.dumpDotFilePrefixed("timing_deps"); } @@ -252,6 +268,7 @@ private: AstClass* m_classp = nullptr; // Current class AstScope* m_scopep = nullptr; // Current scope AstActive* m_activep = nullptr; // Current active + AstNode* m_procp = nullptr; // NodeProcedure/CFunc/Begin we're under double m_timescaleFactor = 1.0; // Factor to scale delays by // Unique names @@ -460,6 +477,14 @@ private: methodp->addPinsp(createEventDescription(sensesp)); addDebugInfo(methodp); } + // Adds process pointer to a hardcoded method call + void addProcessInfo(AstCMethodHard* const methodp) const { + FileLine* const flp = methodp->fileline(); + AstCExpr* const ap = new AstCExpr{ + flp, m_procp && m_procp->user2() == T_PROC ? "vlProcess" : "nullptr", 0}; + ap->dtypeSetVoid(); + methodp->addPinsp(ap); + } // Creates the fork handle type and returns it AstBasicDType* getCreateForkSyncDTypep() { if (m_forkDtp) return m_forkDtp; @@ -512,11 +537,13 @@ private: auto* const initp = new AstCMethodHard{flp, new AstVarRef{flp, forkVscp, VAccess::WRITE}, "init", new AstConst{flp, joinCount}}; initp->dtypeSetVoid(); + addProcessInfo(initp); forkp->addHereThisAsNext(initp->makeStmt()); // Await the join at the end auto* const joinp = new AstCMethodHard{flp, new AstVarRef{flp, forkVscp, VAccess::WRITE}, "join"}; joinp->dtypeSetVoid(); + addProcessInfo(joinp); addDebugInfo(joinp); AstCAwait* const awaitp = new AstCAwait{flp, joinp}; awaitp->dtypeSetVoid(); @@ -543,13 +570,24 @@ private: m_activep = nullptr; } void visit(AstNodeProcedure* nodep) override { + VL_RESTORER(m_procp); + m_procp = nodep; iterateChildren(nodep); - if (nodep->user2()) nodep->setSuspendable(); + if (nodep->user2() >= T_SUSP) nodep->setSuspendable(); + if (nodep->user2() >= T_PROC) nodep->setNeedProcess(); + } + void visit(AstInitial* nodep) override { + visit(static_cast(nodep)); + if (nodep->needProcess() && !nodep->user1SetOnce()) { + nodep->addStmtsp( + new AstCStmt{nodep->fileline(), "vlProcess->state(VlProcess::FINISHED);\n"}); + } } void visit(AstAlways* nodep) override { if (nodep->user1SetOnce()) return; iterateChildren(nodep); if (!nodep->user2()) return; + if (nodep->user2() == T_PROC) nodep->setNeedProcess(); nodep->setSuspendable(); FileLine* const flp = nodep->fileline(); AstSenTree* const sensesp = m_activep->sensesp(); @@ -567,6 +605,8 @@ private: m_activep->addNextHere(activep); } void visit(AstCFunc* nodep) override { + VL_RESTORER(m_procp); + m_procp = nodep; iterateChildren(nodep); if (!nodep->user2()) return; nodep->rtnType("VlCoroutine"); @@ -588,6 +628,7 @@ private: firstCoStmtp->v3warn(E_UNSUPPORTED, "Unsupported: Timing controls inside DPI-exported tasks"); } + if (nodep->user2() == T_PROC) nodep->setNeedProcess(); } void visit(AstNodeCCall* nodep) override { if (nodep->funcp()->user2() && !nodep->user1SetOnce()) { // If suspendable @@ -627,6 +668,7 @@ private: auto* const delayMethodp = new AstCMethodHard{ flp, new AstVarRef{flp, getCreateDelayScheduler(), VAccess::WRITE}, "delay", valuep}; delayMethodp->dtypeSetVoid(); + addProcessInfo(delayMethodp); addDebugInfo(delayMethodp); // Create the co_await AstCAwait* const awaitp = new AstCAwait{flp, delayMethodp, getCreateDelaySenTree()}; @@ -666,6 +708,7 @@ private: flp, new AstVarRef{flp, getCreateDynamicTriggerScheduler(), VAccess::WRITE}, "evaluation"}; evalMethodp->dtypeSetVoid(); + addProcessInfo(evalMethodp); auto* const sensesp = nodep->sensesp(); addEventDebugInfo(evalMethodp, sensesp); // Create the co_await @@ -723,6 +766,7 @@ private: // If it should be committed immediately, pass true, otherwise false triggerMethodp->addPinsp(nodep->user2() ? new AstConst{flp, AstConst::BitTrue{}} : new AstConst{flp, AstConst::BitFalse{}}); + addProcessInfo(triggerMethodp); addEventDebugInfo(triggerMethodp, sensesp); // Create the co_await AstCAwait* const awaitp = new AstCAwait{flp, triggerMethodp, sensesp}; @@ -858,6 +902,11 @@ private: } VL_DO_DANGLING(nodep->deleteTree(), nodep); } + void visit(AstBegin* nodep) override { + VL_RESTORER(m_procp); + m_procp = nodep; + iterateChildren(nodep); + } void visit(AstFork* nodep) override { if (nodep->user1SetOnce()) return; v3Global.setUsesTiming(); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 95f3c3915..9ff2f067e 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -232,7 +232,7 @@ private: const AstWith* m_withp = nullptr; // Current 'with' statement const AstFunc* m_funcp = nullptr; // Current function const AstAttrOf* m_attrp = nullptr; // Current attribute - AstNodeModule* m_modp = nullptr; // Current module + AstPackage* m_pkgp = nullptr; // Current package const bool m_paramsOnly; // Computing parameter value; limit operation const bool m_doGenerate; // Do errors later inside generate statement int m_dtTables = 0; // Number of created data type tables @@ -2628,6 +2628,16 @@ private: } void visit(AstClass* nodep) override { if (nodep->didWidthAndSet()) return; + // If the package is std::process, set m_process type to VlProcessRef + if (m_pkgp && m_pkgp->name() == "std" && nodep->name() == "process") { + if (AstVar* const varp = VN_CAST(nodep->findMember("m_process"), Var)) { + AstBasicDType* const dtypep = new AstBasicDType{ + nodep->fileline(), VBasicDTypeKwd::PROCESS_REFERENCE, VSigning::UNSIGNED}; + v3Global.rootp()->typeTablep()->addTypesp(dtypep); + varp->getChildDTypep()->unlinkFrBack(); + varp->dtypep(dtypep); + } + } // Must do extends first, as we may in functions under this class // start following a tree of extends that takes us to other classes VL_RESTORER(m_classp); @@ -2636,6 +2646,11 @@ private: userIterateChildren(nodep, nullptr); // First size all members nodep->repairCache(); } + void visit(AstPackage* nodep) override { + VL_RESTORER(m_pkgp); + m_pkgp = nodep; + userIterateChildren(nodep, nullptr); + } void visit(AstThisRef* nodep) override { if (nodep->didWidthAndSet()) return; nodep->dtypep(iterateEditMoveDTypep(nodep, nodep->childDTypep())); @@ -2646,12 +2661,6 @@ private: // though causes problems with t_class_forward.v, so for now avoided // userIterateChildren(nodep->classp(), nullptr); } - void visit(AstNodeModule* nodep) override { - // Visitor does not include AstClass - specialized visitor above - VL_RESTORER(m_modp); - m_modp = nodep; - userIterateChildren(nodep, nullptr); - } void visit(AstClassOrPackageRef* nodep) override { if (nodep->didWidthAndSet()) return; userIterateChildren(nodep, nullptr); @@ -3491,7 +3500,7 @@ private: VL_DANGLING(index_exprp); // May have been edited return VN_AS(nodep->pinsp(), Arg)->exprp(); } - void methodCallWarnTiming(AstMethodCall* const nodep, const std::string& className) { + void methodCallWarnTiming(AstNodeFTaskRef* const nodep, const std::string& className) { if (v3Global.opt.timing().isSetFalse()) { nodep->v3warn(E_NOTIMING, className << "::" << nodep->name() << "() requires --timing"); @@ -3515,14 +3524,12 @@ private: if (classp->name() == "semaphore" || classp->name() == "process" || VString::startsWith(classp->name(), "mailbox")) { // Find the package the class is in - AstNode* pkgItemp = classp; - while (pkgItemp->backp() && pkgItemp->backp()->nextp() == pkgItemp) { - pkgItemp = pkgItemp->backp(); - } - AstPackage* const packagep = VN_CAST(pkgItemp->backp(), Package); + AstPackage* const packagep = getItemPackage(classp); // Check if it's std if (packagep && packagep->name() == "std") { - if (classp->name() == "semaphore" && nodep->name() == "get") { + if (classp->name() == "process") { + methodCallWarnTiming(nodep, "process"); + } else if (classp->name() == "semaphore" && nodep->name() == "get") { methodCallWarnTiming(nodep, "semaphore"); } else if (nodep->name() == "put" || nodep->name() == "get" || nodep->name() == "peek") { @@ -5323,6 +5330,7 @@ private: nodep->didWidth(true); return; } + if (m_pkgp && m_pkgp->name() == "std") nodep->isFromStd(true); if (nodep->classMethod() && nodep->name() == "rand_mode") { nodep->v3error("The 'rand_mode' method is built-in and cannot be overridden" " (IEEE 1800-2017 18.8)"); @@ -5405,9 +5413,25 @@ private: } } + AstPackage* getItemPackage(AstNode* pkgItemp) { + while (pkgItemp->backp() && pkgItemp->backp()->nextp() == pkgItemp) { + pkgItemp = pkgItemp->backp(); + } + return VN_CAST(pkgItemp->backp(), Package); + } void visit(AstFuncRef* nodep) override { visit(static_cast(nodep)); nodep->dtypeFrom(nodep->taskp()); + if (nodep->fileline()->timingOn()) { + AstNodeModule* const classp = nodep->classOrPackagep(); + if (nodep->name() == "self" && classp->name() == "process") { + // Find if package the class is in is std:: + AstPackage* const packagep = getItemPackage(classp); + if (packagep && packagep->name() == "std") { + methodCallWarnTiming(nodep, "process"); + } + } + } // if (debug()) nodep->dumpTree("- FuncOut: "); } // Returns true if dtypep0 and dtypep1 have same dimensions diff --git a/test_regress/t/t_process.out b/test_regress/t/t_process.out index ab04bc4e8..f0d3cbfc9 100644 --- a/test_regress/t/t_process.out +++ b/test_regress/t/t_process.out @@ -1,3 +1,2 @@ -[0] %Error: verilated_std.sv:154: Assertion failed in top.std.process.set_randstate: std::process::set_randstate() not supported -%Error: verilated_std.sv:154: Verilog $stop -Aborting... +'{m_process:process} +*-* All Finished *-* diff --git a/test_regress/t/t_process.pl b/test_regress/t/t_process.pl index 39ea187ff..b477231cf 100755 --- a/test_regress/t/t_process.pl +++ b/test_regress/t/t_process.pl @@ -10,14 +10,19 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -compile( - ); +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + v_flags2 => ["--timing"], + ); -execute( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, - check_finished => !$Self->{vlt_all}, - ); + execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); +} ok(1); 1; diff --git a/test_regress/t/t_process.v b/test_regress/t/t_process.v index 0d495ab17..9d4f3fbb8 100644 --- a/test_regress/t/t_process.v +++ b/test_regress/t/t_process.v @@ -38,6 +38,8 @@ module t(/*AUTOARG*/); p.srandom(0); p.set_randstate(p.get_randstate()); + $display("%p", p); + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_process_bad.pl b/test_regress/t/t_process_bad.pl index dd3bcbbf3..c87b2fc6f 100755 --- a/test_regress/t/t_process_bad.pl +++ b/test_regress/t/t_process_bad.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); lint( - verilator_flags2 => ["--xml-only"], + verilator_flags2 => ["--xml-only", "--timing"], fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_process_finished.pl b/test_regress/t/t_process_finished.pl new file mode 100755 index 000000000..1db13024b --- /dev/null +++ b/test_regress/t/t_process_finished.pl @@ -0,0 +1,27 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 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); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--timing"], + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_process_finished.v b/test_regress/t/t_process_finished.v new file mode 100644 index 000000000..df6f6cc28 --- /dev/null +++ b/test_regress/t/t_process_finished.v @@ -0,0 +1,24 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + process p; + + initial begin + p = process::self(); + end + + always @(posedge clk) begin + if (p.status() != process::FINISHED) + $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_process_fork.out b/test_regress/t/t_process_fork.out new file mode 100644 index 000000000..8b4a1a959 --- /dev/null +++ b/test_regress/t/t_process_fork.out @@ -0,0 +1,11 @@ +job started +job started +job started +job started +job started +job started +job started +job started +all jobs started +all jobs finished +*-* All Finished *-* diff --git a/test_regress/t/t_process_fork.pl b/test_regress/t/t_process_fork.pl new file mode 100755 index 000000000..1af68b062 --- /dev/null +++ b/test_regress/t/t_process_fork.pl @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 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); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--timing"], + ); + + execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_process_fork.v b/test_regress/t/t_process_fork.v new file mode 100644 index 000000000..1ea1c477e --- /dev/null +++ b/test_regress/t/t_process_fork.v @@ -0,0 +1,30 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t; + process job[] = new [8]; + bit is_alloc = 0; + + initial begin + foreach (job[j]) fork + begin + $write("job started\n"); + job[j] = process::self(); + end + join_none + foreach (job[j]) begin + is_alloc = !!job[j]; + wait (is_alloc); + end + $write("all jobs started\n"); + foreach (job[j]) begin + job[j].await(); + end + $write("all jobs finished\n"); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_process_kill.pl b/test_regress/t/t_process_kill.pl new file mode 100755 index 000000000..1db13024b --- /dev/null +++ b/test_regress/t/t_process_kill.pl @@ -0,0 +1,27 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 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); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--timing"], + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_process_kill.v b/test_regress/t/t_process_kill.v new file mode 100644 index 000000000..8c0252939 --- /dev/null +++ b/test_regress/t/t_process_kill.v @@ -0,0 +1,31 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + process p; + bit s = 0; + + initial begin + wait (s); + p.kill(); + p.await(); + $write("*-* All Finished *-*\n"); + $finish; + end + + always @(posedge clk) begin + if (!p) begin + p = process::self(); + s = 1; + end else begin + $stop; + end + end +endmodule diff --git a/test_regress/t/t_process_notiming.out b/test_regress/t/t_process_notiming.out new file mode 100644 index 000000000..833040f13 --- /dev/null +++ b/test_regress/t/t_process_notiming.out @@ -0,0 +1,54 @@ +%Error-NOTIMING: t/t_process.v:26:20: process::self() requires --timing + : ... In instance t + 26 | p = process::self(); + | ^~~~ + ... For error description see https://verilator.org/warn/NOTIMING?v=latest +%Error-NOTIMING: t/t_process.v:27:13: process::status() requires --timing + : ... In instance t + 27 | if (p.status() != process::RUNNING) $stop; + | ^~~~~~ +%Error-NOTIMING: t/t_process.v:28:13: process::status() requires --timing + : ... In instance t + 28 | if (p.status() == process::WAITING) $stop; + | ^~~~~~ +%Error-NOTIMING: t/t_process.v:29:13: process::status() requires --timing + : ... In instance t + 29 | if (p.status() == process::SUSPENDED) $stop; + | ^~~~~~ +%Error-NOTIMING: t/t_process.v:30:13: process::status() requires --timing + : ... In instance t + 30 | if (p.status() == process::KILLED) $stop; + | ^~~~~~ +%Error-NOTIMING: t/t_process.v:31:13: process::status() requires --timing + : ... In instance t + 31 | if (p.status() == process::FINISHED) $stop; + | ^~~~~~ +%Error-NOTIMING: t/t_process.v:33:16: process::kill() requires --timing + : ... In instance t + 33 | if (0) p.kill(); + | ^~~~ +%Error-NOTIMING: t/t_process.v:34:16: process::await() requires --timing + : ... In instance t + 34 | if (0) p.await(); + | ^~~~~ +%Error-NOTIMING: t/t_process.v:35:16: process::suspend() requires --timing + : ... In instance t + 35 | if (0) p.suspend(); + | ^~~~~~~ +%Error-NOTIMING: t/t_process.v:36:16: process::resume() requires --timing + : ... In instance t + 36 | if (0) p.resume(); + | ^~~~~~ +%Error-NOTIMING: t/t_process.v:38:9: process::srandom() requires --timing + : ... In instance t + 38 | p.srandom(0); + | ^~~~~~~ +%Error-NOTIMING: t/t_process.v:39:25: process::get_randstate() requires --timing + : ... In instance t + 39 | p.set_randstate(p.get_randstate()); + | ^~~~~~~~~~~~~ +%Error-NOTIMING: t/t_process.v:39:9: process::set_randstate() requires --timing + : ... In instance t + 39 | p.set_randstate(p.get_randstate()); + | ^~~~~~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_process_notiming.pl b/test_regress/t/t_process_notiming.pl new file mode 100755 index 000000000..9a1abce98 --- /dev/null +++ b/test_regress/t/t_process_notiming.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 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +top_filename("t/t_process.v"); + +compile( + expect_filename => $Self->{golden_filename}, + v_flags2 => ["+define+T_PROCESS+std::process", "--no-timing"], + fails => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_process_rand.pl b/test_regress/t/t_process_rand.pl new file mode 100755 index 000000000..95e68c03f --- /dev/null +++ b/test_regress/t/t_process_rand.pl @@ -0,0 +1,27 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + v_flags2 => ["--timing"], + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_process_rand.v b/test_regress/t/t_process_rand.v new file mode 100644 index 000000000..20978fc04 --- /dev/null +++ b/test_regress/t/t_process_rand.v @@ -0,0 +1,52 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t; + process p; + + integer seed; + string state; + int a; + int b; + + initial begin + p = process::self(); + + // Test setting RNG state with state string + state = p.get_randstate(); + p.set_randstate(state); + a = $random; + p.set_randstate(state); + b = $random; + $display("a=%d, b=%d", a, b); + if (a != b) $stop; + + // Test the same with $urandom + state = p.get_randstate(); + p.set_randstate(state); + a = $urandom; + p.set_randstate(state); + b = $urandom; + $display("a=%d, b=%d", a, b); + if (a != b) $stop; + + // Test if the results repeat after the state is reset + state = p.get_randstate(); + for (int i = 0; i < 10; i++) + $random; + a = $random; + // Now reset the state and take 11th result again + p.set_randstate(state); + for (int i = 0; i < 10; i++) + $random; + b = $random; + $display("a=%d, b=%d", a, b); + if (a != b) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_process_std.pl b/test_regress/t/t_process_std.pl index 64cabbccb..d270c22a7 100755 --- a/test_regress/t/t_process_std.pl +++ b/test_regress/t/t_process_std.pl @@ -12,15 +12,18 @@ scenarios(simulator => 1); top_filename("t/t_process.v"); -compile( - v_flags2 => ["+define+T_PROCESS+std::process"], - ); +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + v_flags2 => ["+define+T_PROCESS+std::process", "--timing"], + ); -execute( - check_finished => !$Self->{vlt_all}, - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, - ); + execute( + check_finished => 1, + ) if !$Self->{vlt_all}; +} ok(1); 1; From 0e24f36fef0cf13d1e3c07196d3e9280fefc64f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Boro=C5=84ski?= <94375110+kboronski-ant@users.noreply.github.com> Date: Thu, 1 Jun 2023 17:49:27 +0200 Subject: [PATCH 101/129] Use STATIC lifetime for variables created from clocking items (#4262) Signed-off-by: Krzysztof Boronski --- src/V3LinkDot.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index eeb29ba06..8bfefe137 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1174,6 +1174,7 @@ class LinkDotFindVisitor final : public VNVisitor { } AstVar* const newvarp = new AstVar{nodep->fileline(), VVarType::MODULETEMP, varname, VFlagChildDType{}, dtypep}; + newvarp->lifetime(VLifetime::STATIC); nodep->varp(newvarp); iterate(nodep->exprp()); } From 545caba72048cc813262eb29c4c4c6f8c2ab14b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Boro=C5=84ski?= <94375110+kboronski-ant@users.noreply.github.com> Date: Fri, 2 Jun 2023 17:16:42 +0200 Subject: [PATCH 102/129] Give iterated variables in foreach loops VAUTOM lifetimes (#4265) Signed-off-by: Krzysztof Boronski --- src/V3Width.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 9ff2f067e..a61445ab5 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -4680,6 +4680,7 @@ private: FileLine* const fl = varp->fileline(); auto* const whilep = new AstWhile{ fl, condp, bodysp, new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, incp}}; + varp->lifetime(VLifetime::AUTOMATIC); AstNode* const stmtsp = varp; // New statements for under new Begin stmtsp->addNext(new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, leftp}); stmtsp->addNext(whilep); From 45f064f7cbc1974a47e22659a72224ce94bf3511 Mon Sep 17 00:00:00 2001 From: Jiamin Zhu <43701209+Jomit626@users.noreply.github.com> Date: Sat, 3 Jun 2023 21:40:23 +0800 Subject: [PATCH 103/129] Fix missing assignment for wide class members. (#4267) --- src/V3EmitCFunc.h | 1 + test_regress/t/t_class_wide.pl | 21 +++++++++++++++++++++ test_regress/t/t_class_wide.v | 29 +++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100755 test_regress/t/t_class_wide.pl create mode 100644 test_regress/t/t_class_wide.v diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 3a4f0c683..be40a5f53 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -354,6 +354,7 @@ public: && !VN_IS(nodep->rhsp(), CMethodHard) // && !VN_IS(nodep->rhsp(), VarRef) // && !VN_IS(nodep->rhsp(), AssocSel) // + && !VN_IS(nodep->rhsp(), MemberSel) // && !VN_IS(nodep->rhsp(), StructSel) // && !VN_IS(nodep->rhsp(), ArraySel)) { // Wide functions assign into the array directly, don't need separate assign statement diff --git a/test_regress/t/t_class_wide.pl b/test_regress/t/t_class_wide.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_class_wide.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_wide.v b/test_regress/t/t_class_wide.v new file mode 100644 index 000000000..a61944960 --- /dev/null +++ b/test_regress/t/t_class_wide.v @@ -0,0 +1,29 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Jomit626. +// SPDX-License-Identifier: CC0-1.0 + +`ifndef WIDTH +`define WIDTH 128 +`endif + +class item; + bit [`WIDTH-1:0] data; +endclass + +module t (); + logic [`WIDTH-1:0] data; + item item0 = new; + + initial begin + item0.data = `WIDTH'hda7ada7a; + data = item0.data; + + if (data != `WIDTH'hda7ada7a) + $stop(); + + $write("*-* All Finished *-*\n"); + $finish(); + end +endmodule From dc34968fe7740441688d3aefea3a6f658a47e701 Mon Sep 17 00:00:00 2001 From: John Wehle <46985578+jlwehle@users.noreply.github.com> Date: Sat, 3 Jun 2023 10:07:39 -0400 Subject: [PATCH 104/129] Add class specific same methods for AstVarScope, AstVar, and AstScope (#4203) (#4250) --- docs/CONTRIBUTORS | 1 + src/V3AstNodeOther.h | 3 ++ src/V3AstNodes.cpp | 16 +++++++ test_regress/t/t_cxx_equal_to.pl | 32 ++++++++++++++ test_regress/t/t_cxx_equal_to.v | 74 ++++++++++++++++++++++++++++++++ 5 files changed, 126 insertions(+) create mode 100755 test_regress/t/t_cxx_equal_to.pl create mode 100644 test_regress/t/t_cxx_equal_to.v diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index d82c05948..86fa68c5a 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -74,6 +74,7 @@ Jiuyang Liu Joey Liu John Coiner John Demme +John Wehle Jiamin Zhu Jonathan Drolet Jose Loyola diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 497b545cb..4a284b233 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -1376,6 +1376,7 @@ public: string name() const override VL_MT_STABLE { return m_name; } // * = Scope name void name(const string& name) override { m_name = name; } void dump(std::ostream& str) const override; + bool same(const AstNode* samep) const override; string nameDotless() const; string nameVlSym() const { return string{"vlSymsp->"} + nameDotless(); } AstNodeModule* modp() const { return m_modp; } @@ -1775,6 +1776,7 @@ public: } ASTGEN_MEMBERS_AstVar; void dump(std::ostream& str) const override; + bool same(const AstNode* samep) const override; string name() const override VL_MT_STABLE VL_MT_SAFE { return m_name; } // * = Var name bool hasDType() const override { return true; } bool maybePointedTo() const override { return true; } @@ -2017,6 +2019,7 @@ public: bool maybePointedTo() const override { return true; } string name() const override VL_MT_STABLE { return scopep()->name() + "->" + varp()->name(); } void dump(std::ostream& str) const override; + bool same(const AstNode* samep) const override; bool hasDType() const override { return true; } AstVar* varp() const VL_MT_STABLE { return m_varp; } // [After Link] Pointer to variable AstScope* scopep() const VL_MT_STABLE { return m_scopep; } // Pointer to scope it's under diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index ab7225d87..2ded5d043 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -2066,6 +2066,10 @@ void AstVarScope::dump(std::ostream& str) const { str << " ->UNLINKED"; } } +bool AstVarScope::same(const AstNode* samep) const { + const AstVarScope* const asamep = static_cast(samep); + return varp()->same(asamep->varp()) && scopep()->same(asamep->scopep()); +} void AstNodeVarRef::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep()); @@ -2129,12 +2133,24 @@ void AstVar::dump(std::ostream& str) const { if (!lifetime().isNone()) str << " [" << lifetime().ascii() << "] "; str << " " << varType(); } +bool AstVar::same(const AstNode* samep) const { + const AstVar* const asamep = static_cast(samep); + return name() == asamep->name() + && varType() == asamep->varType(); +} void AstScope::dump(std::ostream& str) const { this->AstNode::dump(str); str << " [abovep=" << reinterpret_cast(aboveScopep()) << "]"; str << " [cellp=" << reinterpret_cast(aboveCellp()) << "]"; str << " [modp=" << reinterpret_cast(modp()) << "]"; } +bool AstScope::same(const AstNode* samep) const { + const AstScope* const asamep = static_cast(samep); + return name() == asamep->name() + && ((!aboveScopep() && !asamep->aboveScopep()) + || (aboveScopep() && asamep->aboveScopep() + && aboveScopep()->name() == asamep->aboveScopep()->name())); +} void AstScopeName::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); if (dpiExport()) str << " [DPIEX]"; diff --git a/test_regress/t/t_cxx_equal_to.pl b/test_regress/t/t_cxx_equal_to.pl new file mode 100755 index 000000000..5ac57f398 --- /dev/null +++ b/test_regress/t/t_cxx_equal_to.pl @@ -0,0 +1,32 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 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); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + top_filename("t/t_cxx_equal_to.v"); + + compile( + verilator_flags2 => ['--binary --timing --trace'], + verilator_make_cmake => 0, + verilator_make_gmake => 0, + make_main => 0, + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_cxx_equal_to.v b/test_regress/t/t_cxx_equal_to.v new file mode 100644 index 000000000..e35c8d6d6 --- /dev/null +++ b/test_regress/t/t_cxx_equal_to.v @@ -0,0 +1,74 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// On some platforms (i.e. FreeBSD 12) this triggered: +// +// Active region did not converge. +// +// due to the mistaken belief that the AstVarScope node for TOP->t__DOT__clk +// is equal to the AstVarScope node for TOP->t__DOT__rst. This occured because +// AstVarScope was missing an appropriate same method and is tickled by the LLVM +// libcxx library. +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by John Wehle. +// SPDX-License-Identifier: CC0-1.0 + +module t; + + wire [1:0] out; + reg in; + reg rst; + reg clk; + + initial begin + clk = 0; + rst = 0; + + #10 rst = 1; + #10 rst = 0; + + in = 1'b0; + + #30 $write("*-* All Finished *-*\n"); + $finish; + end + + always begin + #10 clk <= !clk; + end + + Test test(.out(out), .in(in), + .clk(clk), .rst(rst)); +endmodule + + +module Test(/*AUTOARG*/ + // Outputs + out, + // Inputs + clk, in, rst + ); + + input clk; + input in; + input rst; + output wire [1:0] out; + + reg [1:0] s; + reg sin; + + assign out = s; + + always @(posedge clk) + begin + s[1] <= in; + s[0] <= sin; + end + + always @(negedge clk, posedge rst) + if (rst) + sin <= 1'b0; + else + sin <= in; + +endmodule From a7b0551d23abbca9a87c0d67b1a0d6a812085b85 Mon Sep 17 00:00:00 2001 From: github action Date: Sat, 3 Jun 2023 14:11:23 +0000 Subject: [PATCH 105/129] Apply 'make format' --- src/V3AstNodes.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 2ded5d043..45a99e7ce 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -2135,8 +2135,7 @@ void AstVar::dump(std::ostream& str) const { } bool AstVar::same(const AstNode* samep) const { const AstVar* const asamep = static_cast(samep); - return name() == asamep->name() - && varType() == asamep->varType(); + return name() == asamep->name() && varType() == asamep->varType(); } void AstScope::dump(std::ostream& str) const { this->AstNode::dump(str); From d8c2ecaaf8400642c1282e9eda90661c6f5a48b7 Mon Sep 17 00:00:00 2001 From: Andrei Kostovski <58448051+andkostov@users.noreply.github.com> Date: Sat, 3 Jun 2023 10:31:17 -0400 Subject: [PATCH 106/129] Commentary: Update install.rst for help2man (#4260) (#4261) --- docs/CONTRIBUTORS | 1 + docs/guide/install.rst | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 86fa68c5a..56b9cd782 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -12,6 +12,7 @@ Alex Chadwick Aliaksei Chapyzhenka Ameya Vikram Singh Andreas Kuster +Andrei Kostovski Andrew Nolte Arkadiusz Kozdra Aylon Chaim Porat diff --git a/docs/guide/install.rst b/docs/guide/install.rst index a862b4abb..258389ec2 100644 --- a/docs/guide/install.rst +++ b/docs/guide/install.rst @@ -39,7 +39,7 @@ In brief, to install from git: :: # Prerequisites: - #sudo apt-get install git help2man perl python3 make autoconf g++ flex bison ccache + #sudo apt-get install git help2man perl python3 make autoconf g++ flex bison ccache help2man #sudo apt-get install libgoogle-perftools-dev numactl perl-doc #sudo apt-get install libfl2 # Ubuntu only (ignore if gives error) #sudo apt-get install libfl-dev # Ubuntu only (ignore if gives error) From 191d30cf1ca5a6cffac9992c6b532569fa2dab65 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 3 Jun 2023 12:10:07 -0400 Subject: [PATCH 107/129] Update gtkwave from upstream (#4141) --- include/gtkwave/fstapi.c | 46 ++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/include/gtkwave/fstapi.c b/include/gtkwave/fstapi.c index df8b23866..205e43952 100644 --- a/include/gtkwave/fstapi.c +++ b/include/gtkwave/fstapi.c @@ -2052,7 +2052,8 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) int zfd; int fourpack_duo = 0; #ifndef __MINGW32__ - char *fnam = (char *)malloc(strlen(xc->filename) + 5 + 1); + int fnam_len = strlen(xc->filename) + 5 + 1; + char *fnam = (char *)malloc(fnam_len); #endif fixup_offs = ftello(xc->handle); @@ -2142,7 +2143,7 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) fflush(xc->handle); #ifndef __MINGW32__ - sprintf(fnam, "%s.hier", xc->filename); + snprintf(fnam, fnam_len, "%s.hier", xc->filename); unlink(fnam); free(fnam); #endif @@ -2821,7 +2822,7 @@ if(ctx && name && literal_arr && val_arr && (elem_count != 0)) uint32_t i; name_len = strlen(name); - elem_count_len = sprintf(elem_count_buf, "%" PRIu32, elem_count); + elem_count_len = snprintf(elem_count_buf, 16, "%" PRIu32, elem_count); literal_lens = (unsigned int *)calloc(elem_count, sizeof(unsigned int)); val_lens = (unsigned int *)calloc(elem_count, sizeof(unsigned int)); @@ -3909,7 +3910,8 @@ int pass_status = 1; if(!xc->fh) { fst_off_t offs_cache = ftello(xc->f); - char *fnam = (char *)malloc(strlen(xc->filename) + 6 + 16 + 32 + 1); + int fnam_len = strlen(xc->filename) + 6 + 16 + 32 + 1; + char *fnam = (char *)malloc(fnam_len); unsigned char *mem = (unsigned char *)malloc(FST_GZIO_LEN); fst_off_t hl, uclen; fst_off_t clen = 0; @@ -3928,7 +3930,7 @@ if(!xc->fh) htyp = xc->contains_hier_section_lz4duo ? FST_BL_HIER_LZ4DUO : FST_BL_HIER_LZ4; } - sprintf(fnam, "%s.hier_%d_%p", xc->filename, getpid(), (void *)xc); + snprintf(fnam, fnam_len, "%s.hier_%d_%p", xc->filename, getpid(), (void *)xc); fstReaderFseeko(xc, xc->f, xc->hier_pos, SEEK_SET); uclen = fstReaderUint64(xc->f); #ifndef __MINGW32__ @@ -4585,15 +4587,17 @@ if(sectype == FST_BL_ZWRAPPER) int zfd; int flen = strlen(xc->filename); char *hf; + int hf_len; seclen = fstReaderUint64(xc->f); uclen = fstReaderUint64(xc->f); if(!seclen) return(0); /* not finished compressing, this is a failed read */ - hf = (char *)calloc(1, flen + 16 + 32 + 1); + hf_len = flen + 16 + 32 + 1; + hf = (char *)calloc(1, hf_len); - sprintf(hf, "%s.upk_%d_%p", xc->filename, getpid(), (void *)xc); + snprintf(hf, hf_len, "%s.upk_%d_%p", xc->filename, getpid(), (void *)xc); fcomp = fopen(hf, "w+b"); if(!fcomp) { @@ -5189,16 +5193,16 @@ for(;;) if(beg_tim) { - if(dumpvars_state == 1) { wx_len = sprintf(wx_buf, "$end\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 2; } - wx_len = sprintf(wx_buf, "#%" PRIu64 "\n", beg_tim); + if(dumpvars_state == 1) { wx_len = snprintf(wx_buf, 32, "$end\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 2; } + wx_len = snprintf(wx_buf, 32, "#%" PRIu64 "\n", beg_tim); fstWritex(xc, wx_buf, wx_len); - if(!dumpvars_state) { wx_len = sprintf(wx_buf, "$dumpvars\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 1; } + if(!dumpvars_state) { wx_len = snprintf(wx_buf, 32, "$dumpvars\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 1; } } if((xc->num_blackouts)&&(cur_blackout != xc->num_blackouts)) { if(beg_tim == xc->blackout_times[cur_blackout]) { - wx_len = sprintf(wx_buf, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off"); + wx_len = snprintf(wx_buf, 32, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off"); fstWritex(xc, wx_buf, wx_len); } } @@ -5332,7 +5336,7 @@ for(;;) clone_d[j] = srcdata[7-j]; } } - sprintf((char *)xc->temp_signal_value_buf, "%.16g", d); + snprintf((char *)xc->temp_signal_value_buf, xc->longest_signal_value_len + 1, "%.16g", d); value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf); } } @@ -5360,7 +5364,7 @@ for(;;) } fstVcdID(vcdid_buf, idx+1); - wx_len = sprintf(wx_buf, "r%.16g %s\n", d, vcdid_buf); + wx_len = snprintf(wx_buf, 64, "r%.16g %s\n", d, vcdid_buf); fstWritex(xc, wx_buf, wx_len); } } @@ -5625,16 +5629,16 @@ for(;;) } } - if(dumpvars_state == 1) { wx_len = sprintf(wx_buf, "$end\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 2; } - wx_len = sprintf(wx_buf, "#%" PRIu64 "\n", time_table[i]); + if(dumpvars_state == 1) { wx_len = snprintf(wx_buf, 32, "$end\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 2; } + wx_len = snprintf(wx_buf, 32, "#%" PRIu64 "\n", time_table[i]); fstWritex(xc, wx_buf, wx_len); - if(!dumpvars_state) { wx_len = sprintf(wx_buf, "$dumpvars\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 1; } + if(!dumpvars_state) { wx_len = snprintf(wx_buf, 32, "$dumpvars\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 1; } if((xc->num_blackouts)&&(cur_blackout != xc->num_blackouts)) { if(time_table[i] == xc->blackout_times[cur_blackout]) { - wx_len = sprintf(wx_buf, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off"); + wx_len = snprintf(wx_buf, 32, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off"); fstWritex(xc, wx_buf, wx_len); } } @@ -5884,7 +5888,7 @@ for(;;) clone_d[j] = srcdata[7-j]; } } - sprintf((char *)xc->temp_signal_value_buf, "%.16g", d); + snprintf((char *)xc->temp_signal_value_buf, xc->longest_signal_value_len + 1, "%.16g", d); value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf); } } @@ -5910,7 +5914,7 @@ for(;;) } } - wx_len = sprintf(wx_buf, "r%.16g", d); + wx_len = snprintf(wx_buf, 32, "r%.16g", d); fstWritex(xc, wx_buf, wx_len); } } @@ -6016,7 +6020,7 @@ if(xc->signal_lens[facidx] == 1) } } - sprintf((char *)buf, "%.16g", d); + snprintf((char *)buf, 32, "%.16g", d); /* this will write 18 bytes */ } } @@ -6608,7 +6612,7 @@ if(xc->signal_lens[facidx] == 1) } } - sprintf(buf, "r%.16g", d); + snprintf(buf, 32, "r%.16g", d); /* this will write 19 bytes */ return(buf); } } From 5aa36357f61210495a224268f4812177e5c0e75e Mon Sep 17 00:00:00 2001 From: Mariusz Glebocki Date: Tue, 6 Jun 2023 00:53:19 +0200 Subject: [PATCH 108/129] Internals: Use `auto` instead of SFINAE in return type (#4271). No functional change intended. --- src/V3ThreadPool.h | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src/V3ThreadPool.h b/src/V3ThreadPool.h index 1f4f32f95..3a97d7888 100644 --- a/src/V3ThreadPool.h +++ b/src/V3ThreadPool.h @@ -27,19 +27,6 @@ #include #include -namespace future_type { -template -struct return_type { - typedef std::list type; -}; - -template <> -struct return_type { - typedef void type; -}; - -} // namespace future_type - //============================================================================ class V3ThreadPool final { @@ -124,8 +111,7 @@ public: // specialization as C++11 requires them to be inside namespace scope // Returns list of future result or void template - static typename future_type::return_type::type - waitForFutures(std::list>& futures) { + static auto waitForFutures(std::list>& futures) { return waitForFuturesImp(futures); } @@ -133,9 +119,8 @@ public: private: template - static typename future_type::return_type::type - waitForFuturesImp(std::list>& futures) { - typename future_type::return_type::type results; + static std::list waitForFuturesImp(std::list>& futures) { + std::list results; while (!futures.empty()) { results.push_back(V3ThreadPool::waitForFuture(futures.front())); futures.pop_front(); From 186c851695e77ce3c7f196b72cc4acd1c5573568 Mon Sep 17 00:00:00 2001 From: Mariusz Glebocki Date: Tue, 6 Jun 2023 01:40:36 +0200 Subject: [PATCH 109/129] Internals: Avoid pessimistic mutex locking in waitIfStopRequested() (#4272). No functional change intended. `stopRequested()` reads only atomic variables. It doesn't need a mutex to do this. This function is called in `waitIfStopRequested()`, which in turn is called before execution of every job, and inside some jobs. With this change the mutex inside `waitIfStopRequested` needs to be locked only in very rare cases instead of every time. --- src/V3ThreadPool.cpp | 6 +++--- src/V3ThreadPool.h | 9 ++------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/V3ThreadPool.cpp b/src/V3ThreadPool.cpp index 678270a13..63469681a 100644 --- a/src/V3ThreadPool.cpp +++ b/src/V3ThreadPool.cpp @@ -68,7 +68,7 @@ void V3ThreadPool::workerJobLoop(int id) VL_MT_SAFE { return !m_queue.empty() || m_shutdown || m_stopRequested; }); if (m_shutdown) return; // Terminate if requested - if (stopRequestedStandalone()) { continue; } + if (stopRequested()) { continue; } // Get the job UASSERT(!m_queue.empty(), "Job should be available"); @@ -115,9 +115,9 @@ void V3ThreadPool::requestExclusiveAccess(const V3ThreadPool::job_t&& exclusiveA } } -bool V3ThreadPool::waitIfStopRequested() VL_MT_SAFE { - V3LockGuard stoppedJobLock(m_stoppedJobsMutex); +bool V3ThreadPool::waitIfStopRequested() VL_MT_SAFE VL_EXCLUDES(m_stoppedJobsMutex) { if (!stopRequested()) return false; + V3LockGuard stoppedJobLock(m_stoppedJobsMutex); waitStopRequested(); return true; } diff --git a/src/V3ThreadPool.h b/src/V3ThreadPool.h index 3a97d7888..d87d5be17 100644 --- a/src/V3ThreadPool.h +++ b/src/V3ThreadPool.h @@ -93,7 +93,7 @@ public: // Check if other thread requested exclusive access to processing, // if so, it waits for it to complete. Afterwards it is resumed. // Returns true if request was send and we waited, otherwise false - bool waitIfStopRequested() VL_MT_SAFE; + bool waitIfStopRequested() VL_MT_SAFE VL_EXCLUDES(m_stoppedJobsMutex); // Waits for future. // This function can be interupted by exclusive access request. @@ -139,17 +139,12 @@ private: } // True when any thread requested exclusive access - bool stopRequested() const VL_REQUIRES(m_stoppedJobsMutex) { + bool stopRequested() const VL_MT_SAFE { // don't wait if shutdown already requested if (m_shutdown) return false; return m_stopRequested; } - bool stopRequestedStandalone() VL_MT_SAFE_EXCLUDES(m_stoppedJobsMutex) { - const V3LockGuard lock{m_stoppedJobsMutex}; - return stopRequested(); - } - // Waits until exclusive access job completes its job void waitStopRequested() VL_REQUIRES(m_stoppedJobsMutex); From 058233fc87d45a47a1625c08b8a97a46afa0a855 Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Tue, 6 Jun 2023 15:35:12 +0200 Subject: [PATCH 110/129] Set the global `usesTiming` flag if forks exist (#4274) --- src/V3Timing.cpp | 7 +++++ .../t/t_timing_fork_no_timing_ctrl.pl | 28 +++++++++++++++++++ test_regress/t/t_timing_fork_no_timing_ctrl.v | 15 ++++++++++ 3 files changed, 50 insertions(+) create mode 100755 test_regress/t/t_timing_fork_no_timing_ctrl.pl create mode 100644 test_regress/t/t_timing_fork_no_timing_ctrl.v diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index fa9305000..fc2d06029 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -216,6 +216,13 @@ private: m_procp = nodep; iterateChildren(nodep); } + void visit(AstFork* nodep) override { + v3Global.setUsesTiming(); // Even if there are no event controls, we have to set this flag + // so that transformForks() in V3SchedTiming gets called and + // removes all forks and begins + if (nodep->isTimingControl() && m_procp) m_procp->user2(T_SUSP); + iterateChildren(nodep); + } void visit(AstNode* nodep) override { if (nodep->isTimingControl()) { v3Global.setUsesTiming(); diff --git a/test_regress/t/t_timing_fork_no_timing_ctrl.pl b/test_regress/t/t_timing_fork_no_timing_ctrl.pl new file mode 100755 index 000000000..439181d0a --- /dev/null +++ b/test_regress/t/t_timing_fork_no_timing_ctrl.pl @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 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); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_fork_no_timing_ctrl.v b/test_regress/t/t_timing_fork_no_timing_ctrl.v new file mode 100644 index 000000000..2f9bb387c --- /dev/null +++ b/test_regress/t/t_timing_fork_no_timing_ctrl.v @@ -0,0 +1,15 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t; + initial + fork + begin + $write("*-* All Finished *-*\n"); + $finish; + end + join_none +endmodule From c3e5db5f04826d9c50485616da3e869cf7ab3e94 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Tue, 6 Jun 2023 16:24:42 +0200 Subject: [PATCH 111/129] Fix names of foreach blocks (#4264) --- src/V3LinkDot.cpp | 26 +++++++++++++------------- test_regress/t/t_foreach_blkname.v | 3 +++ test_regress/t/t_randcase_bad.out | 2 +- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 8bfefe137..378942655 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -158,9 +158,7 @@ private: std::array m_scopeAliasMap; // Map of aliases std::vector m_ifaceVarSyms; // List of AstIfaceRefDType's to be imported IfaceModSyms m_ifaceModSyms; // List of AstIface+Symbols to be processed - bool m_forPrimary; // First link - bool m_forPrearray; // Compress cell__[array] refs - bool m_forScopeCreation; // Remove VarXRefs for V3Scope + const VLinkDotStep m_step; // Operational step public: // METHODS @@ -202,11 +200,9 @@ public: // CONSTRUCTORS LinkDotState(AstNetlist* rootp, VLinkDotStep step) - : m_syms{rootp} { + : m_syms{rootp} + , m_step(step) { UINFO(4, __FUNCTION__ << ": " << endl); - m_forPrimary = (step == LDS_PRIMARY); - m_forPrearray = (step == LDS_PARAMED || step == LDS_PRIMARY); - m_forScopeCreation = (step == LDS_SCOPED); s_errorThisp = this; V3Error::errorExitCb(preErrorDumpHandler); // If get error, dump self } @@ -217,9 +213,10 @@ public: // ACCESSORS VSymGraph* symsp() { return &m_syms; } - bool forPrimary() const { return m_forPrimary; } - bool forPrearray() const { return m_forPrearray; } - bool forScopeCreation() const { return m_forScopeCreation; } + int stepNumber() const { return int(m_step); } + bool forPrimary() const { return m_step == LDS_PRIMARY; } + bool forPrearray() const { return m_step == LDS_PARAMED || m_step == LDS_PRIMARY; } + bool forScopeCreation() const { return m_step == LDS_SCOPED; } // METHODS static string nodeTextType(AstNode* nodep) { @@ -590,7 +587,7 @@ public: baddot = ident; // So user can see where they botched it okSymp = lookupSymp; string altIdent; - if (m_forPrearray) { + if (forPrearray()) { // GENFOR Begin is foo__BRA__##__KET__ after we've genloop unrolled, // but presently should be just "foo". // Likewise cell foo__[array] before we've expanded arrays is just foo @@ -620,7 +617,7 @@ public: else if (ident == "$root") { lookupSymp = rootEntp(); // We've added the '$root' module, now everything else is one lower - if (!m_forPrearray) { + if (!forPrearray()) { lookupSymp = lookupSymp->findIdFlat(ident); UASSERT(lookupSymp, "Cannot find $root module under netlist"); } @@ -1017,9 +1014,12 @@ class LinkDotFindVisitor final : public VNVisitor { for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { if (VN_IS(stmtp, Var) || VN_IS(stmtp, Foreach)) { std::string name; + const std::string stepStr = m_statep->forPrimary() + ? "" + : std::to_string(m_statep->stepNumber()) + "_"; do { ++m_modBlockNum; - name = "unnamedblk" + cvtToStr(m_modBlockNum); + name = "unnamedblk" + stepStr + cvtToStr(m_modBlockNum); // Increment again if earlier pass of V3LinkDot claimed this name } while (m_curSymp->findIdFlat(name)); nodep->name(name); diff --git a/test_regress/t/t_foreach_blkname.v b/test_regress/t/t_foreach_blkname.v index 768e7697f..3eceb8a3c 100644 --- a/test_regress/t/t_foreach_blkname.v +++ b/test_regress/t/t_foreach_blkname.v @@ -12,5 +12,8 @@ module t; end foreach (a[i]) begin end + begin + int x; + end endfunction endmodule diff --git a/test_regress/t/t_randcase_bad.out b/test_regress/t/t_randcase_bad.out index 4e3daeeac..6d1b58341 100644 --- a/test_regress/t/t_randcase_bad.out +++ b/test_regress/t/t_randcase_bad.out @@ -1,2 +1,2 @@ -[0] %Error: t_randcase_bad.v:12: Assertion failed in top.t.unnamedblk1: All randcase items had 0 weights (IEEE 1800-2017 18.16) +[0] %Error: t_randcase_bad.v:12: Assertion failed in top.t.unnamedblk2_1: All randcase items had 0 weights (IEEE 1800-2017 18.16) *-* All Finished *-* From c2483189580e0c0b9ba87a9087d1a1032ba5c011 Mon Sep 17 00:00:00 2001 From: Aleksander Kiryk Date: Tue, 6 Jun 2023 15:28:35 -0700 Subject: [PATCH 112/129] Fix struct redefinition (#4276) --- src/V3Class.cpp | 6 ++++-- test_regress/t/t_unpacked_struct_redef.pl | 21 ++++++++++++++++++ test_regress/t/t_unpacked_struct_redef.v | 26 +++++++++++++++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_unpacked_struct_redef.pl create mode 100644 test_regress/t/t_unpacked_struct_redef.v diff --git a/src/V3Class.cpp b/src/V3Class.cpp index f318048f8..3653b8b2d 100644 --- a/src/V3Class.cpp +++ b/src/V3Class.cpp @@ -27,6 +27,7 @@ #include "V3Ast.h" #include "V3Global.h" +#include "V3UniqueNames.h" VL_DEFINE_DEBUG_FUNCTIONS; @@ -41,6 +42,7 @@ private: // MEMBERS string m_prefix; // String prefix to add to name based on hier + V3UniqueNames m_names; // For unique naming of structs and unions AstNodeModule* m_modp = nullptr; // Current module AstNodeModule* m_classPackagep = nullptr; // Package moving into const AstScope* m_classScopep = nullptr; // Package moving scopes into @@ -181,8 +183,8 @@ private: // Give struct a pointer to its package and a final name dtypep->editCountInc(); dtypep->classOrPackagep(m_classPackagep ? m_classPackagep : m_modp); - dtypep->name(dtypep->name() + (VN_IS(dtypep, UnionDType) ? "__union" : "__struct") - + cvtToStr(dtypep->uniqueNum())); + dtypep->name( + m_names.get(dtypep->name() + (VN_IS(dtypep, UnionDType) ? "__union" : "__struct"))); for (const AstMemberDType* itemp = dtypep->membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) { diff --git a/test_regress/t/t_unpacked_struct_redef.pl b/test_regress/t/t_unpacked_struct_redef.pl new file mode 100755 index 000000000..859050d63 --- /dev/null +++ b/test_regress/t/t_unpacked_struct_redef.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 2023 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_unpacked_struct_redef.v b/test_regress/t/t_unpacked_struct_redef.v new file mode 100644 index 000000000..931177607 --- /dev/null +++ b/test_regress/t/t_unpacked_struct_redef.v @@ -0,0 +1,26 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Class#(parameter WIDTH); + typedef logic [WIDTH-1:0] word; + typedef struct { + word w; + } Struct; +endclass + +module t; + Class#(1)::Struct s1; + Class#(1)::Struct s2; + Class#(2)::Struct s3; + + initial begin + $display("%p", s1); + $display("%p", s2); + $display("%p", s3); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From 6cb0335d285329b1cf690b27304e1a2956955503 Mon Sep 17 00:00:00 2001 From: Aleksander Kiryk Date: Wed, 7 Jun 2023 04:44:21 -0700 Subject: [PATCH 113/129] Support array max (#4275) --- include/verilated_types.h | 168 +++++++++++++++++++++++- src/V3Width.cpp | 123 +++++++---------- test_regress/t/t_array_method.out | 117 ----------------- test_regress/t/t_array_method.pl | 4 +- test_regress/t/t_array_method.v | 41 +++--- test_regress/t/t_array_method_bad.out | 5 + test_regress/t/t_array_method_bad.pl | 19 +++ test_regress/t/t_array_method_bad.v | 16 +++ test_regress/t/t_array_method_unsup.out | 21 +++ test_regress/t/t_array_method_unsup.pl | 23 ++++ test_regress/t/t_array_method_unsup.v | 35 +++++ 11 files changed, 349 insertions(+), 223 deletions(-) delete mode 100644 test_regress/t/t_array_method.out create mode 100644 test_regress/t/t_array_method_bad.out create mode 100755 test_regress/t/t_array_method_bad.pl create mode 100644 test_regress/t/t_array_method_bad.v create mode 100644 test_regress/t/t_array_method_unsup.out create mode 100755 test_regress/t/t_array_method_unsup.pl create mode 100644 test_regress/t/t_array_method_unsup.v diff --git a/include/verilated_types.h b/include/verilated_types.h index 494af9be8..46a4d99b5 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -1040,9 +1040,15 @@ void VL_WRITEMEM_N(bool hex, int bits, const std::string& filename, template struct VlUnpacked final { +private: + // TYPES + using T_Key = IData; // Index type, for uniformity with other containers + using Unpacked = T_Value[T_Depth]; + +public: // MEMBERS // This should be the only data member, otherwise generated static initializers need updating - T_Value m_storage[T_Depth]; // Contents of the unpacked array + Unpacked m_storage; // Contents of the unpacked array // CONSTRUCTORS // Default constructors and destructor are used. Note however that C++20 requires that @@ -1053,6 +1059,7 @@ struct VlUnpacked final { // Default copy assignment operators are used. // METHODS +public: // Raw access WData* data() { return &m_storage[0]; } const WData* data() const { return &m_storage[0]; } @@ -1065,10 +1072,167 @@ struct VlUnpacked final { bool neq(const VlUnpacked& that) const { return neq(*this, that); } // Similar to 'neq' above, *this = that used for change detection void assign(const VlUnpacked& that) { *this = that; } - bool operator==(const VlUnpacked& that) const { return !neq(that); } bool operator!=(const VlUnpacked& that) { return neq(that); } + void sort() { std::sort(std::begin(m_storage), std::end(m_storage)); } + template + void sort(Func with_func) { + // with_func returns arbitrary type to use for the sort comparison + std::sort(std::begin(m_storage), std::end(m_storage), + [=](const T_Value& a, const T_Value& b) { + // index number is meaningless with sort, as it changes + return with_func(0, a) < with_func(0, b); + }); + } + void rsort() { std::sort(std::rbegin(m_storage), std::rend(m_storage)); } + template + void rsort(Func with_func) { + // with_func returns arbitrary type to use for the sort comparison + std::sort(std::rbegin(m_storage), std::rend(m_storage), + [=](const T_Value& a, const T_Value& b) { + // index number is meaningless with sort, as it changes + return with_func(0, a) < with_func(0, b); + }); + } + void reverse() { std::reverse(std::begin(m_storage), std::end(m_storage)); } + void shuffle() { std::shuffle(std::begin(m_storage), std::end(m_storage), VlURNG{}); } + VlQueue unique() const { + VlQueue out; + std::set saw; + for (const auto& i : m_storage) { + const auto it = saw.find(i); + if (it == saw.end()) { + saw.insert(it, i); + out.push_back(i); + } + } + return out; + } + template + VlQueue unique(Func with_func) const { + VlQueue out; + std::set saw; + for (const auto& i : m_storage) { + const auto i_mapped = with_func(0, i); + const auto it = saw.find(i_mapped); + if (it == saw.end()) { + saw.insert(it, i_mapped); + out.push_back(i); + } + } + return out; + } + VlQueue unique_index() const { + VlQueue out; + IData index = 0; + std::set saw; + for (const auto& i : m_storage) { + const auto it = saw.find(i); + if (it == saw.end()) { + saw.insert(it, i); + out.push_back(index); + } + ++index; + } + return out; + } + template + VlQueue unique_index(Func with_func) const { + VlQueue out; + IData index = 0; + std::unordered_set saw; + for (const auto& i : m_storage) { + const auto i_mapped = with_func(index, i); + auto it = saw.find(i_mapped); + if (it == saw.end()) { + saw.insert(it, i_mapped); + out.push_back(index); + } + ++index; + } + return out; + } + template + VlQueue find(Func with_func) const { + VlQueue out; + IData index = 0; + for (const auto& i : m_storage) { + if (with_func(index, i)) out.push_back(i); + ++index; + } + return out; + } + template + VlQueue find_index(Func with_func) const { + VlQueue out; + IData index = 0; + for (const auto& i : m_storage) { + if (with_func(index, i)) out.push_back(index); + ++index; + } + return out; + } + template + VlQueue find_first(Func with_func) const { + // Can't use std::find_if as need index number + IData index = 0; + for (const auto& i : m_storage) { + if (with_func(index, i)) return VlQueue::cons(i); + ++index; + } + return VlQueue{}; + } + template + VlQueue find_first_index(Func with_func) const { + IData index = 0; + for (const auto& i : m_storage) { + if (with_func(index, i)) return VlQueue::cons(index); + ++index; + } + return VlQueue{}; + } + template + VlQueue find_last(Func with_func) const { + for (int i = T_Depth - 1; i >= 0; i--) { + if (with_func(i, m_storage[i])) return VlQueue::cons(m_storage[i]); + } + return VlQueue{}; + } + template + VlQueue find_last_index(Func with_func) const { + for (int i = T_Depth - 1; i >= 0; i--) { + if (with_func(i, m_storage[i])) return VlQueue::cons(i); + } + return VlQueue{}; + } + + // Reduction operators + VlQueue min() const { + const auto it = std::min_element(std::begin(m_storage), std::end(m_storage)); + return VlQueue::cons(*it); + } + template + VlQueue min(Func with_func) const { + const auto it = std::min_element(std::begin(m_storage), std::end(m_storage), + [&with_func](const IData& a, const IData& b) { + return with_func(0, a) < with_func(0, b); + }); + return VlQueue::cons(*it); + } + VlQueue max() const { + const auto it = std::max_element(std::begin(m_storage), std::end(m_storage)); + return VlQueue::cons(*it); + } + template + VlQueue max(Func with_func) const { + const auto it = std::max_element(std::begin(m_storage), std::end(m_storage), + [&with_func](const IData& a, const IData& b) { + return with_func(0, a) < with_func(0, b); + }); + return VlQueue::cons(*it); + } + // Dumping. Verilog: str = $sformatf("%p", assoc) std::string to_string() const { std::string out = "'{"; diff --git a/src/V3Width.cpp b/src/V3Width.cpp index a61445ab5..334987da8 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -3273,36 +3273,11 @@ private: << nodep->prettyName() << "'"); } } - void methodCallDyn(AstMethodCall* nodep, AstDynArrayDType* adtypep) { + AstCMethodHard* methodCallArray(AstMethodCall* nodep, AstNodeDType* adtypep) { AstCMethodHard* newp = nullptr; - if (nodep->name() == "at") { // Created internally for [] - methodOkArguments(nodep, 1, 1); - methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); - newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), "at"}; - newp->dtypeFrom(adtypep->subDTypep()); - } else if (nodep->name() == "size") { - methodOkArguments(nodep, 0, 0); - newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), "size"}; - newp->dtypeSetSigned32(); - } else if (nodep->name() == "delete") { // function void delete() - methodOkArguments(nodep, 0, 0); - methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); - newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), "clear"}; - newp->dtypeSetVoid(); - } else if (nodep->name() == "and" || nodep->name() == "or" || nodep->name() == "xor" - || nodep->name() == "sum" || nodep->name() == "product") { - // All value return - AstWith* const withp - = methodWithArgument(nodep, false, false, adtypep->subDTypep(), - nodep->findUInt32DType(), adtypep->subDTypep()); - methodOkArguments(nodep, 0, 0); - methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); - newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), - "r_" + nodep->name(), withp}; - newp->dtypeFrom(adtypep->subDTypep()); - if (!nodep->firstAbovep()) newp->dtypeSetVoid(); - } else if (nodep->name() == "reverse" || nodep->name() == "shuffle" - || nodep->name() == "sort" || nodep->name() == "rsort") { + + if (nodep->name() == "reverse" || nodep->name() == "shuffle" || nodep->name() == "sort" + || nodep->name() == "rsort") { AstWith* withp = nullptr; if (nodep->name() == "sort" || nodep->name() == "rsort") { withp = methodWithArgument(nodep, false, true, nullptr, nodep->findUInt32DType(), @@ -3315,10 +3290,12 @@ private: newp->dtypeSetVoid(); } else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique" || nodep->name() == "unique_index") { + AstWith* const withp = methodWithArgument( + nodep, false, true, nullptr, nodep->findUInt32DType(), adtypep->subDTypep()); methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), - nodep->name()}; + nodep->name(), withp}; if (nodep->name() == "unique_index") { newp->dtypep(newp->findQueueIndexDType()); } else { @@ -3347,6 +3324,38 @@ private: nodep->name(), withp}; newp->dtypep(newp->findQueueIndexDType()); if (!nodep->firstAbovep()) newp->dtypeSetVoid(); + } + return newp; + } + void methodCallDyn(AstMethodCall* nodep, AstDynArrayDType* adtypep) { + AstCMethodHard* newp = nullptr; + if (nodep->name() == "at") { // Created internally for [] + methodOkArguments(nodep, 1, 1); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); + newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), "at"}; + newp->dtypeFrom(adtypep->subDTypep()); + } else if (nodep->name() == "size") { + methodOkArguments(nodep, 0, 0); + newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), "size"}; + newp->dtypeSetSigned32(); + } else if (nodep->name() == "delete") { // function void delete() + methodOkArguments(nodep, 0, 0); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); + newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), "clear"}; + newp->dtypeSetVoid(); + } else if (nodep->name() == "and" || nodep->name() == "or" || nodep->name() == "xor" + || nodep->name() == "sum" || nodep->name() == "product") { + // All value return + AstWith* const withp + = methodWithArgument(nodep, false, false, adtypep->subDTypep(), + nodep->findUInt32DType(), adtypep->subDTypep()); + methodOkArguments(nodep, 0, 0); + methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); + newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), + "r_" + nodep->name(), withp}; + newp->dtypeFrom(adtypep->subDTypep()); + if (!nodep->firstAbovep()) newp->dtypeSetVoid(); + } else if ((newp = methodCallArray(nodep, adtypep))) { } else { nodep->v3warn(E_UNSUPPORTED, "Unsupported/unknown built-in dynamic array method " << nodep->prettyNameQ()); @@ -3434,54 +3443,7 @@ private: "r_" + nodep->name(), withp}; newp->dtypeFrom(withp ? withp->dtypep() : adtypep->subDTypep()); if (!nodep->firstAbovep()) newp->dtypeSetVoid(); - } else if (nodep->name() == "reverse" || nodep->name() == "shuffle" - || nodep->name() == "sort" || nodep->name() == "rsort") { - AstWith* withp = nullptr; - if (nodep->name() == "sort" || nodep->name() == "rsort") { - withp = methodWithArgument(nodep, false, true, nullptr, nodep->findUInt32DType(), - adtypep->subDTypep()); - } - methodOkArguments(nodep, 0, 0); - methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); - newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), - nodep->name(), withp}; - newp->dtypeSetVoid(); - } else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique" - || nodep->name() == "unique_index") { - AstWith* const withp = methodWithArgument( - nodep, false, true, nullptr, nodep->findUInt32DType(), adtypep->subDTypep()); - methodOkArguments(nodep, 0, 0); - methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); - newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), - nodep->name(), withp}; - if (nodep->name() == "unique_index") { - newp->dtypep(newp->findQueueIndexDType()); - } else { - newp->dtypeFrom(adtypep); - } - if (!nodep->firstAbovep()) newp->dtypeSetVoid(); - } else if (nodep->name() == "find" || nodep->name() == "find_first" - || nodep->name() == "find_last") { - AstWith* const withp - = methodWithArgument(nodep, true, false, nodep->findBitDType(), - nodep->findUInt32DType(), adtypep->subDTypep()); - methodOkArguments(nodep, 0, 0); - methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); - newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), - nodep->name(), withp}; - newp->dtypeFrom(adtypep); - if (!nodep->firstAbovep()) newp->dtypeSetVoid(); - } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index" - || nodep->name() == "find_last_index") { - AstWith* const withp - = methodWithArgument(nodep, true, false, nodep->findBitDType(), - nodep->findUInt32DType(), adtypep->subDTypep()); - methodOkArguments(nodep, 0, 0); - methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); - newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), - nodep->name(), withp}; - newp->dtypep(newp->findQueueIndexDType()); - if (!nodep->firstAbovep()) newp->dtypeSetVoid(); + } else if ((newp = methodCallArray(nodep, adtypep))) { } else { nodep->v3warn(E_UNSUPPORTED, "Unsupported/unknown built-in queue method " << nodep->prettyNameQ()); @@ -3653,6 +3615,11 @@ private: } nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + } else if (AstCMethodHard* newp = methodCallArray(nodep, adtypep)) { + newp->protect(false); + newp->didWidth(true); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); } else { nodep->v3error("Unknown built-in array method " << nodep->prettyNameQ()); nodep->dtypeFrom(adtypep->subDTypep()); // Best guess diff --git a/test_regress/t/t_array_method.out b/test_regress/t/t_array_method.out deleted file mode 100644 index 48e2a0a0f..000000000 --- a/test_regress/t/t_array_method.out +++ /dev/null @@ -1,117 +0,0 @@ -%Error: t/t_array_method.v:24:9: Unknown built-in array method 'sort' - : ... In instance t - 24 | q.sort; - | ^~~~ -%Error: t/t_array_method.v:26:9: Unknown built-in array method 'sort' - : ... In instance t - 26 | q.sort with (item == 2); - | ^~~~ -%Error: t/t_array_method.v:28:9: Unknown built-in array method 'sort' - : ... In instance t - 28 | q.sort(x) with (x == 3); - | ^~~~ -%Error: t/t_array_method.v:31:9: Unknown built-in array method 'rsort' - : ... In instance t - 31 | q.rsort; - | ^~~~~ -%Error: t/t_array_method.v:33:9: Unknown built-in array method 'rsort' - : ... In instance t - 33 | q.rsort with (item == 2); - | ^~~~~ -%Error: t/t_array_method.v:36:14: Unknown built-in array method 'unique' - : ... In instance t - 36 | qv = q.unique; - | ^~~~~~ -%Error: t/t_array_method.v:38:14: Unknown built-in array method 'unique_index' - : ... In instance t - 38 | qi = q.unique_index; qi.sort; - | ^~~~~~~~~~~~ -%Error: t/t_array_method.v:40:9: Unknown built-in array method 'reverse' - : ... In instance t - 40 | q.reverse; - | ^~~~~~~ -%Error: t/t_array_method.v:42:9: Unknown built-in array method 'shuffle' - : ... In instance t - 42 | q.shuffle(); q.sort; - | ^~~~~~~ -%Error: t/t_array_method.v:42:22: Unknown built-in array method 'sort' - : ... In instance t - 42 | q.shuffle(); q.sort; - | ^~~~ -%Error: t/t_array_method.v:47:14: Unknown built-in array method 'find' - : ... In instance t - 47 | qv = q.find with (item == 2); - | ^~~~ -%Error: t/t_array_method.v:49:14: Unknown built-in array method 'find_first' - : ... In instance t - 49 | qv = q.find_first with (item == 2); - | ^~~~~~~~~~ -%Error: t/t_array_method.v:51:14: Unknown built-in array method 'find_last' - : ... In instance t - 51 | qv = q.find_last with (item == 2); - | ^~~~~~~~~ -%Error: t/t_array_method.v:54:14: Unknown built-in array method 'find' - : ... In instance t - 54 | qv = q.find with (item == 20); - | ^~~~ -%Error: t/t_array_method.v:56:14: Unknown built-in array method 'find_first' - : ... In instance t - 56 | qv = q.find_first with (item == 20); - | ^~~~~~~~~~ -%Error: t/t_array_method.v:58:14: Unknown built-in array method 'find_last' - : ... In instance t - 58 | qv = q.find_last with (item == 20); - | ^~~~~~~~~ -%Error: t/t_array_method.v:61:14: Unknown built-in array method 'find_index' - : ... In instance t - 61 | qi = q.find_index with (item == 2); qi.sort; - | ^~~~~~~~~~ -%Error: t/t_array_method.v:63:14: Unknown built-in array method 'find_first_index' - : ... In instance t - 63 | qi = q.find_first_index with (item == 2); - | ^~~~~~~~~~~~~~~~ -%Error: t/t_array_method.v:65:14: Unknown built-in array method 'find_last_index' - : ... In instance t - 65 | qi = q.find_last_index with (item == 2); - | ^~~~~~~~~~~~~~~ -%Error: t/t_array_method.v:68:14: Unknown built-in array method 'find_index' - : ... In instance t - 68 | qi = q.find_index with (item == 20); qi.sort; - | ^~~~~~~~~~ -%Error: t/t_array_method.v:70:14: Unknown built-in array method 'find_first_index' - : ... In instance t - 70 | qi = q.find_first_index with (item == 20); - | ^~~~~~~~~~~~~~~~ -%Error: t/t_array_method.v:72:14: Unknown built-in array method 'find_last_index' - : ... In instance t - 72 | qi = q.find_last_index with (item == 20); - | ^~~~~~~~~~~~~~~ -%Error: t/t_array_method.v:75:14: Unknown built-in array method 'min' - : ... In instance t - 75 | qv = q.min; - | ^~~ -%Error: t/t_array_method.v:77:14: Unknown built-in array method 'max' - : ... In instance t - 77 | qv = q.max; - | ^~~ -%Error: t/t_array_method.v:83:17: 'with' not legal on this method - : ... In instance t - 83 | i = q.sum with (item + 1); do if ((i) !== (32'h11)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",83, (i), (32'h11)); $stop; end while(0);; - | ^~~~ -%Error: t/t_array_method.v:85:21: 'with' not legal on this method - : ... In instance t - 85 | i = q.product with (item + 1); do if ((i) !== (32'h168)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",85, (i), (32'h168)); $stop; end while(0);; - | ^~~~ -%Error: t/t_array_method.v:89:17: 'with' not legal on this method - : ... In instance t - 89 | i = q.and with (item + 1); do if ((i) !== (32'b1001)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",89, (i), (32'b1001)); $stop; end while(0);; - | ^~~~ -%Error: t/t_array_method.v:91:16: 'with' not legal on this method - : ... In instance t - 91 | i = q.or with (item + 1); do if ((i) !== (32'b1111)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",91, (i), (32'b1111)); $stop; end while(0);; - | ^~~~ -%Error: t/t_array_method.v:93:17: 'with' not legal on this method - : ... In instance t - 93 | i = q.xor with (item + 1); do if ((i) !== (32'hb)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method.v",93, (i), (32'hb)); $stop; end while(0);; - | ^~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_array_method.pl b/test_regress/t/t_array_method.pl index be66c40e6..b46d46042 100755 --- a/test_regress/t/t_array_method.pl +++ b/test_regress/t/t_array_method.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); execute( check_finished => 1, - ) if !$Self->{vlt_all}; + ); ok(1); 1; diff --git a/test_regress/t/t_array_method.v b/test_regress/t/t_array_method.v index e89003046..5326a500a 100644 --- a/test_regress/t/t_array_method.v +++ b/test_regress/t/t_array_method.v @@ -17,39 +17,39 @@ module t (/*AUTOARG*/); string v; q = '{1, 2, 2, 4, 3}; - v = $sformatf("%p", q); `checks(v, "'{1, 2, 2, 4, 3} "); + v = $sformatf("%p", q); `checks(v, "'{'h1, 'h2, 'h2, 'h4, 'h3} "); // NOT tested: with ... selectors q.sort; - v = $sformatf("%p", q); `checks(v, "'{1, 2, 2, 3, 4} "); + v = $sformatf("%p", q); `checks(v, "'{'h1, 'h2, 'h2, 'h3, 'h4} "); q.sort with (item == 2); - v = $sformatf("%p", q); `checks(v, "'{4, 3, 1, 2, 2} "); + v = $sformatf("%p", q); `checks(v, "'{'h1, 'h3, 'h4, 'h2, 'h2} "); q.sort(x) with (x == 3); - v = $sformatf("%p", q); `checks(v, "'{2, 1, 2, 4, 3} "); + v = $sformatf("%p", q); `checks(v, "'{'h1, 'h4, 'h2, 'h2, 'h3} "); q.rsort; - v = $sformatf("%p", q); `checks(v, "'{4, 3, 2, 2, 1} "); + v = $sformatf("%p", q); `checks(v, "'{'h4, 'h3, 'h2, 'h2, 'h1} "); q.rsort with (item == 2); - v = $sformatf("%p", q); `checks(v, "'{2, 2, 4, 1, 3} "); + v = $sformatf("%p", q); `checks(v, "'{'h2, 'h2, 'h4, 'h3, 'h1} "); qv = q.unique; - v = $sformatf("%p", qv); `checks(v, "'{2, 4, 1, 3} "); + v = $sformatf("%p", qv); `checks(v, "'{'h2, 'h4, 'h3, 'h1} "); qi = q.unique_index; qi.sort; - v = $sformatf("%p", qi); `checks(v, "'{0, 2, 3, 4} "); + v = $sformatf("%p", qi); `checks(v, "'{'h0, 'h2, 'h3, 'h4} "); q.reverse; - v = $sformatf("%p", q); `checks(v, "'{3, 1, 4, 2, 2} "); + v = $sformatf("%p", q); `checks(v, "'{'h1, 'h3, 'h4, 'h2, 'h2} "); q.shuffle(); q.sort; - v = $sformatf("%p", q); `checks(v, "'{1, 2, 2, 3, 4} "); + v = $sformatf("%p", q); `checks(v, "'{'h1, 'h2, 'h2, 'h3, 'h4} "); // These require an with clause or are illegal // TODO add a lint check that with clause is provided qv = q.find with (item == 2); - v = $sformatf("%p", qv); `checks(v, "'{2, 2} "); + v = $sformatf("%p", qv); `checks(v, "'{'h2, 'h2} "); qv = q.find_first with (item == 2); - v = $sformatf("%p", qv); `checks(v, "'{2} "); + v = $sformatf("%p", qv); `checks(v, "'{'h2} "); qv = q.find_last with (item == 2); - v = $sformatf("%p", qv); `checks(v, "'{2} "); + v = $sformatf("%p", qv); `checks(v, "'{'h2} "); qv = q.find with (item == 20); v = $sformatf("%p", qv); `checks(v, "'{}"); @@ -59,11 +59,11 @@ module t (/*AUTOARG*/); v = $sformatf("%p", qv); `checks(v, "'{}"); qi = q.find_index with (item == 2); qi.sort; - v = $sformatf("%p", qi); `checks(v, "'{1, 2} "); + v = $sformatf("%p", qi); `checks(v, "'{'h1, 'h2} "); qi = q.find_first_index with (item == 2); - v = $sformatf("%p", qi); `checks(v, "'{1} "); + v = $sformatf("%p", qi); `checks(v, "'{'h1} "); qi = q.find_last_index with (item == 2); - v = $sformatf("%p", qi); `checks(v, "'{2} "); + v = $sformatf("%p", qi); `checks(v, "'{'h2} "); qi = q.find_index with (item == 20); qi.sort; v = $sformatf("%p", qi); `checks(v, "'{}"); @@ -73,24 +73,19 @@ module t (/*AUTOARG*/); v = $sformatf("%p", qi); `checks(v, "'{}"); qv = q.min; - v = $sformatf("%p", qv); `checks(v, "'{1} "); + v = $sformatf("%p", qv); `checks(v, "'{'h1} "); qv = q.max; - v = $sformatf("%p", qv); `checks(v, "'{4} "); + v = $sformatf("%p", qv); `checks(v, "'{'h4} "); // Reduction methods i = q.sum; `checkh(i, 32'hc); - i = q.sum with (item + 1); `checkh(i, 32'h11); i = q.product; `checkh(i, 32'h30); - i = q.product with (item + 1); `checkh(i, 32'h168); q = '{32'b1100, 32'b1010, 32'b1100, 32'b1010, 32'b1010}; i = q.and; `checkh(i, 32'b1000); - i = q.and with (item + 1); `checkh(i, 32'b1001); i = q.or; `checkh(i, 32'b1110); - i = q.or with (item + 1); `checkh(i, 32'b1111); i = q.xor; `checkh(i, 32'ha); - i = q.xor with (item + 1); `checkh(i, 32'hb); $write("*-* All Finished *-*\n"); $finish; diff --git a/test_regress/t/t_array_method_bad.out b/test_regress/t/t_array_method_bad.out new file mode 100644 index 000000000..34f1fcb09 --- /dev/null +++ b/test_regress/t/t_array_method_bad.out @@ -0,0 +1,5 @@ +%Error: t/t_array_method_bad.v:11:9: Unknown built-in array method 'mex' + : ... In instance t + 11 | q.mex; + | ^~~ +%Error: Exiting due to diff --git a/test_regress/t/t_array_method_bad.pl b/test_regress/t/t_array_method_bad.pl new file mode 100755 index 000000000..1d770f716 --- /dev/null +++ b/test_regress/t/t_array_method_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 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_array_method_bad.v b/test_regress/t/t_array_method_bad.v new file mode 100644 index 000000000..ed8a07cde --- /dev/null +++ b/test_regress/t/t_array_method_bad.v @@ -0,0 +1,16 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t; + initial begin + int q[5]; + + q.mex; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_array_method_unsup.out b/test_regress/t/t_array_method_unsup.out new file mode 100644 index 000000000..792927193 --- /dev/null +++ b/test_regress/t/t_array_method_unsup.out @@ -0,0 +1,21 @@ +%Error: t/t_array_method_unsup.v:24:17: 'with' not legal on this method + : ... In instance t + 24 | i = q.sum with (item + 1); do if ((i) !== (32'h11)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method_unsup.v",24, (i), (32'h11)); $stop; end while(0);; + | ^~~~ +%Error: t/t_array_method_unsup.v:25:21: 'with' not legal on this method + : ... In instance t + 25 | i = q.product with (item + 1); do if ((i) !== (32'h168)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method_unsup.v",25, (i), (32'h168)); $stop; end while(0);; + | ^~~~ +%Error: t/t_array_method_unsup.v:28:17: 'with' not legal on this method + : ... In instance t + 28 | i = q.and with (item + 1); do if ((i) !== (32'b1001)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method_unsup.v",28, (i), (32'b1001)); $stop; end while(0);; + | ^~~~ +%Error: t/t_array_method_unsup.v:29:16: 'with' not legal on this method + : ... In instance t + 29 | i = q.or with (item + 1); do if ((i) !== (32'b1111)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method_unsup.v",29, (i), (32'b1111)); $stop; end while(0);; + | ^~~~ +%Error: t/t_array_method_unsup.v:30:17: 'with' not legal on this method + : ... In instance t + 30 | i = q.xor with (item + 1); do if ((i) !== (32'hb)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", "t/t_array_method_unsup.v",30, (i), (32'hb)); $stop; end while(0);; + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_array_method_unsup.pl b/test_regress/t/t_array_method_unsup.pl new file mode 100755 index 000000000..bd07fc421 --- /dev/null +++ b/test_regress/t/t_array_method_unsup.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; + +ok(1); +1; diff --git a/test_regress/t/t_array_method_unsup.v b/test_regress/t/t_array_method_unsup.v new file mode 100644 index 000000000..fc6c727f1 --- /dev/null +++ b/test_regress/t/t_array_method_unsup.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, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); + +module t (/*AUTOARG*/); + initial begin + int q[5]; + int qv[$]; // Value returns + int qi[$]; // Index returns + int i; + string v; + + q = '{1, 2, 2, 4, 3}; + v = $sformatf("%p", q); `checks(v, "'{1, 2, 2, 4, 3} "); + + // Reduction methods + + i = q.sum with (item + 1); `checkh(i, 32'h11); + i = q.product with (item + 1); `checkh(i, 32'h168); + + q = '{32'b1100, 32'b1010, 32'b1100, 32'b1010, 32'b1010}; + i = q.and with (item + 1); `checkh(i, 32'b1001); + i = q.or with (item + 1); `checkh(i, 32'b1111); + i = q.xor with (item + 1); `checkh(i, 32'hb); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From 4b7b185d05a8d56e29de4acfee9a5c63f927bfc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=80lex=20Torregrosa?= <78434679+atorregrosa-smd@users.noreply.github.com> Date: Thu, 8 Jun 2023 17:43:04 +0200 Subject: [PATCH 114/129] Fix VCD scope types (#4227) (#4282) --- include/verilated_vcd_c.cpp | 18 +--- src/V3TraceDecl.cpp | 6 +- test_regress/t/t_hier_block_sc_trace_vcd.out | 8 +- test_regress/t/t_hier_block_trace_vcd.out | 8 +- test_regress/t/t_interface_ref_trace.out | 88 ++++++++++---------- test_regress/t/t_trace_array.out | 2 +- test_regress/t/t_trace_complex_structs.out | 28 +++---- 7 files changed, 74 insertions(+), 84 deletions(-) diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index e9efd953c..b05967c1b 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -410,28 +410,14 @@ void VerilatedVcd::dumpHeader() { if (*np == ' ') np++; if (*np == '\t') break; // tab means signal name starts printIndent(1); - // Find character after name end - const char* sp = np; - while (*sp && *sp != ' ' && *sp != '\t' && !(*sp & '\x80')) sp++; - - printStr("$scope "); - if (*sp & '\x80') { - switch (*sp & 0x7f) { - case VLT_TRACE_SCOPE_STRUCT: printStr("struct "); break; - case VLT_TRACE_SCOPE_INTERFACE: printStr("interface "); break; - case VLT_TRACE_SCOPE_UNION: printStr("union "); break; - default: printStr("module "); - } - } else { - printStr("module "); - } + printStr("$scope module "); for (; *np && *np != ' ' && *np != '\t'; np++) { if (*np == '[') { printStr("["); } else if (*np == ']') { printStr("]"); - } else if (!(*np & '\x80')) { + } else { *m_writep++ = *np; } } diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index 55bf02720..e06a7f02b 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -196,7 +196,11 @@ private: } std::string getScopeChar(VltTraceScope sct) { - return std::string(1, static_cast(0x80 + sct)); + if (v3Global.opt.traceFormat().fst()) { + return std::string(1, static_cast(0x80 + sct)); + } else { + return std::string(); + } } std::string addAboveInterface(const std::string& scopeName) { diff --git a/test_regress/t/t_hier_block_sc_trace_vcd.out b/test_regress/t/t_hier_block_sc_trace_vcd.out index bcb002864..aa5149eb5 100644 --- a/test_regress/t/t_hier_block_sc_trace_vcd.out +++ b/test_regress/t/t_hier_block_sc_trace_vcd.out @@ -156,20 +156,20 @@ $timescale 1ps $end $var wire 8 N in [7:0] $end $var wire 8 P out [7:0] $end $upscope $end - $scope interface in $end + $scope module in $end $var wire 1 K clk $end $var wire 8 N data [7:0] $end $upscope $end - $scope interface out $end + $scope module out $end $var wire 1 K clk $end $var wire 8 O data [7:0] $end $upscope $end $upscope $end - $scope interface in_ifs $end + $scope module in_ifs $end $var wire 1 K clk $end $var wire 8 N data [7:0] $end $upscope $end - $scope interface out_ifs $end + $scope module out_ifs $end $var wire 1 K clk $end $var wire 8 O data [7:0] $end $upscope $end diff --git a/test_regress/t/t_hier_block_trace_vcd.out b/test_regress/t/t_hier_block_trace_vcd.out index e9b9dbdcb..2e89a537a 100644 --- a/test_regress/t/t_hier_block_trace_vcd.out +++ b/test_regress/t/t_hier_block_trace_vcd.out @@ -157,20 +157,20 @@ $timescale 1ps $end $var wire 8 N in [7:0] $end $var wire 8 P out [7:0] $end $upscope $end - $scope interface in $end + $scope module in $end $var wire 1 K clk $end $var wire 8 N data [7:0] $end $upscope $end - $scope interface out $end + $scope module out $end $var wire 1 K clk $end $var wire 8 O data [7:0] $end $upscope $end $upscope $end - $scope interface in_ifs $end + $scope module in_ifs $end $var wire 1 K clk $end $var wire 8 N data [7:0] $end $upscope $end - $scope interface out_ifs $end + $scope module out_ifs $end $var wire 1 K clk $end $var wire 8 O data [7:0] $end $upscope $end diff --git a/test_regress/t/t_interface_ref_trace.out b/test_regress/t/t_interface_ref_trace.out index 5e2a4c6b1..9f59e314d 100644 --- a/test_regress/t/t_interface_ref_trace.out +++ b/test_regress/t/t_interface_ref_trace.out @@ -9,76 +9,76 @@ $timescale 1ps $end $var wire 32 # cyc [31:0] $end $scope module a $end $scope module ac1 $end - $scope interface intf_for_check $end + $scope module intf_for_check $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 $ value [31:0] $end - $scope struct the_struct $end + $scope module the_struct $end $var wire 32 % val100 [31:0] $end $var wire 32 & val200 [31:0] $end $upscope $end $upscope $end $upscope $end $scope module ac2 $end - $scope interface intf_for_check $end + $scope module intf_for_check $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 ' value [31:0] $end - $scope struct the_struct $end + $scope module the_struct $end $var wire 32 ( val100 [31:0] $end $var wire 32 ) val200 [31:0] $end $upscope $end $upscope $end $upscope $end $scope module ac3 $end - $scope interface intf_for_check $end + $scope module intf_for_check $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 * value [31:0] $end - $scope struct the_struct $end + $scope module the_struct $end $var wire 32 + val100 [31:0] $end $var wire 32 , val200 [31:0] $end $upscope $end $upscope $end $upscope $end $scope module as3 $end - $scope interface intf_for_struct $end + $scope module intf_for_struct $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 * value [31:0] $end - $scope struct the_struct $end + $scope module the_struct $end $var wire 32 + val100 [31:0] $end $var wire 32 , val200 [31:0] $end $upscope $end $upscope $end $upscope $end - $scope interface intf_in_sub_all $end + $scope module intf_in_sub_all $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 * value [31:0] $end - $scope interface inner $end + $scope module inner $end $var wire 32 # cyc [31:0] $end $var wire 32 3 value [31:0] $end $upscope $end - $scope struct the_struct $end + $scope module the_struct $end $var wire 32 + val100 [31:0] $end $var wire 32 , val200 [31:0] $end $upscope $end $upscope $end - $scope interface intf_one $end + $scope module intf_one $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 $ value [31:0] $end - $scope struct the_struct $end + $scope module the_struct $end $var wire 32 % val100 [31:0] $end $var wire 32 & val200 [31:0] $end $upscope $end $upscope $end - $scope interface intf_two $end + $scope module intf_two $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 ' value [31:0] $end - $scope struct the_struct $end + $scope module the_struct $end $var wire 32 ( val100 [31:0] $end $var wire 32 ) val200 [31:0] $end $upscope $end @@ -86,146 +86,146 @@ $timescale 1ps $end $upscope $end $scope module abcdefghijklmnopqrstuvwxyz $end $scope module ac1 $end - $scope interface intf_for_check $end + $scope module intf_for_check $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 ' value [31:0] $end - $scope struct the_struct $end + $scope module the_struct $end $var wire 32 ( val100 [31:0] $end $var wire 32 ) val200 [31:0] $end $upscope $end $upscope $end $upscope $end $scope module ac2 $end - $scope interface intf_for_check $end + $scope module intf_for_check $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 $ value [31:0] $end - $scope struct the_struct $end + $scope module the_struct $end $var wire 32 % val100 [31:0] $end $var wire 32 & val200 [31:0] $end $upscope $end $upscope $end $upscope $end $scope module ac3 $end - $scope interface intf_for_check $end + $scope module intf_for_check $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 - value [31:0] $end - $scope struct the_struct $end + $scope module the_struct $end $var wire 32 . val100 [31:0] $end $var wire 32 / val200 [31:0] $end $upscope $end $upscope $end $upscope $end $scope module as3 $end - $scope interface intf_for_struct $end + $scope module intf_for_struct $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 - value [31:0] $end - $scope struct the_struct $end + $scope module the_struct $end $var wire 32 . val100 [31:0] $end $var wire 32 / val200 [31:0] $end $upscope $end $upscope $end $upscope $end - $scope interface intf_in_sub_all $end + $scope module intf_in_sub_all $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 - value [31:0] $end - $scope interface inner $end + $scope module inner $end $var wire 32 # cyc [31:0] $end $var wire 32 4 value [31:0] $end $upscope $end - $scope struct the_struct $end + $scope module the_struct $end $var wire 32 . val100 [31:0] $end $var wire 32 / val200 [31:0] $end $upscope $end $upscope $end - $scope interface intf_one $end + $scope module intf_one $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 ' value [31:0] $end - $scope struct the_struct $end + $scope module the_struct $end $var wire 32 ( val100 [31:0] $end $var wire 32 ) val200 [31:0] $end $upscope $end $upscope $end - $scope interface intf_two $end + $scope module intf_two $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 $ value [31:0] $end - $scope struct the_struct $end + $scope module the_struct $end $var wire 32 % val100 [31:0] $end $var wire 32 & val200 [31:0] $end $upscope $end $upscope $end $upscope $end $scope module c1 $end - $scope interface intf_for_check $end + $scope module intf_for_check $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 $ value [31:0] $end - $scope struct the_struct $end + $scope module the_struct $end $var wire 32 % val100 [31:0] $end $var wire 32 & val200 [31:0] $end $upscope $end $upscope $end $upscope $end $scope module c2 $end - $scope interface intf_for_check $end + $scope module intf_for_check $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 ' value [31:0] $end - $scope struct the_struct $end + $scope module the_struct $end $var wire 32 ( val100 [31:0] $end $var wire 32 ) val200 [31:0] $end $upscope $end $upscope $end $upscope $end - $scope interface intf_1 $end + $scope module intf_1 $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 $ value [31:0] $end - $scope interface inner $end + $scope module inner $end $var wire 32 # cyc [31:0] $end $var wire 32 1 value [31:0] $end $upscope $end - $scope struct the_struct $end + $scope module the_struct $end $var wire 32 % val100 [31:0] $end $var wire 32 & val200 [31:0] $end $upscope $end $upscope $end - $scope interface intf_2 $end + $scope module intf_2 $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 ' value [31:0] $end - $scope interface inner $end + $scope module inner $end $var wire 32 # cyc [31:0] $end $var wire 32 2 value [31:0] $end $upscope $end - $scope struct the_struct $end + $scope module the_struct $end $var wire 32 ( val100 [31:0] $end $var wire 32 ) val200 [31:0] $end $upscope $end $upscope $end $scope module s1 $end - $scope interface intf_for_struct $end + $scope module intf_for_struct $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 $ value [31:0] $end - $scope struct the_struct $end + $scope module the_struct $end $var wire 32 % val100 [31:0] $end $var wire 32 & val200 [31:0] $end $upscope $end $upscope $end $upscope $end $scope module s2 $end - $scope interface intf_for_struct $end + $scope module intf_for_struct $end $var wire 1 0 clk $end $var wire 32 # cyc [31:0] $end $var wire 32 ' value [31:0] $end - $scope struct the_struct $end + $scope module the_struct $end $var wire 32 ( val100 [31:0] $end $var wire 32 ) val200 [31:0] $end $upscope $end diff --git a/test_regress/t/t_trace_array.out b/test_regress/t/t_trace_array.out index 4791912ee..15d934b35 100644 --- a/test_regress/t/t_trace_array.out +++ b/test_regress/t/t_trace_array.out @@ -7,7 +7,7 @@ $timescale 1ps $end $scope module t $end $var wire 1 ]b# clk $end $var wire 32 # cyc [31:0] $end - $scope struct biggie $end + $scope module biggie $end $var wire 1048577 $ d [1048576:0] $end $upscope $end $upscope $end diff --git a/test_regress/t/t_trace_complex_structs.out b/test_regress/t/t_trace_complex_structs.out index c421a6293..8b5d5f780 100644 --- a/test_regress/t/t_trace_complex_structs.out +++ b/test_regress/t/t_trace_complex_structs.out @@ -37,52 +37,52 @@ $timescale 1ps $end $var wire 32 H a [31:0] $end $upscope $end $upscope $end - $scope struct v_arrp_strp[3] $end + $scope module v_arrp_strp[3] $end $var wire 1 1 b0 $end $var wire 1 0 b1 $end $upscope $end - $scope struct v_arrp_strp[4] $end + $scope module v_arrp_strp[4] $end $var wire 1 3 b0 $end $var wire 1 2 b1 $end $upscope $end - $scope struct v_arru_strp[3] $end + $scope module v_arru_strp[3] $end $var wire 1 7 b0 $end $var wire 1 6 b1 $end $upscope $end - $scope struct v_arru_strp[4] $end + $scope module v_arru_strp[4] $end $var wire 1 9 b0 $end $var wire 1 8 b1 $end $upscope $end - $scope struct v_enumb2_str $end + $scope module v_enumb2_str $end $var wire 3 E a [2:0] $end $var wire 3 F b [2:0] $end $upscope $end - $scope struct v_str32x2[0] $end + $scope module v_str32x2[0] $end $var wire 32 @ data [31:0] $end $upscope $end - $scope struct v_str32x2[1] $end + $scope module v_str32x2[1] $end $var wire 32 A data [31:0] $end $upscope $end - $scope struct v_strp_strp $end - $scope struct x0 $end + $scope module v_strp_strp $end + $scope module x0 $end $var wire 1 * b0 $end $var wire 1 ) b1 $end $upscope $end - $scope struct x1 $end + $scope module x1 $end $var wire 1 ( b0 $end $var wire 1 ' b1 $end $upscope $end $upscope $end - $scope struct v_strp $end + $scope module v_strp $end $var wire 1 & b0 $end $var wire 1 % b1 $end $upscope $end - $scope union v_unip_strp $end - $scope struct x0 $end + $scope module v_unip_strp $end + $scope module x0 $end $var wire 1 , b0 $end $var wire 1 + b1 $end $upscope $end - $scope struct x1 $end + $scope module x1 $end $var wire 1 , b0 $end $var wire 1 + b1 $end $upscope $end From 5094e94df1657062aaff4ebac94daef94507f4d9 Mon Sep 17 00:00:00 2001 From: John Wehle <46985578+jlwehle@users.noreply.github.com> Date: Mon, 12 Jun 2023 07:13:00 -0400 Subject: [PATCH 115/129] Fix tracing undefined alignment (#4201) (#4288) --- include/verilated_trace.h | 9 +- include/verilated_trace_imp.h | 4 +- .../t/t_trace_ub_misaligned_address.out | 1 + .../t/t_trace_ub_misaligned_address.pl | 38 ++++++++ .../t/t_trace_ub_misaligned_address.v | 92 +++++++++++++++++++ 5 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 test_regress/t/t_trace_ub_misaligned_address.out create mode 100755 test_regress/t/t_trace_ub_misaligned_address.pl create mode 100644 test_regress/t/t_trace_ub_misaligned_address.v diff --git a/include/verilated_trace.h b/include/verilated_trace.h index d0c2ff4e3..7e8694b70 100644 --- a/include/verilated_trace.h +++ b/include/verilated_trace.h @@ -447,7 +447,9 @@ public: if (VL_UNLIKELY(diff)) fullIData(oldp, newval, bits); } VL_ATTR_ALWINLINE void chgQData(uint32_t* oldp, QData newval, int bits) { - const uint64_t diff = *reinterpret_cast(oldp) ^ newval; + QData old; + std::memcpy(&old, oldp, sizeof(old)); + const uint64_t diff = old ^ newval; if (VL_UNLIKELY(diff)) fullQData(oldp, newval, bits); } VL_ATTR_ALWINLINE void chgWData(uint32_t* oldp, const WData* newvalp, int bits) { @@ -460,8 +462,9 @@ public: } VL_ATTR_ALWINLINE void chgEvent(uint32_t* oldp, VlEvent newval) { fullEvent(oldp, newval); } VL_ATTR_ALWINLINE void chgDouble(uint32_t* oldp, double newval) { - // cppcheck-suppress invalidPointerCast - if (VL_UNLIKELY(*reinterpret_cast(oldp) != newval)) fullDouble(oldp, newval); + double old; + std::memcpy(&old, oldp, sizeof(old)); + if (VL_UNLIKELY(old != newval)) fullDouble(oldp, newval); } }; diff --git a/include/verilated_trace_imp.h b/include/verilated_trace_imp.h index f7d03fc99..9f5792127 100644 --- a/include/verilated_trace_imp.h +++ b/include/verilated_trace_imp.h @@ -872,7 +872,7 @@ void VerilatedTraceBuffer::fullIData(uint32_t* oldp, IData newval, int template <> void VerilatedTraceBuffer::fullQData(uint32_t* oldp, QData newval, int bits) { const uint32_t code = oldp - m_sigs_oldvalp; - *reinterpret_cast(oldp) = newval; + std::memcpy(oldp, &newval, sizeof(newval)); if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return; emitQData(code, newval, bits); } @@ -888,7 +888,7 @@ void VerilatedTraceBuffer::fullWData(uint32_t* oldp, const WData* newv template <> void VerilatedTraceBuffer::fullDouble(uint32_t* oldp, double newval) { const uint32_t code = oldp - m_sigs_oldvalp; - *reinterpret_cast(oldp) = newval; + std::memcpy(oldp, &newval, sizeof(newval)); if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return; // cppcheck-suppress invalidPointerCast emitDouble(code, newval); diff --git a/test_regress/t/t_trace_ub_misaligned_address.out b/test_regress/t/t_trace_ub_misaligned_address.out new file mode 100644 index 000000000..1fe9f3feb --- /dev/null +++ b/test_regress/t/t_trace_ub_misaligned_address.out @@ -0,0 +1 @@ +*-* All Finished *-* diff --git a/test_regress/t/t_trace_ub_misaligned_address.pl b/test_regress/t/t_trace_ub_misaligned_address.pl new file mode 100755 index 000000000..6a37a1511 --- /dev/null +++ b/test_regress/t/t_trace_ub_misaligned_address.pl @@ -0,0 +1,38 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 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); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + top_filename("t/t_trace_ub_misaligned_address.v"); + + compile( + verilator_flags2 => ["--binary --timing --trace", + "-CFLAGS -fsanitize=address,undefined", + "-LDFLAGS -fsanitize=address,undefined"], + verilator_make_cmake => 0, + verilator_make_gmake => 0, + make_main => 0, + ); + + execute( + check_finished => 1, + ); + +# Make sure that there are no additional messages (such as runtime messages +# regarding undefined behavior). + files_identical("$Self->{obj_dir}/vlt_sim.log", $Self->{golden_filename}, "logfile"); +} + +ok(1); +1; diff --git a/test_regress/t/t_trace_ub_misaligned_address.v b/test_regress/t/t_trace_ub_misaligned_address.v new file mode 100644 index 000000000..379412d3a --- /dev/null +++ b/test_regress/t/t_trace_ub_misaligned_address.v @@ -0,0 +1,92 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// When compiled using -fsanitize=address,undefined this triggered: +// +// verilated_trace_imp.h:875:5: runtime error: store to misaligned address ... +// verilated_trace.h:450:31: runtime error: load of misaligned address ... +// +// due to 32 bit aligned addresses being used for types which require +// stricter alignment. +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by John Wehle. +// SPDX-License-Identifier: CC0-1.0 + +`define STRINGIFY(x) `"x`" + +module t; + + wire [2:0] out; + reg in; + reg [39:0] p; + reg rst; + reg clk; + + initial begin + $dumpfile(`STRINGIFY(`TEST_DUMPFILE)); + $dumpvars(0, test); + + clk = 0; + rst = 0; + + for (int i = 0; i < 2; i++) + begin + #10 rst = 1; + #10 rst = 0; + + p = 40'b0000000000111111111111111111110000000000; + + in = i[0]; + + for (int k = 0; k < 31; k++) + begin + in = p[39 - k] ^ i[0]; + #1; + end + + end + + #30 $write("*-* All Finished *-*\n"); + $finish; + end + + always begin + #10 clk <= !clk; + end + + Test test(.out(out), .in(in), + .clk(clk), .rst(rst)); +endmodule + + +module Test(/*AUTOARG*/ + // Outputs + out, + // Inputs + clk, in, rst + ); + + input clk; + input in; + input rst; + output wire [2:0] out; + + reg [2:0] s; + reg sin; + + assign out = s; + + always @(posedge clk, posedge rst) + begin + s[0] <= s[2]; + s[2] <= in; + s[1] <= sin; + end + + always @(negedge clk, posedge rst) + if (rst) + sin <= 1'b0; + else + sin <= in; + +endmodule From ac4315e145a133f25ea7d580b621d17a3a4e3f45 Mon Sep 17 00:00:00 2001 From: Julien Margetts <56540603+margej@users.noreply.github.com> Date: Mon, 12 Jun 2023 14:24:46 +0100 Subject: [PATCH 116/129] Fix LATCH warning on function local variables (#4221) (#4284) --- src/V3Active.cpp | 5 ++++- src/V3AstNodeOther.h | 8 +++++++- test_regress/t/t_lint_latch_6.pl | 17 +++++++++++++++++ test_regress/t/t_lint_latch_6.v | 26 ++++++++++++++++++++++++++ test_regress/t/t_lint_latch_7.pl | 17 +++++++++++++++++ test_regress/t/t_lint_latch_7.v | 21 +++++++++++++++++++++ 6 files changed, 92 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_lint_latch_6.pl create mode 100644 test_regress/t/t_lint_latch_6.v create mode 100755 test_regress/t/t_lint_latch_7.pl create mode 100644 test_regress/t/t_lint_latch_7.v diff --git a/src/V3Active.cpp b/src/V3Active.cpp index e7029790a..fc40166c0 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -320,7 +320,8 @@ private: // VISITORS void visit(AstVarRef* nodep) override { const AstVar* const varp = nodep->varp(); - if (nodep->access().isWriteOrRW() && varp->isSignal() && !varp->isUsedLoopIdx()) { + if (nodep->access().isWriteOrRW() && varp->isSignal() && !varp->isUsedLoopIdx() + && !varp->isFuncLocalSticky()) { m_graph.addAssignment(nodep); } } @@ -333,6 +334,8 @@ private: m_graph.addPathVertex(branchp, "ELSE"); iterateAndNextConstNull(nodep->elsesp()); m_graph.currentp(parentp); + } else { + iterateChildrenConst(nodep); } } //-------------------- diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 4a284b233..90e475d15 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -1646,6 +1646,7 @@ class AstVar final : public AstNode { bool m_usedLoopIdx : 1; // Variable subject of for unrolling bool m_usedVirtIface : 1; // Signal used through a virtual interface bool m_funcLocal : 1; // Local variable for a function + bool m_funcLocalSticky : 1; // As m_funcLocal but remains set if var is moved to a static bool m_funcReturn : 1; // Return variable for a function bool m_attrScBv : 1; // User force bit vector attribute bool m_attrIsolateAssign : 1; // User isolate_assignments attribute @@ -1689,6 +1690,7 @@ class AstVar final : public AstNode { m_sigUserRdPublic = false; m_sigUserRWPublic = false; m_funcLocal = false; + m_funcLocalSticky = false; m_funcReturn = false; m_attrScBv = false; m_attrIsolateAssign = false; @@ -1852,7 +1854,10 @@ public: void isContinuously(bool flag) { m_isContinuously = flag; } void isStatic(bool flag) { m_isStatic = flag; } void isIfaceParent(bool flag) { m_isIfaceParent = flag; } - void funcLocal(bool flag) { m_funcLocal = flag; } + void funcLocal(bool flag) { + m_funcLocal = flag; + if (flag) m_funcLocalSticky = true; + } void funcReturn(bool flag) { m_funcReturn = flag; } void hasStrengthAssignment(bool flag) { m_hasStrengthAssignment = flag; } bool hasStrengthAssignment() { return m_hasStrengthAssignment; } @@ -1934,6 +1939,7 @@ public: bool isStatic() const VL_MT_SAFE { return m_isStatic; } bool isLatched() const { return m_isLatched; } bool isFuncLocal() const { return m_funcLocal; } + bool isFuncLocalSticky() const { return m_funcLocalSticky; } bool isFuncReturn() const { return m_funcReturn; } bool isPullup() const { return m_isPullup; } bool isPulldown() const { return m_isPulldown; } diff --git a/test_regress/t/t_lint_latch_6.pl b/test_regress/t/t_lint_latch_6.pl new file mode 100755 index 000000000..629a44bbb --- /dev/null +++ b/test_regress/t/t_lint_latch_6.pl @@ -0,0 +1,17 @@ +#!/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 => 1); + +lint( + ); + +ok(1); +1; diff --git a/test_regress/t/t_lint_latch_6.v b/test_regress/t/t_lint_latch_6.v new file mode 100644 index 000000000..9f55fb831 --- /dev/null +++ b/test_regress/t/t_lint_latch_6.v @@ -0,0 +1,26 @@ +// DESCRIPTION: Verilator: Verilog Test module for Issue#221 +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Julien Margetts (Originally provided by Adrien Le Masle) +// SPDX-License-Identifier: Unlicense + +module verilator_latch +( + input logic state, + output logic [31:0] b +); + + function logic [31:0 ] toto (); + logic [31:0] res; + res = 10; + return res; + endfunction + + always_comb + begin + b = 0; + if (state) + b = toto(); + end + +endmodule; diff --git a/test_regress/t/t_lint_latch_7.pl b/test_regress/t/t_lint_latch_7.pl new file mode 100755 index 000000000..629a44bbb --- /dev/null +++ b/test_regress/t/t_lint_latch_7.pl @@ -0,0 +1,17 @@ +#!/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 => 1); + +lint( + ); + +ok(1); +1; diff --git a/test_regress/t/t_lint_latch_7.v b/test_regress/t/t_lint_latch_7.v new file mode 100644 index 000000000..d8fbbc1c6 --- /dev/null +++ b/test_regress/t/t_lint_latch_7.v @@ -0,0 +1,21 @@ +// DESCRIPTION: Verilator: Verilog Test module for Issue#xxxx +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2021 by Julien Margetts +// SPDX-License-Identifier: Unlicense + +module test #(parameter W = 65) + (input logic [W-1:0] a, + input logic e, + output logic [W-1:0] z); + + integer i; + + always @(*) + if (e) + for (i=0;i Date: Mon, 12 Jun 2023 20:09:12 -0400 Subject: [PATCH 117/129] Tests: Auto detect and exit --timing with no coroutines --- test_regress/driver.pl | 80 +++++++++++-------- test_regress/t/t_clocking_sched_timing.pl | 25 +++--- test_regress/t/t_clocking_timing1.pl | 23 +++--- test_regress/t/t_clocking_timing2.pl | 21 ++--- test_regress/t/t_cxx_equal_to.pl | 25 +++--- test_regress/t/t_delay_incr_timing.pl | 21 ++--- test_regress/t/t_delay_timing.pl | 21 ++--- test_regress/t/t_delay_var.pl | 23 +++--- test_regress/t/t_event_control_timing.pl | 21 ++--- test_regress/t/t_flag_binary.pl | 29 +++---- test_regress/t/t_fork_label_timing.pl | 23 +++--- test_regress/t/t_fork_timing.pl | 19 ++--- test_regress/t/t_func_lib_sub_timing.pl | 16 ++-- test_regress/t/t_gate_basic_timing.pl | 21 ++--- test_regress/t/t_mailbox.pl | 19 ++--- test_regress/t/t_mailbox_class.pl | 11 +-- test_regress/t/t_mailbox_std.pl | 21 ++--- test_regress/t/t_math_signed5_timing.pl | 23 +++--- test_regress/t/t_net_delay_timing.pl | 23 +++--- test_regress/t/t_net_delay_timing_sc.pl | 22 ++--- test_regress/t/t_order_timing.pl | 21 ++--- test_regress/t/t_package_ddecl_timing.pl | 23 +++--- test_regress/t/t_parse_delay_timing.pl | 15 ++-- test_regress/t/t_process.pl | 19 ++--- test_regress/t/t_process_finished.pl | 17 ++-- test_regress/t/t_process_fork.pl | 19 ++--- test_regress/t/t_process_kill.pl | 17 ++-- test_regress/t/t_process_rand.pl | 17 ++-- test_regress/t/t_process_std.pl | 17 ++-- test_regress/t/t_semaphore.pl | 19 ++--- test_regress/t/t_semaphore_always.pl | 17 ++-- test_regress/t/t_semaphore_class.pl | 11 +-- test_regress/t/t_semaphore_std.pl | 21 ++--- test_regress/t/t_suspendable_deep.pl | 11 +-- test_regress/t/t_timing_always.pl | 21 ++--- test_regress/t/t_timing_class.pl | 21 ++--- test_regress/t/t_timing_clkgen1.pl | 21 ++--- test_regress/t/t_timing_clkgen2.pl | 21 ++--- test_regress/t/t_timing_clkgen3.pl | 21 ++--- test_regress/t/t_timing_clkgen_sc.pl | 24 ++---- test_regress/t/t_timing_debug1.pl | 27 +++---- test_regress/t/t_timing_debug2.pl | 27 +++---- test_regress/t/t_timing_delay_callstack.pl | 21 ++--- test_regress/t/t_timing_dlyassign.pl | 21 ++--- test_regress/t/t_timing_events.pl | 21 ++--- test_regress/t/t_timing_fork_comb.pl | 33 ++++---- test_regress/t/t_timing_fork_join.pl | 23 +++--- test_regress/t/t_timing_fork_many.pl | 21 ++--- test_regress/t/t_timing_fork_nba.pl | 11 +-- .../t/t_timing_fork_no_timing_ctrl.pl | 21 ++--- test_regress/t/t_timing_fork_taskcall.pl | 21 ++--- test_regress/t/t_timing_intra_assign.pl | 38 ++++----- test_regress/t/t_timing_long.pl | 2 +- test_regress/t/t_timing_nba.pl | 21 ++--- test_regress/t/t_timing_off.pl | 21 ++--- test_regress/t/t_timing_pong.pl | 21 ++--- test_regress/t/t_timing_protect.pl | 39 ++++----- test_regress/t/t_timing_reentry.pl | 21 ++--- test_regress/t/t_timing_sched.pl | 21 ++--- test_regress/t/t_timing_sched_if.pl | 21 ++--- test_regress/t/t_timing_sched_nba.pl | 21 ++--- test_regress/t/t_timing_strobe.pl | 23 +++--- test_regress/t/t_timing_trace.pl | 23 +++--- test_regress/t/t_timing_trace_fst.pl | 21 ++--- test_regress/t/t_timing_wait1.pl | 21 ++--- test_regress/t/t_timing_wait2.pl | 21 ++--- test_regress/t/t_timing_wait_long.pl | 24 +++--- test_regress/t/t_trace_binary.pl | 31 +++---- test_regress/t/t_trace_binary_flag_off.pl | 29 +++---- test_regress/t/t_trace_timing1.pl | 29 +++---- .../t/t_trace_ub_misaligned_address.pl | 31 +++---- test_regress/t/t_vlt_timing.pl | 21 ++--- test_regress/t/t_wait_timing.pl | 21 ++--- test_regress/t/t_while_timing_control.pl | 19 ++--- 74 files changed, 646 insertions(+), 1001 deletions(-) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 6bf8240c8..9a9440b1b 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -153,6 +153,9 @@ if ($#opt_tests < 0) { # Run everything @opt_tests = _calc_hashset(@opt_tests) if $opt_hashset; if ($#opt_tests >= 2 && $opt_jobs >= 2) { + # Read supported into master process, so don't call every subprocess + _have_coroutines(); + _have_sc(); # Without this tests such as t_debug_sigsegv_bt_bad.pl will occasionally # block on input and cause a SIGSTOP, then a "fg" was needed to resume testing. if (!$::Have_Forker) { @@ -289,6 +292,35 @@ sub _calc_hashset { return @new; } +####################################################################### +# Verilator utilities + +our %_Verilator_Supported; +sub _verilator_get_supported { + my $feature = shift; + # Returns if given feature is supported + if (!defined $_Verilator_Supported{$feature}) { + my @args = ("perl", "$ENV{VERILATOR_ROOT}/bin/verilator", "-get-supported", $feature); + my $args = join(' ', @args); + my $out = `$args`; + $out or die "couldn't run: $! " . join(' ', @args); + chomp $out; + $_Verilator_Supported{$feature} = ($out =~ /1/ ? 1 : 0); + } + return $_Verilator_Supported{$feature}; +} + +sub _have_coroutines { + return 1 if _verilator_get_supported('COROUTINES'); + return 0; +} + +sub _have_sc { + return 1 if (defined $ENV{SYSTEMC} || defined $ENV{SYSTEMC_INCLUDE} || $ENV{CFG_HAVE_SYSTEMC}); + return 1 if _verilator_get_supported('SYSTEMC'); + return 0; +} + ####################################################################### ####################################################################### ####################################################################### @@ -889,21 +921,22 @@ sub compile_vlt_flags { my %param = (%{$self}, @_); # Default arguments are from $self return 1 if $self->errors || $self->skips; - my $checkflags = join(' ', @{$param{v_flags}}, - @{$param{v_flags2}}, - @{$param{verilator_flags}}, - @{$param{verilator_flags2}}, - @{$param{verilator_flags3}}); + my $checkflags = ' '.join(' ', @{$param{v_flags}}, + @{$param{v_flags2}}, + @{$param{verilator_flags}}, + @{$param{verilator_flags2}}, + @{$param{verilator_flags3}}); die "%Error: specify threads via 'threads =>' argument, not as a command line option" unless ($checkflags !~ /(^|\s)-?-threads\s/); + $self->{coverage} = 1 if ($checkflags =~ /-coverage\b/); + $self->{savable} = 1 if ($checkflags =~ /-savable\b/); $self->{sc} = 1 if ($checkflags =~ /-sc\b/); + $self->{timing} = 1 if ($checkflags =~ /\b-?-timing\b/ || $checkflags =~ /\b-?-binary\b/ ); $self->{trace} = ($opt_trace || $checkflags =~ /-trace\b/ || $checkflags =~ /-trace-fst\b/); $self->{trace_format} = (($checkflags =~ /-trace-fst/ && $self->{sc} && 'fst-sc') || ($checkflags =~ /-trace-fst/ && !$self->{sc} && 'fst-c') || ($self->{sc} && 'vcd-sc') || (!$self->{sc} && 'vcd-c')); - $self->{savable} = 1 if ($checkflags =~ /-savable\b/); - $self->{coverage} = 1 if ($checkflags =~ /-coverage\b/); $self->{sanitize} = $opt_sanitize unless exists($self->{sanitize}); $self->{benchmarksim} = 1 if ($param{benchmarksim}); @@ -1113,7 +1146,10 @@ sub compile { $self->skip("Test requires SystemC; ignore error since not installed\n"); return 1; } - + if ($self->{timing} && !$self->have_coroutines) { + $self->skip("Test requires Coroutines; ignore error since not available\n"); + return 1; + } if ($param{verilator_make_cmake} && !$self->have_cmake) { $self->skip("Test requires CMake; ignore error since not available or version too old\n"); return 1; @@ -1464,16 +1500,11 @@ sub sc { } sub have_sc { - my $self = (ref $_[0] ? shift : $Self); - return 1 if (defined $ENV{SYSTEMC} || defined $ENV{SYSTEMC_INCLUDE} || $ENV{CFG_HAVE_SYSTEMC}); - return 1 if $self->verilator_get_supported('SYSTEMC'); - return 0; + return ::_have_sc(); } sub have_coroutines { - my $self = (ref $_[0] ? shift : $Self); - return 1 if $self->verilator_get_supported('COROUTINES'); - return 0; + return ::_have_coroutines(); } sub make_version { @@ -2155,25 +2186,6 @@ sub _read_inputs_vhdl { $fh->close(); } -####################################################################### -# Verilator utilities - -our %_Verilator_Supported; -sub verilator_get_supported { - my $self = (ref $_[0] ? shift : $Self); - my $feature = shift; - # Returns if given feature is supported - if (!defined $_Verilator_Supported{$feature}) { - my @args = ("perl", "$ENV{VERILATOR_ROOT}/bin/verilator", "-get-supported", $feature); - my $args = join(' ', @args); - my $out = `$args`; - $out or die "couldn't run: $! " . join(' ', @args); - chomp $out; - $_Verilator_Supported{$feature} = ($out =~ /1/ ? 1 : 0); - } - return $_Verilator_Supported{$feature}; -} - ####################################################################### # File utilities diff --git a/test_regress/t/t_clocking_sched_timing.pl b/test_regress/t/t_clocking_sched_timing.pl index 7fe0b1dee..1d537460a 100755 --- a/test_regress/t/t_clocking_sched_timing.pl +++ b/test_regress/t/t_clocking_sched_timing.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,22 +10,17 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - top_filename("t/t_clocking_sched.v"); +top_filename("t/t_clocking_sched.v"); - compile( - timing_loop => 1, - verilator_flags2 => ["--timing"], - ); +compile( + timing_loop => 1, + verilator_flags2 => ["--timing"], + ); - execute( - check_finished => 1, - expect_filename => $Self->{golden_filename} - ); -} +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename} + ); ok(1); 1; diff --git a/test_regress/t/t_clocking_timing1.pl b/test_regress/t/t_clocking_timing1.pl index ca8f6fa4e..671334c7d 100755 --- a/test_regress/t/t_clocking_timing1.pl +++ b/test_regress/t/t_clocking_timing1.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,21 +10,16 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - top_filename("t/t_clocking_timing.v"); +top_filename("t/t_clocking_timing.v"); - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_clocking_timing2.pl b/test_regress/t/t_clocking_timing2.pl index 6dff6484b..ad6f5308f 100755 --- a/test_regress/t/t_clocking_timing2.pl +++ b/test_regress/t/t_clocking_timing2.pl @@ -10,21 +10,16 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - top_filename("t/t_clocking_timing.v"); +top_filename("t/t_clocking_timing.v"); - compile( - verilator_flags2 => ["--exe --main --timing -DTEST_INPUT_SKEW=12 -DTEST_OUTPUT_SKEW=16"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing -DTEST_INPUT_SKEW=12 -DTEST_OUTPUT_SKEW=16"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_cxx_equal_to.pl b/test_regress/t/t_cxx_equal_to.pl index 5ac57f398..adba530eb 100755 --- a/test_regress/t/t_cxx_equal_to.pl +++ b/test_regress/t/t_cxx_equal_to.pl @@ -10,23 +10,18 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - top_filename("t/t_cxx_equal_to.v"); +top_filename("t/t_cxx_equal_to.v"); - compile( - verilator_flags2 => ['--binary --timing --trace'], - verilator_make_cmake => 0, - verilator_make_gmake => 0, - make_main => 0, - ); +compile( + verilator_flags2 => ['--exe --main --timing --timing --trace'], + verilator_make_cmake => 0, + verilator_make_gmake => 0, + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_delay_incr_timing.pl b/test_regress/t/t_delay_incr_timing.pl index 6b78f49a3..7bc99d468 100755 --- a/test_regress/t/t_delay_incr_timing.pl +++ b/test_regress/t/t_delay_incr_timing.pl @@ -12,21 +12,16 @@ scenarios(simulator => 1); $Self->{main_time_multiplier} = 10e-7 / 10e-9; -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - top_filename("t/t_delay_incr.v"); +top_filename("t/t_delay_incr.v"); - compile( - timing_loop => 1, - verilator_flags2 => ['--timing -Wno-ZERODLY'], - ); +compile( + timing_loop => 1, + verilator_flags2 => ['--timing -Wno-ZERODLY'], + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_delay_timing.pl b/test_regress/t/t_delay_timing.pl index 505ebf865..9514aafb4 100755 --- a/test_regress/t/t_delay_timing.pl +++ b/test_regress/t/t_delay_timing.pl @@ -12,21 +12,16 @@ scenarios(simulator => 1); $Self->{main_time_multiplier} = 10e-7 / 10e-9; -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - top_filename("t/t_delay.v"); +top_filename("t/t_delay.v"); - compile( - timing_loop => 1, - verilator_flags2 => ['--timing -Wno-ZERODLY'], - ); +compile( + timing_loop => 1, + verilator_flags2 => ['--timing -Wno-ZERODLY'], + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_delay_var.pl b/test_regress/t/t_delay_var.pl index c0d64fbeb..68a8b13cd 100755 --- a/test_regress/t/t_delay_var.pl +++ b/test_regress/t/t_delay_var.pl @@ -10,21 +10,16 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - fails => $Self->{vlt}, - expect_filename => $Self->{golden_filename}, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + fails => $Self->{vlt}, + expect_filename => $Self->{golden_filename}, + ); - execute( - check_finished => 1, - ) if !$Self->{vlt}; -} +execute( + check_finished => 1, + ) if !$Self->{vlt}; ok(1); 1; diff --git a/test_regress/t/t_event_control_timing.pl b/test_regress/t/t_event_control_timing.pl index 6a4829740..750ff60c9 100755 --- a/test_regress/t/t_event_control_timing.pl +++ b/test_regress/t/t_event_control_timing.pl @@ -10,21 +10,16 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - top_filename("t/t_event_control.v"); +top_filename("t/t_event_control.v"); - compile( - verilator_flags2 => ["--timing"], - ); +compile( + verilator_flags2 => ["--timing"], + ); - execute( - check_finished => 1, - expect_filename => $Self->{golden_filename}, - ); -} +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); ok(1); 1; diff --git a/test_regress/t/t_flag_binary.pl b/test_regress/t/t_flag_binary.pl index c8f265aa1..e810b1eb6 100755 --- a/test_regress/t/t_flag_binary.pl +++ b/test_regress/t/t_flag_binary.pl @@ -12,24 +12,19 @@ scenarios(simulator => 1); top_filename("t/t_flag_main.v"); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags => [# Custom as don't want -cc - "-Mdir $Self->{obj_dir}", - "--debug-check", ], - verilator_flags2 => ['--binary'], - verilator_make_cmake => 0, - verilator_make_gmake => 0, - make_main => 0, - ); +compile( + verilator_flags => [# Custom as don't want -cc + "-Mdir $Self->{obj_dir}", + "--debug-check", ], + verilator_flags2 => ['--binary'], + verilator_make_cmake => 0, + verilator_make_gmake => 0, + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_fork_label_timing.pl b/test_regress/t/t_fork_label_timing.pl index 8d67932b9..da97b37e2 100755 --- a/test_regress/t/t_fork_label_timing.pl +++ b/test_regress/t/t_fork_label_timing.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,21 +10,16 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - top_filename("t/t_fork_label.v"); +top_filename("t/t_fork_label.v"); - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_fork_timing.pl b/test_regress/t/t_fork_timing.pl index f31aef7c3..db741a7d5 100755 --- a/test_regress/t/t_fork_timing.pl +++ b/test_regress/t/t_fork_timing.pl @@ -10,20 +10,15 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - top_filename("t/t_fork.v"); +top_filename("t/t_fork.v"); - compile( - verilator_flags2 => ["--timing"], - ); +compile( + verilator_flags2 => ["--timing"], + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_func_lib_sub_timing.pl b/test_regress/t/t_func_lib_sub_timing.pl index 0acb617a6..7498c6694 100755 --- a/test_regress/t/t_func_lib_sub_timing.pl +++ b/test_regress/t/t_func_lib_sub_timing.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,16 +10,12 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); # UNOPTTHREADS in vltmt -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - top_filename("t/t_func_lib_sub.v"); +top_filename("t/t_func_lib_sub.v"); + +compile( + verilator_flags2 => ["--timing"], + ); - compile( - verilator_flags2 => ["--timing"], - ); -} # No execute ok(1); 1; diff --git a/test_regress/t/t_gate_basic_timing.pl b/test_regress/t/t_gate_basic_timing.pl index 713929427..efbe15374 100755 --- a/test_regress/t/t_gate_basic_timing.pl +++ b/test_regress/t/t_gate_basic_timing.pl @@ -12,21 +12,16 @@ scenarios(simulator => 1); $Self->{main_time_multiplier} = 10e-7 / 10e-9; -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - top_filename("t/t_gate_basic.v"); +top_filename("t/t_gate_basic.v"); - compile( - timing_loop => 1, - verilator_flags2 => ["--timing --timescale 10ns/1ns -Wno-RISEFALLDLY"], - ); +compile( + timing_loop => 1, + verilator_flags2 => ["--timing --timescale 10ns/1ns -Wno-RISEFALLDLY"], + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_mailbox.pl b/test_regress/t/t_mailbox.pl index d7ae01e91..30306c8ce 100755 --- a/test_regress/t/t_mailbox.pl +++ b/test_regress/t/t_mailbox.pl @@ -10,19 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing -Wall"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing -Wall"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_mailbox_class.pl b/test_regress/t/t_mailbox_class.pl index 3329d516e..6e30bd25d 100755 --- a/test_regress/t/t_mailbox_class.pl +++ b/test_regress/t/t_mailbox_class.pl @@ -10,14 +10,9 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--timing"], - ); -} +compile( + verilator_flags2 => ["--timing"], + ); ok(1); 1; diff --git a/test_regress/t/t_mailbox_std.pl b/test_regress/t/t_mailbox_std.pl index 1229e6524..31b9a5203 100755 --- a/test_regress/t/t_mailbox_std.pl +++ b/test_regress/t/t_mailbox_std.pl @@ -10,21 +10,16 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - top_filename("t/t_mailbox.v"); +top_filename("t/t_mailbox.v"); - compile( - verilator_flags2 => ["--exe --main --timing -Wall --Wpedantic -DMAILBOX_T=std::mailbox"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing -Wall --Wpedantic -DMAILBOX_T=std::mailbox"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_math_signed5_timing.pl b/test_regress/t/t_math_signed5_timing.pl index 2365fef9a..34482e187 100755 --- a/test_regress/t/t_math_signed5_timing.pl +++ b/test_regress/t/t_math_signed5_timing.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,21 +10,16 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - top_filename("t/t_math_signed5.v"); +top_filename("t/t_math_signed5.v"); - compile( - verilator_flags2 => ['--timing'], - timing_loop => 1, - ); +compile( + verilator_flags2 => ['--timing'], + timing_loop => 1, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_net_delay_timing.pl b/test_regress/t/t_net_delay_timing.pl index 63a94fdbd..0ebdb8a45 100755 --- a/test_regress/t/t_net_delay_timing.pl +++ b/test_regress/t/t_net_delay_timing.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,21 +10,16 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - top_filename("t/t_net_delay.v"); +top_filename("t/t_net_delay.v"); - compile( - timing_loop => 1, - verilator_flags2 => ["--timing"], - ); +compile( + timing_loop => 1, + verilator_flags2 => ["--timing"], + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_net_delay_timing_sc.pl b/test_regress/t/t_net_delay_timing_sc.pl index 1fd75cffb..3dd55e6e1 100755 --- a/test_regress/t/t_net_delay_timing_sc.pl +++ b/test_regress/t/t_net_delay_timing_sc.pl @@ -12,23 +12,15 @@ scenarios(simulator => 1); $Self->{main_time_multiplier} = 2; -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -elsif (!$Self->have_sc) { - skip("No SystemC installed"); -} -else { - top_filename("t/t_net_delay.v"); +top_filename("t/t_net_delay.v"); - compile( - verilator_flags2 => ["--sc --exe --timing --timescale 10ps/1ps"], - ); +compile( + verilator_flags2 => ["--sc --exe --timing --timescale 10ps/1ps"], + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_order_timing.pl b/test_regress/t/t_order_timing.pl index ee807ce82..d00f26d4a 100755 --- a/test_regress/t/t_order_timing.pl +++ b/test_regress/t/t_order_timing.pl @@ -12,21 +12,16 @@ scenarios(simulator => 1); $Self->{main_time_multiplier} = 1e-8 / 1e-9; -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - top_filename("t/t_order.v"); +top_filename("t/t_order.v"); - compile( - timing_loop => 1, - verilator_flags2 => ["--timescale 10ns/1ns --timing"], - ); +compile( + timing_loop => 1, + verilator_flags2 => ["--timescale 10ns/1ns --timing"], + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_package_ddecl_timing.pl b/test_regress/t/t_package_ddecl_timing.pl index d471a7adb..f7858dcb8 100755 --- a/test_regress/t/t_package_ddecl_timing.pl +++ b/test_regress/t/t_package_ddecl_timing.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,21 +10,16 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - top_filename("t/t_package_ddecl.v"); +top_filename("t/t_package_ddecl.v"); - compile( - verilator_flags2 => ['--timing'], - timing_loop => 1, - ); +compile( + verilator_flags2 => ['--timing'], + timing_loop => 1, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_parse_delay_timing.pl b/test_regress/t/t_parse_delay_timing.pl index f4847bf8c..d466d38c7 100755 --- a/test_regress/t/t_parse_delay_timing.pl +++ b/test_regress/t/t_parse_delay_timing.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,16 +10,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - top_filename("t/t_parse_delay.v"); +top_filename("t/t_parse_delay.v"); - compile( - verilator_flags2 => ['--timing'], - ); -} +compile( + verilator_flags2 => ['--timing'], + ); ok(1); 1; diff --git a/test_regress/t/t_process.pl b/test_regress/t/t_process.pl index b477231cf..7eac3054e 100755 --- a/test_regress/t/t_process.pl +++ b/test_regress/t/t_process.pl @@ -10,19 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - v_flags2 => ["--timing"], - ); +compile( + v_flags2 => ["--timing"], + ); - execute( - check_finished => 1, - expect_filename => $Self->{golden_filename}, - ); -} +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); ok(1); 1; diff --git a/test_regress/t/t_process_finished.pl b/test_regress/t/t_process_finished.pl index 1db13024b..b267631e9 100755 --- a/test_regress/t/t_process_finished.pl +++ b/test_regress/t/t_process_finished.pl @@ -10,18 +10,13 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--timing"], - ); +compile( + verilator_flags2 => ["--timing"], + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_process_fork.pl b/test_regress/t/t_process_fork.pl index 1af68b062..604f632d4 100755 --- a/test_regress/t/t_process_fork.pl +++ b/test_regress/t/t_process_fork.pl @@ -10,19 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--timing"], - ); +compile( + verilator_flags2 => ["--timing"], + ); - execute( - check_finished => 1, - expect_filename => $Self->{golden_filename}, - ); -} +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); ok(1); 1; diff --git a/test_regress/t/t_process_kill.pl b/test_regress/t/t_process_kill.pl index 1db13024b..b267631e9 100755 --- a/test_regress/t/t_process_kill.pl +++ b/test_regress/t/t_process_kill.pl @@ -10,18 +10,13 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--timing"], - ); +compile( + verilator_flags2 => ["--timing"], + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_process_rand.pl b/test_regress/t/t_process_rand.pl index 95e68c03f..4152e3d9b 100755 --- a/test_regress/t/t_process_rand.pl +++ b/test_regress/t/t_process_rand.pl @@ -10,18 +10,13 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - v_flags2 => ["--timing"], - ); +compile( + v_flags2 => ["--timing"], + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_process_std.pl b/test_regress/t/t_process_std.pl index d270c22a7..c9318acf2 100755 --- a/test_regress/t/t_process_std.pl +++ b/test_regress/t/t_process_std.pl @@ -12,18 +12,13 @@ scenarios(simulator => 1); top_filename("t/t_process.v"); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - v_flags2 => ["+define+T_PROCESS+std::process", "--timing"], - ); +compile( + v_flags2 => ["+define+T_PROCESS+std::process", "--timing"], + ); - execute( - check_finished => 1, - ) if !$Self->{vlt_all}; -} +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; ok(1); 1; diff --git a/test_regress/t/t_semaphore.pl b/test_regress/t/t_semaphore.pl index d7ae01e91..30306c8ce 100755 --- a/test_regress/t/t_semaphore.pl +++ b/test_regress/t/t_semaphore.pl @@ -10,19 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing -Wall"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing -Wall"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_semaphore_always.pl b/test_regress/t/t_semaphore_always.pl index 1db13024b..b267631e9 100755 --- a/test_regress/t/t_semaphore_always.pl +++ b/test_regress/t/t_semaphore_always.pl @@ -10,18 +10,13 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--timing"], - ); +compile( + verilator_flags2 => ["--timing"], + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_semaphore_class.pl b/test_regress/t/t_semaphore_class.pl index 3329d516e..6e30bd25d 100755 --- a/test_regress/t/t_semaphore_class.pl +++ b/test_regress/t/t_semaphore_class.pl @@ -10,14 +10,9 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--timing"], - ); -} +compile( + verilator_flags2 => ["--timing"], + ); ok(1); 1; diff --git a/test_regress/t/t_semaphore_std.pl b/test_regress/t/t_semaphore_std.pl index 7fcb5b404..47041497b 100755 --- a/test_regress/t/t_semaphore_std.pl +++ b/test_regress/t/t_semaphore_std.pl @@ -10,21 +10,16 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - top_filename("t/t_semaphore.v"); +top_filename("t/t_semaphore.v"); - compile( - verilator_flags2 => ["--exe --main --timing -Wall -DSEMAPHORE_T=std::semaphore"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing -Wall -DSEMAPHORE_T=std::semaphore"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_suspendable_deep.pl b/test_regress/t/t_suspendable_deep.pl index 422d61e57..e7824bce9 100755 --- a/test_regress/t/t_suspendable_deep.pl +++ b/test_regress/t/t_suspendable_deep.pl @@ -10,14 +10,9 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--timing"], - ); -} +compile( + verilator_flags2 => ["--timing"], + ); ok(1); 1; diff --git a/test_regress/t/t_timing_always.pl b/test_regress/t/t_timing_always.pl index f86c4b944..b8493bd06 100755 --- a/test_regress/t/t_timing_always.pl +++ b/test_regress/t/t_timing_always.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,19 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_class.pl b/test_regress/t/t_timing_class.pl index c469d3de3..002312d88 100755 --- a/test_regress/t/t_timing_class.pl +++ b/test_regress/t/t_timing_class.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,19 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_clkgen1.pl b/test_regress/t/t_timing_clkgen1.pl index aa7288ef4..edbe747b4 100755 --- a/test_regress/t/t_timing_clkgen1.pl +++ b/test_regress/t/t_timing_clkgen1.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,19 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing -Wno-MINTYPMAXDLY"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing -Wno-MINTYPMAXDLY"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_clkgen2.pl b/test_regress/t/t_timing_clkgen2.pl index f86c4b944..b8493bd06 100755 --- a/test_regress/t/t_timing_clkgen2.pl +++ b/test_regress/t/t_timing_clkgen2.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,19 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_clkgen3.pl b/test_regress/t/t_timing_clkgen3.pl index f86c4b944..b8493bd06 100755 --- a/test_regress/t/t_timing_clkgen3.pl +++ b/test_regress/t/t_timing_clkgen3.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,19 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_clkgen_sc.pl b/test_regress/t/t_timing_clkgen_sc.pl index a5fe43850..728e33f11 100755 --- a/test_regress/t/t_timing_clkgen_sc.pl +++ b/test_regress/t/t_timing_clkgen_sc.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,23 +10,15 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -elsif (!$Self->have_sc) { - skip("No SystemC installed"); -} -else { - top_filename("t/t_timing_clkgen2.v"); +top_filename("t/t_timing_clkgen2.v"); - compile( - verilator_flags2 => ["--sc --exe --timing --timescale 10ps/1ps"], - ); +compile( + verilator_flags2 => ["--sc --exe --timing --timescale 10ps/1ps"], + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_debug1.pl b/test_regress/t/t_timing_debug1.pl index 0d4523725..06be36082 100755 --- a/test_regress/t/t_timing_debug1.pl +++ b/test_regress/t/t_timing_debug1.pl @@ -10,25 +10,20 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt_all => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - top_filename("t/t_timing_sched.v"); +top_filename("t/t_timing_sched.v"); - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - all_run_flags => ["+verilator+debug"], - check_finished => 1, - ); +execute( + all_run_flags => ["+verilator+debug"], + check_finished => 1, + ); - if (!$Self->{vltmt}) { # vltmt output may vary between thread exec order - files_identical("$Self->{obj_dir}/vlt_sim.log", $Self->{golden_filename}, "logfile"); - } +if (!$Self->{vltmt}) { # vltmt output may vary between thread exec order + files_identical("$Self->{obj_dir}/vlt_sim.log", $Self->{golden_filename}, "logfile"); } ok(1); diff --git a/test_regress/t/t_timing_debug2.pl b/test_regress/t/t_timing_debug2.pl index 56ef19876..4ff0b44ea 100755 --- a/test_regress/t/t_timing_debug2.pl +++ b/test_regress/t/t_timing_debug2.pl @@ -10,25 +10,20 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt_all => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - top_filename("t/t_timing_class.v"); +top_filename("t/t_timing_class.v"); - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - all_run_flags => ["+verilator+debug"], - check_finished => 1, - ); +execute( + all_run_flags => ["+verilator+debug"], + check_finished => 1, + ); - if (!$Self->{vltmt}) { # vltmt output may vary between thread exec order - files_identical("$Self->{obj_dir}/vlt_sim.log", $Self->{golden_filename}, "logfile"); - } +if (!$Self->{vltmt}) { # vltmt output may vary between thread exec order + files_identical("$Self->{obj_dir}/vlt_sim.log", $Self->{golden_filename}, "logfile"); } ok(1); diff --git a/test_regress/t/t_timing_delay_callstack.pl b/test_regress/t/t_timing_delay_callstack.pl index f86c4b944..b8493bd06 100755 --- a/test_regress/t/t_timing_delay_callstack.pl +++ b/test_regress/t/t_timing_delay_callstack.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,19 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_dlyassign.pl b/test_regress/t/t_timing_dlyassign.pl index f86c4b944..b8493bd06 100755 --- a/test_regress/t/t_timing_dlyassign.pl +++ b/test_regress/t/t_timing_dlyassign.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,19 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_events.pl b/test_regress/t/t_timing_events.pl index c469d3de3..002312d88 100755 --- a/test_regress/t/t_timing_events.pl +++ b/test_regress/t/t_timing_events.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,19 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_fork_comb.pl b/test_regress/t/t_timing_fork_comb.pl index d96687ccb..ac0e116ba 100755 --- a/test_regress/t/t_timing_fork_comb.pl +++ b/test_regress/t/t_timing_fork_comb.pl @@ -10,27 +10,22 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - # Should convert the first always into combo and detect cycle - compile( - fails => 1, - verilator_flags2 => ["--timing"], - expect => - '%Warning-UNOPTFLAT: t/t_timing_fork_comb.v:\d+:\d+: Signal unoptimizable: Circular combinational logic:' - ); +# Should convert the first always into combo and detect cycle +compile( + fails => 1, + verilator_flags2 => ["--timing"], + expect => + '%Warning-UNOPTFLAT: t/t_timing_fork_comb.v:\d+:\d+: Signal unoptimizable: Circular combinational logic:' + ); - compile( - verilator_flags2 => ["--exe --main --timing -Wno-UNOPTFLAT"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing -Wno-UNOPTFLAT"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_fork_join.pl b/test_regress/t/t_timing_fork_join.pl index 4ab3c9652..3feb337e3 100755 --- a/test_regress/t/t_timing_fork_join.pl +++ b/test_regress/t/t_timing_fork_join.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,20 +10,15 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - check_finished => 1, - expect_filename => $Self->{golden_filename}, - ); -} +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_fork_many.pl b/test_regress/t/t_timing_fork_many.pl index f86c4b944..b8493bd06 100755 --- a/test_regress/t/t_timing_fork_many.pl +++ b/test_regress/t/t_timing_fork_many.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,19 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_fork_nba.pl b/test_regress/t/t_timing_fork_nba.pl index 372246cb3..e23c975f9 100755 --- a/test_regress/t/t_timing_fork_nba.pl +++ b/test_regress/t/t_timing_fork_nba.pl @@ -10,14 +10,9 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --timing"], - ); -} +compile( + verilator_flags2 => ["--exe --timing"], + ); ok(1); 1; diff --git a/test_regress/t/t_timing_fork_no_timing_ctrl.pl b/test_regress/t/t_timing_fork_no_timing_ctrl.pl index 439181d0a..b8493bd06 100755 --- a/test_regress/t/t_timing_fork_no_timing_ctrl.pl +++ b/test_regress/t/t_timing_fork_no_timing_ctrl.pl @@ -2,7 +2,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } # DESCRIPTION: Verilator: Verilog Test driver/expect definition # -# Copyright 2023 by Antmicro Ltd. This program is free software; you +# Copyright 2023 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. @@ -10,19 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_fork_taskcall.pl b/test_regress/t/t_timing_fork_taskcall.pl index 439181d0a..b8493bd06 100755 --- a/test_regress/t/t_timing_fork_taskcall.pl +++ b/test_regress/t/t_timing_fork_taskcall.pl @@ -2,7 +2,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } # DESCRIPTION: Verilator: Verilog Test driver/expect definition # -# Copyright 2023 by Antmicro Ltd. This program is free software; you +# Copyright 2023 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. @@ -10,19 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_intra_assign.pl b/test_regress/t/t_timing_intra_assign.pl index 6852f73f7..fabe5ebc4 100755 --- a/test_regress/t/t_timing_intra_assign.pl +++ b/test_regress/t/t_timing_intra_assign.pl @@ -10,31 +10,25 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing -Wno-UNOPTFLAT"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing -Wno-UNOPTFLAT"], + make_main => 0, + ); - execute( - check_finished => 1, - expect_filename => $Self->{golden_filename}, - ); +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); - compile( - verilator_flags2 => ["--exe --main --timing -Wno-UNOPTFLAT -fno-localize"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing -Wno-UNOPTFLAT -fno-localize"], + make_main => 0, + ); - execute( - check_finished => 1, - expect_filename => $Self->{golden_filename}, - ); - -} +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_long.pl b/test_regress/t/t_timing_long.pl index 3efef3dff..834a8c4f5 100755 --- a/test_regress/t/t_timing_long.pl +++ b/test_regress/t/t_timing_long.pl @@ -56,7 +56,7 @@ gen($Self->{top_filename}); if ($Self->have_coroutines) { compile( - verilator_flags2 => ["--exe --build --main --timing"], + verilator_flags2 => ["--exe --build --main --tim" . "ing"], verilator_make_cmake => 0, verilator_make_gmake => 0, make_main => 0, diff --git a/test_regress/t/t_timing_nba.pl b/test_regress/t/t_timing_nba.pl index f86c4b944..b8493bd06 100755 --- a/test_regress/t/t_timing_nba.pl +++ b/test_regress/t/t_timing_nba.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,19 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_off.pl b/test_regress/t/t_timing_off.pl index f86c4b944..b8493bd06 100755 --- a/test_regress/t/t_timing_off.pl +++ b/test_regress/t/t_timing_off.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,19 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_pong.pl b/test_regress/t/t_timing_pong.pl index f86c4b944..b8493bd06 100755 --- a/test_regress/t/t_timing_pong.pl +++ b/test_regress/t/t_timing_pong.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,19 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_protect.pl b/test_regress/t/t_timing_protect.pl index bd2ed322d..0c17f2348 100755 --- a/test_regress/t/t_timing_protect.pl +++ b/test_regress/t/t_timing_protect.pl @@ -10,34 +10,27 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - top_filename("t/t_timing_fork_join.v"); # Contains all relevant constructs +top_filename("t/t_timing_fork_join.v"); # Contains all relevant constructs - compile( - verilator_flags2 => ["--exe --main --timing --protect-ids", - "--protect-key SECRET_KEY"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing --protect-ids", + "--protect-key SECRET_KEY"], + make_main => 0, + ); - execute( - check_finished => 1, - ); +execute( + check_finished => 1, + ); - if ($Self->{vlt_all}) { - # Check for secret in any outputs - my $any; - foreach my $filename (glob $Self->{obj_dir} . "/*.[ch]*") { - file_grep_not($filename, qr/event[123]/i); - file_grep_not($filename, qr/t_timing_fork_join/i); - $any = 1; +if ($Self->{vlt_all}) { + # Check for secret in any outputs + my $any; + foreach my $filename (glob $Self->{obj_dir} . "/*.[ch]*") { + file_grep_not($filename, qr/event[123]/i); + file_grep_not($filename, qr/t_timing_fork_join/i); + $any = 1; } $any or $Self->error("No outputs found"); - -} - } ok(1); diff --git a/test_regress/t/t_timing_reentry.pl b/test_regress/t/t_timing_reentry.pl index f86c4b944..b8493bd06 100755 --- a/test_regress/t/t_timing_reentry.pl +++ b/test_regress/t/t_timing_reentry.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,19 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_sched.pl b/test_regress/t/t_timing_sched.pl index f86c4b944..b8493bd06 100755 --- a/test_regress/t/t_timing_sched.pl +++ b/test_regress/t/t_timing_sched.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,19 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_sched_if.pl b/test_regress/t/t_timing_sched_if.pl index f86c4b944..b8493bd06 100755 --- a/test_regress/t/t_timing_sched_if.pl +++ b/test_regress/t/t_timing_sched_if.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,19 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_sched_nba.pl b/test_regress/t/t_timing_sched_nba.pl index f86c4b944..b8493bd06 100755 --- a/test_regress/t/t_timing_sched_nba.pl +++ b/test_regress/t/t_timing_sched_nba.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,19 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_strobe.pl b/test_regress/t/t_timing_strobe.pl index 4ab3c9652..3feb337e3 100755 --- a/test_regress/t/t_timing_strobe.pl +++ b/test_regress/t/t_timing_strobe.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,20 +10,15 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - check_finished => 1, - expect_filename => $Self->{golden_filename}, - ); -} +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_trace.pl b/test_regress/t/t_timing_trace.pl index 6a98bee9d..73c643cee 100755 --- a/test_regress/t/t_timing_trace.pl +++ b/test_regress/t/t_timing_trace.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,21 +10,16 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing --trace -Wno-MINTYPMAXDLY"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing --trace -Wno-MINTYPMAXDLY"], + make_main => 0, + ); - execute( - check_finished => 1, - ); +execute( + check_finished => 1, + ); - vcd_identical($Self->trace_filename, $Self->{golden_filename}); -} +vcd_identical($Self->trace_filename, $Self->{golden_filename}); ok(1); 1; diff --git a/test_regress/t/t_timing_trace_fst.pl b/test_regress/t/t_timing_trace_fst.pl index 0ac004740..261ee5e84 100755 --- a/test_regress/t/t_timing_trace_fst.pl +++ b/test_regress/t/t_timing_trace_fst.pl @@ -12,21 +12,16 @@ scenarios(simulator => 1); top_filename("t/t_timing_trace.v"); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing --trace-fst -Wno-MINTYPMAXDLY"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing --trace-fst -Wno-MINTYPMAXDLY"], + make_main => 0, + ); - execute( - check_finished => 1, - ); +execute( + check_finished => 1, + ); - fst_identical($Self->trace_filename, $Self->{golden_filename}); -} +fst_identical($Self->trace_filename, $Self->{golden_filename}); ok(1); 1; diff --git a/test_regress/t/t_timing_wait1.pl b/test_regress/t/t_timing_wait1.pl index ecf974b24..3508f0a14 100755 --- a/test_regress/t/t_timing_wait1.pl +++ b/test_regress/t/t_timing_wait1.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,19 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing -Wno-WAITCONST"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing -Wno-WAITCONST"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_wait2.pl b/test_regress/t/t_timing_wait2.pl index 3860b2943..3feb337e3 100755 --- a/test_regress/t/t_timing_wait2.pl +++ b/test_regress/t/t_timing_wait2.pl @@ -10,20 +10,15 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --timing --main"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); - execute( - check_finished => 1, - expect_filename => $Self->{golden_filename}, - ); -} +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); ok(1); 1; diff --git a/test_regress/t/t_timing_wait_long.pl b/test_regress/t/t_timing_wait_long.pl index 549b8ba35..3feb337e3 100755 --- a/test_regress/t/t_timing_wait_long.pl +++ b/test_regress/t/t_timing_wait_long.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -10,19 +10,15 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); - execute( - check_finished => 1, - expect_filename => $Self->{golden_filename}, - ); -} ok(1); 1; diff --git a/test_regress/t/t_trace_binary.pl b/test_regress/t/t_trace_binary.pl index 03fd8a3c5..8304613d5 100755 --- a/test_regress/t/t_trace_binary.pl +++ b/test_regress/t/t_trace_binary.pl @@ -10,26 +10,21 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags => [# Custom as don't want -cc - "-Mdir $Self->{obj_dir}", - "--debug-check", ], - verilator_flags2 => ['--binary --trace'], - verilator_make_cmake => 0, - verilator_make_gmake => 0, - make_main => 0, - ); +compile( + verilator_flags => [# Custom as don't want -cc + "-Mdir $Self->{obj_dir}", + "--debug-check", ], + verilator_flags2 => ['--binary --trace'], + verilator_make_cmake => 0, + verilator_make_gmake => 0, + make_main => 0, + ); - execute( - check_finished => 1, - ); +execute( + check_finished => 1, + ); - vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); -} +vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); ok(1); 1; diff --git a/test_regress/t/t_trace_binary_flag_off.pl b/test_regress/t/t_trace_binary_flag_off.pl index eaa6a3518..6de81c2ca 100755 --- a/test_regress/t/t_trace_binary_flag_off.pl +++ b/test_regress/t/t_trace_binary_flag_off.pl @@ -12,24 +12,19 @@ scenarios(vlt => 1); top_filename("t/t_trace_binary.v"); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags => [# Custom as don't want -cc - "-Mdir $Self->{obj_dir}", - "--debug-check", ], - verilator_flags2 => ['--binary'], - verilator_make_cmake => 0, - verilator_make_gmake => 0, - make_main => 0, - ); +compile( + verilator_flags => [# Custom as don't want -cc + "-Mdir $Self->{obj_dir}", + "--debug-check", ], + verilator_flags2 => ['--binary'], + verilator_make_cmake => 0, + verilator_make_gmake => 0, + make_main => 0, + ); - execute( - expect_filename => $Self->{golden_filename}, - ); -} +execute( + expect_filename => $Self->{golden_filename}, + ); ok(1); 1; diff --git a/test_regress/t/t_trace_timing1.pl b/test_regress/t/t_trace_timing1.pl index 2ae74250a..a0528ef80 100755 --- a/test_regress/t/t_trace_timing1.pl +++ b/test_regress/t/t_trace_timing1.pl @@ -10,24 +10,19 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags => [# Custom as don't want -cc - "-Mdir $Self->{obj_dir}", - "--debug-check", ], - verilator_flags2 => ['--binary --trace'], - verilator_make_cmake => 0, - verilator_make_gmake => 0, - make_main => 0, - ); +compile( + verilator_flags => [# Custom as don't want -cc + "-Mdir $Self->{obj_dir}", + "--debug-check", ], + verilator_flags2 => ['--binary --trace'], + verilator_make_cmake => 0, + verilator_make_gmake => 0, + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); vcd_identical("$Self->{obj_dir}/simx.vcd", $Self->{golden_filename}); diff --git a/test_regress/t/t_trace_ub_misaligned_address.pl b/test_regress/t/t_trace_ub_misaligned_address.pl index 6a37a1511..83dcf0fb4 100755 --- a/test_regress/t/t_trace_ub_misaligned_address.pl +++ b/test_regress/t/t_trace_ub_misaligned_address.pl @@ -10,29 +10,24 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - top_filename("t/t_trace_ub_misaligned_address.v"); +top_filename("t/t_trace_ub_misaligned_address.v"); - compile( - verilator_flags2 => ["--binary --timing --trace", - "-CFLAGS -fsanitize=address,undefined", - "-LDFLAGS -fsanitize=address,undefined"], - verilator_make_cmake => 0, - verilator_make_gmake => 0, - make_main => 0, - ); +compile( + verilator_flags2 => ["--binary --trace", + "-CFLAGS -fsanitize=address,undefined", + "-LDFLAGS -fsanitize=address,undefined"], + verilator_make_cmake => 0, + verilator_make_gmake => 0, + make_main => 0, + ); - execute( - check_finished => 1, - ); +execute( + check_finished => 1, + ); # Make sure that there are no additional messages (such as runtime messages # regarding undefined behavior). - files_identical("$Self->{obj_dir}/vlt_sim.log", $Self->{golden_filename}, "logfile"); -} +files_identical("$Self->{obj_dir}/vlt_sim.log", $Self->{golden_filename}, "logfile"); ok(1); 1; diff --git a/test_regress/t/t_vlt_timing.pl b/test_regress/t/t_vlt_timing.pl index 0b172f726..d816239d3 100755 --- a/test_regress/t/t_vlt_timing.pl +++ b/test_regress/t/t_vlt_timing.pl @@ -2,7 +2,7 @@ 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 +# Copyright 2023 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. @@ -12,19 +12,14 @@ scenarios(simulator => 1); top_filename("t/t_timing_off.v"); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - verilator_flags2 => ["--exe --main --timing t/t_vlt_timing.vlt"], - make_main => 0, - ); +compile( + verilator_flags2 => ["--exe --main --timing t/t_vlt_timing.vlt"], + make_main => 0, + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_wait_timing.pl b/test_regress/t/t_wait_timing.pl index 8c852569f..41fd8a2dd 100755 --- a/test_regress/t/t_wait_timing.pl +++ b/test_regress/t/t_wait_timing.pl @@ -10,21 +10,16 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - top_filename("t/t_wait.v"); +top_filename("t/t_wait.v"); - compile( - timing_loop => 1, - verilator_flags2 => ["--timing -Wno-WAITCONST"], - ); +compile( + timing_loop => 1, + verilator_flags2 => ["--timing -Wno-WAITCONST"], + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_while_timing_control.pl b/test_regress/t/t_while_timing_control.pl index 5f740b172..b6091c571 100755 --- a/test_regress/t/t_while_timing_control.pl +++ b/test_regress/t/t_while_timing_control.pl @@ -12,19 +12,14 @@ scenarios(simulator => 1); $Self->{main_time_multiplier} = 10e-7 / 10e-9; -if (!$Self->have_coroutines) { - skip("No coroutine support"); -} -else { - compile( - timing_loop => 1, - verilator_flags2 => ['--timing -Wno-ZERODLY'], - ); +compile( + timing_loop => 1, + verilator_flags2 => ['--timing -Wno-ZERODLY'], + ); - execute( - check_finished => 1, - ); -} +execute( + check_finished => 1, + ); ok(1); 1; From 5cf9d7851641d973bcee0275963e6f017dda5f09 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 12 Jun 2023 20:28:32 -0400 Subject: [PATCH 118/129] Commentary --- docs/guide/install.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/install.rst b/docs/guide/install.rst index 258389ec2..a862b4abb 100644 --- a/docs/guide/install.rst +++ b/docs/guide/install.rst @@ -39,7 +39,7 @@ In brief, to install from git: :: # Prerequisites: - #sudo apt-get install git help2man perl python3 make autoconf g++ flex bison ccache help2man + #sudo apt-get install git help2man perl python3 make autoconf g++ flex bison ccache #sudo apt-get install libgoogle-perftools-dev numactl perl-doc #sudo apt-get install libfl2 # Ubuntu only (ignore if gives error) #sudo apt-get install libfl-dev # Ubuntu only (ignore if gives error) From 2488af906659bd0c1e7efbd4777ffa75a1460de0 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 12 Jun 2023 20:38:33 -0400 Subject: [PATCH 119/129] Commentary: Changes update --- Changes | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/Changes b/Changes index 3a9fc7aba..17e3f1bdc 100644 --- a/Changes +++ b/Changes @@ -18,10 +18,15 @@ Verilator 5.011 devel **Minor:** +* Add --main-top-name option for C main TOP name (#4235) (#4249). [Don Williamson] +* Add creating __inputs.vpp file with --debug (#4177). [Tudor Timi] +* Add NEWERSTD warning when using feature in newer language standard (#4168) (#4172). [Ethan Sifferman] +* Add warning that timing controls in DPI exports are unsupported (#4238). [Krzysztof Bieganski, Antmicro Ltd] +* Support std::process class (#4212). [Aleksander Kiryk, Antmicro Ltd] * Support inside expressions with strings and doubles (#4138) (#4139). [Krzysztof Boroński] * Support get_randstate/set_randstate class method functions. -* Add NEWERSTD warning when using feature in newer language standard (#4168) (#4172). [Ethan Sifferman] -* Add creating __inputs.vpp file with --debug (#4177). [Tudor Timi] +* Support for condition operator on class objects (#4214). [Ryszard Rozak, Antmicro Ltd] +* Support array max (#4275). [Aleksander Kiryk, Antmicro Ltd] * Optimize VPI callValueCbs (#4155). [Hennadii Chernyshchyk] * Configure for faster C++ linking using 'mold', if it is installed. * Fix crash on duplicate imported modules (#3231). [Robert Balas] @@ -40,12 +45,28 @@ Verilator 5.011 devel * Fix forced assignments that override non-continuous assignments (#4183) (#4192). [Krzysztof Bieganski, Antmicro Ltd] * Fix wide structure VL_TOSTRING_W generation (#4188) (#4189). [Aylon Chaim Porat] * Fix references to members of parameterized base classes (#4196). [Ryszard Rozak, Antmicro Ltd] +* Fix tracing undefined alignment (#4201) (#4288) [John Wehle] +* Fix class specific same methods for AstVarScope, AstVar, and AstScope (#4203) (#4250). [John Wehle] * Fix dotted references in parameterized classes (#4206). [Ryszard Rozak, Antmicro Ltd] * Fix bit selections under parameterized classes (#4210). [Ryszard Rozak, Antmicro Ltd] * Fix duplicate std:: declaration with -I (#4215). [Harald Pretl] * Fix deep traversal of class inheritance timing (#4216). [Krzysztof Boroński] * Fix class parameters of enum types (#4219). [Ryszard Rozak, Antmicro Ltd] +* Fix static methods with prototypes (#4220). [Ryszard Rozak, Antmicro Ltd] +* Fix LATCH warning on function local variables (#4221) (#4284) [Julien Margetts] +* Fix VCD scope types (#4227) (#4282). [Àlex Torregrosa] +* Fix incorrect multi-driven lint warning (#4231) (#4248). [Adrien Le Masle] * Fix missing assignment for wide unpacked structs (#4233). [Jiamin Zhu] +* Fix unpacked struct == and != operators (#4234) (#4240). [Risto Pejašinović] +* Fix AstStructSel clean when data type is structure (#4241) (#4244). [Risto Pejašinović] +* Fix function calls in with statements (#4245). [Ryszard Rozak, Antmicro Ltd] +* Fix operator == for unpacked struct, if elements are VlUnpacked arrays (#4247). [Risto Pejašinović] +* Fix STATIC lifetime for variables created from clocking items (#4262). [Krzysztof Boroński] +* Fix names of foreach blocks (#4264). [Ryszard Rozak, Antmicro Ltd] +* Fix iterated variables in foreach loops to have VAUTOM lifetimes (#4265). [Krzysztof Boroński] +* Fix missing assignment for wide class members (#4267). [Jiamin Zhu] +* Fix the global `usesTiming` flag when forks exist (#4274). [Krzysztof Bieganski, Antmicro Ltd] +* Fix struct redefinition (#4276). [Aleksander Kiryk, Antmicro Ltd] * Fix detection of wire/reg duplicates. * Fix false IMPLICITSTATIC on package functions. * Fix method calls on function return values. From 81affad2dc7475030afcce148a634ef3f65f6b8f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 12 Jun 2023 20:41:33 -0400 Subject: [PATCH 120/129] Tests: Fix test, broke in previous commit --- test_regress/t/t_cxx_equal_to.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_regress/t/t_cxx_equal_to.pl b/test_regress/t/t_cxx_equal_to.pl index adba530eb..efd6274f5 100755 --- a/test_regress/t/t_cxx_equal_to.pl +++ b/test_regress/t/t_cxx_equal_to.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_cxx_equal_to.v"); compile( - verilator_flags2 => ['--exe --main --timing --timing --trace'], + verilator_flags2 => ['--binary --timing --trace'], verilator_make_cmake => 0, verilator_make_gmake => 0, make_main => 0, From 66c3d6d2d1cd0ed72ee4d9bd711f240b498e3c37 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 12 Jun 2023 20:52:29 -0400 Subject: [PATCH 121/129] Commentary --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 3b8977d34..d0ad3405c 100644 --- a/configure.ac +++ b/configure.ac @@ -5,7 +5,7 @@ # General Public License Version 3 or the Perl Artistic License Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -# When releasing, also update header of Changes file, +# When releasing, also update header of Changes file, and CmakeLists.txt, # and commit using "devel release" or "Version bump" message # Then 'make maintainer-dist' #AC_INIT([Verilator],[#.### YYYY-MM-DD]) From d42f76c34649856c93b8eee4a38a3be6a70d52fb Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 12 Jun 2023 21:36:23 -0400 Subject: [PATCH 122/129] Tests: Fix tests, broke in commit 3a9eeabd --- test_regress/driver.pl | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 9a9440b1b..283aaa41e 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -921,16 +921,18 @@ sub compile_vlt_flags { my %param = (%{$self}, @_); # Default arguments are from $self return 1 if $self->errors || $self->skips; - my $checkflags = ' '.join(' ', @{$param{v_flags}}, - @{$param{v_flags2}}, - @{$param{verilator_flags}}, - @{$param{verilator_flags2}}, - @{$param{verilator_flags3}}); + my $checkflags = (' '.join(' ', + @{$param{v_flags}}, + @{$param{v_flags2}}, + @{$param{verilator_flags}}, + @{$param{verilator_flags2}}, + @{$param{verilator_flags3}}) + .' '); die "%Error: specify threads via 'threads =>' argument, not as a command line option" unless ($checkflags !~ /(^|\s)-?-threads\s/); $self->{coverage} = 1 if ($checkflags =~ /-coverage\b/); $self->{savable} = 1 if ($checkflags =~ /-savable\b/); $self->{sc} = 1 if ($checkflags =~ /-sc\b/); - $self->{timing} = 1 if ($checkflags =~ /\b-?-timing\b/ || $checkflags =~ /\b-?-binary\b/ ); + $self->{timing} = 1 if ($checkflags =~ / -?-timing\b/ || $checkflags =~ / -?-binary\b/ ); $self->{trace} = ($opt_trace || $checkflags =~ /-trace\b/ || $checkflags =~ /-trace-fst\b/); $self->{trace_format} = (($checkflags =~ /-trace-fst/ && $self->{sc} && 'fst-sc') From a06f260f426d5b8315d44b893427229834bc4d16 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 12 Jun 2023 21:46:32 -0400 Subject: [PATCH 123/129] Fix C++11 compiler error with C++14 rbegin --- include/verilated_types.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/include/verilated_types.h b/include/verilated_types.h index 46a4d99b5..cbd05ad96 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -1085,14 +1085,18 @@ public: return with_func(0, a) < with_func(0, b); }); } - void rsort() { std::sort(std::rbegin(m_storage), std::rend(m_storage)); } + // std::rbegin/std::rend not available until C++14 + void rsort() { + std::sort(std::begin(m_storage), std::end(m_storage), std::greater()); + } template void rsort(Func with_func) { // with_func returns arbitrary type to use for the sort comparison - std::sort(std::rbegin(m_storage), std::rend(m_storage), + // std::rbegin/std::rend not available until C++14, so using > below + std::sort(std::begin(m_storage), std::end(m_storage), [=](const T_Value& a, const T_Value& b) { // index number is meaningless with sort, as it changes - return with_func(0, a) < with_func(0, b); + return with_func(0, a) > with_func(0, b); }); } void reverse() { std::reverse(std::begin(m_storage), std::end(m_storage)); } From 70d26ec1232f3adf1a9afc21a0c2ed65caee1919 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 12 Jun 2023 21:59:33 -0400 Subject: [PATCH 124/129] Commentary (#4211) (#4254) --- docs/CONTRIBUTORS | 1 + docs/guide/environment.rst | 32 ++++++++++++++++++++++++++------ docs/guide/install.rst | 26 ++++++++++++++------------ 3 files changed, 41 insertions(+), 18 deletions(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 56b9cd782..20c63956f 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -146,6 +146,7 @@ Stephen Henry Steven Hugg Sören Tempel Teng Huang +Tim Hutt Tim Snyder Tobias Rosenkranz Tobias Wölfel diff --git a/docs/guide/environment.rst b/docs/guide/environment.rst index dc037cc8f..a8e4b4439 100644 --- a/docs/guide/environment.rst +++ b/docs/guide/environment.rst @@ -91,9 +91,29 @@ associated programs. .. option:: VERILATOR_ROOT - Specifies the directory containing the distribution kit. This is used - to find the executable, Perl library, and include files. If not - specified, it will come from a default optionally specified at configure - time (before Verilator was compiled). It should not be specified if - using a pre-compiled Verilator package as the hard-coded value should be - correct. See :ref:`Installation`. + The ``VERILATOR_ROOT`` environment variable is used in several places: + + * At ``./configure`` time: If set, it is embedded into the binary, and + at runtime if ``VERILATOR_ROOT`` is not set, the embedded value is + used for the runtime default. + + * When ``verilator`` is run: If ``VERILATOR_ROOT`` is set it will be + used to find the ``verilator_bin`` executable (this is the actual + Verilator binary; ``verilator`` is a Perl wrapper). If not set, the + ``verilator`` script uses other methods to find ``verilator_bin`` + (looking in the same directory and falling back to ``$PATH``). + + * When ``make`` is run on the Makefile generated by ``verilator``: The + value of ``VERILATOR_ROOT`` (falling back to the value embedded in the + binary if not set) is used to find the include files + (``include/verilated.mk``). + + If you are using a pre-compiled Verilator package, you should not need + to set ``VERILATOR_ROOT`` - the value embedded in the binary should be + correct. In fact this option *does not work* with Verilator packages + that have been installed with ``make install``. If a Verilator package + has been installed using ``./configure --prefix=/some/path && make + install`` and then moved to another location, you cannot use + ``VERILATOR_ROOT`` to point to the new version. + + See :ref:`Installation` for more details. diff --git a/docs/guide/install.rst b/docs/guide/install.rst index a862b4abb..5d1021b34 100644 --- a/docs/guide/install.rst +++ b/docs/guide/install.rst @@ -202,8 +202,9 @@ These are the installation options: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Our personal favorite is to always run Verilator in-place from its Git -directory. This allows the easiest experimentation and upgrading, and -allows many versions of Verilator to co-exist on a system. +directory (don't run ``make install``). This allows the easiest +experimentation and upgrading, and allows many versions of Verilator to +co-exist on a system. :: @@ -212,10 +213,10 @@ allows many versions of Verilator to co-exist on a system. ./configure # Running will use files from $VERILATOR_ROOT, so no install needed -Note after installing (below steps), a calling program or shell must set -the environment variable :option:`VERILATOR_ROOT` to point to this Git -directory, then execute ``$VERILATOR_ROOT/bin/verilator``, which will find -the path to all needed files. +Note after installing (see `Installation`_), a calling program or shell +must set the environment variable :option:`VERILATOR_ROOT` to point to this +Git directory, then execute ``$VERILATOR_ROOT/bin/verilator``, which will +find the path to all needed files. 2. Install into a specific location @@ -233,7 +234,8 @@ location include the Verilator version name: # For the tarball, use the version number instead of git describe ./configure --prefix /CAD_DISK/verilator/`git describe | sed "s/verilator_//"` -Note after installing (below steps), if you use `modulecmd +Note after installing (see `Installation`_), you need to add the path to +the ``bin`` directory to your ``PATH``. Or, if you use `modulecmd `__, you'll want a module file like the following: @@ -246,11 +248,11 @@ following: prepend-path PKG_CONFIG_PATH $install_root/share/pkgconfig -3. Install into a Specific Path -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +3. Install into a Specific Prefix +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ You may eventually install Verilator into a specific installation prefix, -as most GNU tools support: +as follows. This option is typically only used by OS package maintainers. :: @@ -274,8 +276,8 @@ configure's default system paths: unsetenv VERILATOR_ROOT # if your shell is csh ./configure -Then after installing (below), the binaries should be in a location -already in your ``$PATH`` environment variable. +Then after installing (see `Installation`_), the binaries should be in a +location already in your ``$PATH`` environment variable. Configure From e08bbcdb07b8db18d19f896c17554daa04efd99f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 12 Jun 2023 21:59:52 -0400 Subject: [PATCH 125/129] Commentary --- Changes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Changes b/Changes index 17e3f1bdc..1f77cc707 100644 --- a/Changes +++ b/Changes @@ -65,7 +65,7 @@ Verilator 5.011 devel * Fix names of foreach blocks (#4264). [Ryszard Rozak, Antmicro Ltd] * Fix iterated variables in foreach loops to have VAUTOM lifetimes (#4265). [Krzysztof Boroński] * Fix missing assignment for wide class members (#4267). [Jiamin Zhu] -* Fix the global `usesTiming` flag when forks exist (#4274). [Krzysztof Bieganski, Antmicro Ltd] +* Fix the global uses timing flag when forks exist (#4274). [Krzysztof Bieganski, Antmicro Ltd] * Fix struct redefinition (#4276). [Aleksander Kiryk, Antmicro Ltd] * Fix detection of wire/reg duplicates. * Fix false IMPLICITSTATIC on package functions. From 0dc887720d67480324011753ce82bb4af4f2e332 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 12 Jun 2023 22:38:45 -0400 Subject: [PATCH 126/129] Tests: Fix tests, broke in commit 3a9eeabd --- test_regress/t/t_timing_protect.pl | 39 ++++++++++++++++++------------ 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/test_regress/t/t_timing_protect.pl b/test_regress/t/t_timing_protect.pl index 0c17f2348..bd2ed322d 100755 --- a/test_regress/t/t_timing_protect.pl +++ b/test_regress/t/t_timing_protect.pl @@ -10,27 +10,34 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -top_filename("t/t_timing_fork_join.v"); # Contains all relevant constructs +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + top_filename("t/t_timing_fork_join.v"); # Contains all relevant constructs -compile( - verilator_flags2 => ["--exe --main --timing --protect-ids", - "--protect-key SECRET_KEY"], - make_main => 0, - ); + compile( + verilator_flags2 => ["--exe --main --timing --protect-ids", + "--protect-key SECRET_KEY"], + make_main => 0, + ); -execute( - check_finished => 1, - ); + execute( + check_finished => 1, + ); -if ($Self->{vlt_all}) { - # Check for secret in any outputs - my $any; - foreach my $filename (glob $Self->{obj_dir} . "/*.[ch]*") { - file_grep_not($filename, qr/event[123]/i); - file_grep_not($filename, qr/t_timing_fork_join/i); - $any = 1; + if ($Self->{vlt_all}) { + # Check for secret in any outputs + my $any; + foreach my $filename (glob $Self->{obj_dir} . "/*.[ch]*") { + file_grep_not($filename, qr/event[123]/i); + file_grep_not($filename, qr/t_timing_fork_join/i); + $any = 1; } $any or $Self->error("No outputs found"); + +} + } ok(1); From 01d0f0327b52d23d9130d369ed9b99a936ab1158 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 13 Jun 2023 08:22:57 -0400 Subject: [PATCH 127/129] Commentary (#4254) --- docs/guide/install.rst | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/docs/guide/install.rst b/docs/guide/install.rst index 5d1021b34..81da117c9 100644 --- a/docs/guide/install.rst +++ b/docs/guide/install.rst @@ -219,11 +219,12 @@ Git directory, then execute ``$VERILATOR_ROOT/bin/verilator``, which will find the path to all needed files. -2. Install into a specific location -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2. Install into a Specific Prefix +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -You may eventually be installing onto a project/company-wide "CAD" tools -disk that may support multiple versions of every tool. Tell configure the +You may be an OS package maintainer building a Verilator package, or you +may eventually be installing onto a project/company-wide "CAD" tools disk +that may support multiple versions of every tool. Tell configure the eventual destination directory name. We recommend that the destination location include the Verilator version name: @@ -248,23 +249,7 @@ following: prepend-path PKG_CONFIG_PATH $install_root/share/pkgconfig -3. Install into a Specific Prefix -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -You may eventually install Verilator into a specific installation prefix, -as follows. This option is typically only used by OS package maintainers. - -:: - - unset VERILATOR_ROOT # if your shell is bash - unsetenv VERILATOR_ROOT # if your shell is csh - ./configure --prefix /opt/verilator-VERSION - -Then after installing (below steps), you will need to add -``/opt/verilator-VERSION/bin`` to your ``$PATH`` environment variable. - - -4. Install System Globally +3. Install System Globally ^^^^^^^^^^^^^^^^^^^^^^^^^^ The final option is to eventually install Verilator globally, using From 48e98ea2bd49453b74bf612f377853f91eb30fd4 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 13 Jun 2023 08:52:13 -0400 Subject: [PATCH 128/129] Internals: Sort some error codes (#4253). No functional change intended. --- src/V3Error.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/V3Error.h b/src/V3Error.h index 8a7902e01..da7a17a9b 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -54,17 +54,17 @@ public: // Boolean information we track per-line, but aren't errors I_CELLDEFINE, // Inside cell define from `celldefine/`endcelldefine I_COVERAGE, // Coverage is on/off from /*verilator coverage_on/off*/ - I_TRACING, // Tracing is on/off from /*verilator tracing_on/off*/ - I_LINT, // All lint messages - I_UNUSED, // Unused genvar, parameter or signal message (Backward Compatibility) I_DEF_NETTYPE_WIRE, // `default_nettype is WIRE (false=NONE) + I_LINT, // All lint messages I_TIMING, // Enable timing from /*verilator timing_on/off*/ + I_TRACING, // Tracing is on/off from /*verilator tracing_on/off*/ + I_UNUSED, // Unused genvar, parameter or signal message (Backward Compatibility) // Error codes: - E_PORTSHORT, // Error: Output port is connected to a constant, electrical short - E_UNSUPPORTED, // Error: Unsupported (generally) - E_TASKNSVAR, // Error: Task I/O not simple E_NEEDTIMINGOPT, // Error: --timing/--no-timing option not specified E_NOTIMING, // Timing control encountered with --no-timing + E_PORTSHORT, // Error: Output port is connected to a constant, electrical short + E_TASKNSVAR, // Error: Task I/O not simple + E_UNSUPPORTED, // Error: Unsupported (generally) // // Warning codes: EC_FIRST_WARN, // Just a code so the program knows where to start warnings @@ -156,10 +156,10 @@ public: VARHIDDEN, // Hiding variable WAITCONST, // Wait condition is constant WIDTH, // Width mismatch - WIDTHTRUNC, // Width mismatch- lhs < rhs - WIDTHEXPAND, // Width mismatch- lhs > rhs - WIDTHXZEXPAND, // Width mismatch- lhs > rhs xz filled WIDTHCONCAT, // Unsized numbers/parameters in concatenations + WIDTHEXPAND, // Width mismatch- lhs > rhs + WIDTHTRUNC, // Width mismatch- lhs < rhs + WIDTHXZEXPAND, // Width mismatch- lhs > rhs xz filled ZERODLY, // #0 delay _ENUM_MAX // ***Add new elements below also*** @@ -181,9 +181,9 @@ public: // Leading spaces indicate it can't be disabled. " MIN", " INFO", " FATAL", " FATALEXIT", " FATALSRC", " ERROR", " FIRST_NAMED", // Boolean - " I_CELLDEFINE", " I_COVERAGE", " I_TRACING", " I_LINT", " I_UNUSED", " I_DEF_NETTYPE_WIRE", " I_TIMING", + " I_CELLDEFINE", " I_COVERAGE", " I_DEF_NETTYPE_WIRE", " I_LINT", " I_TIMING", " I_TRACING", " I_UNUSED", // Errors - "PORTSHORT", "UNSUPPORTED", "TASKNSVAR", "NEEDTIMINGOPT", "NOTIMING", + "NEEDTIMINGOPT", "NOTIMING", "PORTSHORT", "TASKNSVAR", "UNSUPPORTED", // Warnings " EC_FIRST_WARN", "ALWCOMBORDER", "ASCRANGE", "ASSIGNDLY", "ASSIGNIN", "BADSTDPRAGMA", @@ -204,7 +204,7 @@ public: "UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS", "UNPACKED", "UNSIGNED", "UNUSEDGENVAR", "UNUSEDPARAM", "UNUSEDSIGNAL", "USERERROR", "USERFATAL", "USERINFO", "USERWARN", - "VARHIDDEN", "WAITCONST", "WIDTH", "WIDTHTRUNC", "WIDTHEXPAND", "WIDTHXZEXPAND", "WIDTHCONCAT", "ZERODLY", + "VARHIDDEN", "WAITCONST", "WIDTH", "WIDTHCONCAT", "WIDTHEXPAND", "WIDTHTRUNC", "WIDTHXZEXPAND", "ZERODLY", " MAX" }; // clang-format on From 7d2d32420a630befa4097170ecbf227e04e32522 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 13 Jun 2023 19:31:57 -0400 Subject: [PATCH 129/129] Version bump --- CMakeLists.txt | 2 +- Changes | 2 +- configure.ac | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0377c4d08..13957138e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ cmake_minimum_required(VERSION 3.15) cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime project(Verilator - VERSION 5.011 + VERSION 5.012 HOMEPAGE_URL https://verilator.org LANGUAGES CXX ) diff --git a/Changes b/Changes index 1f77cc707..daf8c20ad 100644 --- a/Changes +++ b/Changes @@ -8,7 +8,7 @@ The changes in each Verilator version are described below. The contributors that suggested a given feature are shown in []. Thanks! -Verilator 5.011 devel +Verilator 5.012 2023-06-13 ========================== **Major:** diff --git a/configure.ac b/configure.ac index d0ad3405c..51af31653 100644 --- a/configure.ac +++ b/configure.ac @@ -10,7 +10,7 @@ # Then 'make maintainer-dist' #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[5.011 devel], +AC_INIT([Verilator],[5.012 2023-06-13], [https://verilator.org], [verilator],[https://verilator.org])