diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index d0dfeccb7..7817a3bf6 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -158,7 +158,7 @@ jobs: with: path: repo - name: Cache $CCACHE_DIR - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5 with: path: ${{ env.CCACHE_DIR }} key: msbuild-msvc-cmake diff --git a/.github/workflows/reusable-build.yml b/.github/workflows/reusable-build.yml index 5d053cadb..87a4052d7 100644 --- a/.github/workflows/reusable-build.yml +++ b/.github/workflows/reusable-build.yml @@ -68,7 +68,7 @@ jobs: fetch-depth: ${{ inputs.dev-gcov && '0' || '1' }} # Coverage flow needs full history - name: Cache $CCACHE_DIR - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5 env: CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache with: diff --git a/.github/workflows/reusable-rtlmeter-build.yml b/.github/workflows/reusable-rtlmeter-build.yml index cdfee423a..b38ed62cf 100644 --- a/.github/workflows/reusable-rtlmeter-build.yml +++ b/.github/workflows/reusable-rtlmeter-build.yml @@ -50,7 +50,7 @@ jobs: sudo apt install ccache mold help2man libfl-dev libjemalloc-dev libsystemc-dev - name: Use saved ccache - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5 with: path: ccache key: rtlmeter-build-ccache-${{ inputs.runs-on }}-${{ inputs.cc }}-${{ inputs.sha }}-${{ github.run_id }}-${{ github.run_attempt }} diff --git a/.github/workflows/reusable-rtlmeter-run.yml b/.github/workflows/reusable-rtlmeter-run.yml index 81aaad405..ab66647db 100644 --- a/.github/workflows/reusable-rtlmeter-run.yml +++ b/.github/workflows/reusable-rtlmeter-run.yml @@ -84,7 +84,7 @@ jobs: - name: Use saved ccache if: ${{ env.CCACHE_DISABLE == 0 }} - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5 with: path: ${{ env.CCACHE_DIR }} key: rtlmeter-run-ccache-${{ inputs.runs-on }}-${{ inputs.cc }}-${{ inputs.cases }}-${{ inputs.compileArgs }}-${{ github.run_id }}-${{ github.run_attempt }} diff --git a/.github/workflows/reusable-test.yml b/.github/workflows/reusable-test.yml index efc9c50fe..ffec26b84 100644 --- a/.github/workflows/reusable-test.yml +++ b/.github/workflows/reusable-test.yml @@ -67,7 +67,7 @@ jobs: ls -lsha - name: Cache $CCACHE_DIR - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5 env: CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache2 with: diff --git a/CMakeLists.txt b/CMakeLists.txt index eb5682e7b..6fa5e2ffc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ cmake_minimum_required(VERSION 3.15) cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime project( Verilator - VERSION 5.049 + VERSION 5.051 HOMEPAGE_URL https://verilator.org LANGUAGES CXX ) diff --git a/Changes b/Changes index 438a8c265..9ae1a40ee 100644 --- a/Changes +++ b/Changes @@ -10,7 +10,21 @@ The changes in each Verilator version are described below. The contributors that suggested or implemented a given issue are shown in []. Thanks! -Verilator 5.049 devel +Verilator 5.051 devel +========================== + +**Other:** + +* Add comments as a branch description in coverage .info files (#7843). [Eryk Szpotanski] +* Optimize random initialization. [Geza Lore, Testorrent USA, Inc.] +* Fix DFG misoptimizing bound checks (#7755). [Jakub Michalski] +* Fix unique0 case side effects (#7787). [Pawel Klopotek] +* Fix cleaning purity cache after assertions. [Geza Lore, Testorrent USA, Inc.] +* Fix clang++ ambiguous overload of '==' operator (#7863). [Pawel Kojma, Antmicro Ltd.] +* Fix heap-use-after-free in `VlRNG::VlRNG()` (#7865). [Dragon-Git] + + +Verilator 5.050 2026-07-01 ========================== **Important:** @@ -32,7 +46,7 @@ Verilator 5.049 devel * Improve `--coverage-fsm` (#7490) (#7529) (#7561) (#7573) (#7619). [Yogish Sekhar] * Change `+verilator+seed` to default to 1, and 0 to randomly select (#7325) (#7516). [Miguel] * Change JSON to include parameter constant mnemonics for FSM Coverage (#7531). [Yogish Sekhar] -* Support assert property 'default disable iff` (#4848) (#7723). [Artur Bieniek, Antmicro Ltd.] +* Support assert property `default disable iff` (#4848) (#7723). [Artur Bieniek, Antmicro Ltd.] * Support printing enum names for %p and %s (#5523) (#7338 repair) (#7521) (#7527). [Nick Brereton] * Support weak `until` / `until_with` property operators (#7290) (#7548) (#7685). [Yilou Wang] * Support `s_eventually` (#7291) (#7508). [Bartłomiej Chmiel, Antmicro Ltd.] @@ -67,6 +81,7 @@ Verilator 5.049 devel * Support property case (#7682) (#7721). [Artur Bieniek, Antmicro Ltd.] * Support `s_until` and `s_until_with`(#7722). [Artur Bieniek, Antmicro Ltd.] * Support covergroup runtime model Phase A1 (#7728). [Matthew Ballance] +* Support hierarchical reference cross members (#7749) (#7820). [Matthew Ballance] * Support reduction XOR/AND operations in constraints (#7753). [Kornel Uriasz, Antmicro Ltd.] * Support NBAs in initial blocks (#7754). [Igor Zaworski, Antmicro Ltd.] * Support assertion control system tasks in classes and interfaces (#7761). [Yilou Wang] @@ -75,6 +90,11 @@ Verilator 5.049 devel * Support $assertcontrol control_type from lock to kill (#7788). [Yilou Wang] * Support unbounded always [m:$] and strong s_always liveness (#7798). [Yilou Wang] * Support method calls on a sub-interface via a virtual interface (#7800). [Yilou Wang] +* Support global $assertcontrol (#7807). [Artur Bieniek, Antmicro Ltd.] +* Support VPI access to unpacked struct members (#7823). [Nick Brereton] +* Support variable-length intersect in SVA sequences (#7835). [Yilou Wang] +* Support dynamic loading of VPI extensions (#7727). [Matthew Ballance] +* Optimize DFG cycle breaking to do less work (#7210). [Geza Lore, Testorrent USA, Inc.] * Optimize emitting to_string() for compiler speedup (#7468). [Jakub Michalski, Antmicro Ltd.] * Optimize additional DFG peephole cases (#7553). [Varun Koyyalagunta, Testorrent USA, Inc.] * Optimize forced signal handling (#7554 partial) (#7572) (#7594) (#7596). [Krzysztof Bieganski, Artur Bieniek, Antmicro Ltd.] @@ -97,7 +117,12 @@ Verilator 5.049 devel * Optimize input combinational logic by change detection (#7784). [Geza Lore, Testorrent USA, Inc.] * Optimize decoder case statements into lookup tables (#7795). [Geza Lore, Testorrent USA, Inc.] * Optimize wide decoder case statements into decoder expressions (#7804). [Geza Lore, Testorrent USA, Inc.] -* Optimize DFG cycle breaking to do less work (#7210). [Geza Lore, Testorrent USA, Inc.] +* Optimize statically known oversize shifts (#7806). [Geza Lore, Testorrent USA, Inc.] +* Optimize generated function inlining (#7811). [Geza Lore, Testorrent USA, Inc.] +* Optimize bit-scan loops into most-set-bit or $countones (#7822). [Thomas Santerre] +* Optimize additional expression patterns (#7824). [Geza Lore, Testorrent USA, Inc.] +* Optimize module inlining heuristic (#7837). [Geza Lore, Testorrent USA, Inc.] +* Fix `$bits` on unpacked structs (#4521) (#7796). [Nick Brereton] * Fix TSP variable ordering for mtasks (#5342) (#7610). [Muzaffer Kal] * Fix inlining static initializer in V3Gate (#5381) (#7503). [Andrew Nolte] [Geza Lore, Testorrent USA, Inc.] * Fix timed nested fork block with disable (#6720) (#7743). [Marco Bartoli] @@ -147,6 +172,7 @@ Verilator 5.049 devel * Fix reference counting for modport task references (#7628). [Nick Brereton] * Fix internal error when handling typedefs containing parameterized class type members (#7635) (#7661). [em2machine] * Fix forceable signal with a procedural continuous assign (#7638) (#7639). [Zubin Jain] +* Fix scheduling of virtual interface method writes (#7641). [Artur Bieniek, Antmicro Ltd.] * Fix implicit conversions of VlWide (#7642). [Geza Lore, Testorrent USA, Inc.] * Fix CASEINCOMPLETE to not warn on `unique0 case` (#7647). * Fix hierarchical coverage counts for duplicate no-inline module instances (#7649). [Yogish Sekhar] @@ -173,17 +199,29 @@ Verilator 5.049 devel * Fix s_eventually in parameterized interfaces (#7741). [Nick Brereton] * Fix dpi export pointers (#7742) (#7751). [Yilin Li] * Fix force on unpacked bit select (#7744) (#7745). [Nikolai Kumar] +* Fix `$` as unsupported coverpoint-bin range bounds (#7750) (#7825). [Matthew Ballance] * Fix FSM detect unchecked casts and variable redeclaration (#7758). [Adam Kostrzewski, Antmicro Ltd.] * Fix no-scope internal error on virtual interface method calls (#7759). [Yilou Wang] -* Fix 'case (_) inside' with x wildcards (#7766). [Geza Lore, Testorrent USA, Inc.] +* Fix `case (_) inside` with x wildcards (#7766). [Geza Lore, Testorrent USA, Inc.] * Fix not failing assertion when RHS of a range window rejects once (#7773). [Artur Bieniek, Antmicro Ltd.] * Fix $fflush and autoflush with --threads (#7782). * Fix out-of-bounds read value for 2-state types (#7785). [Jakub Michalski] * Fix `cover property` of an implication counting vacuous matches (#7789). [Yilou Wang] * Fix randomization of dynamic arrays of objects (#7790). [Ryszard Rozak, Antmicro Ltd.] -* Fix `$bits` on unpacked structs (#4521) (#7796). [Nick Brereton] * Fix randomize() with skipping derived pre/post_randomize (#7799). [Yilou Wang] +* Fix skewed dist operator for arrays (#7802). [Jakub Wasilewski, Antmicro Ltd.] * Fix assertion when loop unrolling failed (#7810). [Geza Lore, Testorrent USA, Inc.] +* Fix CASEINCOMPLETE for all uncovered enum items (#7815) (#7817). [Saksham] +* Fix split optimization nested-class crash (#7826). [Igor Zaworski, Antmicro Ltd.] +* Fix class/var named identically to an enclosing-scope type (#7827) (#7828). [Tom Jackson] +* Fix performance on large package-scoped structs (#7830). [Wolfgang Mayerwieser] +* Fix unclocked concurrent assertion misreported as unsupported (#7831). [Yilou Wang] +* Fix insertion of expression coverage statement (#7832). [Ryszard Rozak, Antmicro Ltd.] +* Fix lifetime of expression coverage variable (#7834). [Ryszard Rozak, Antmicro Ltd.] +* Fix disable iff ignored when its condition is held continuously true (#7841). [Yilou Wang] +* Fix constant pool cache after dead scope removal (#7845). [Nick Brereton] +* Fix covergroups without --coverage (#7848) (#7849). [Joshua Leahy] +* Fix class scope '::' reference through an inherited type parameter (#7844). [Sergey Chusov] Verilator 5.048 2026-04-26 @@ -520,7 +558,7 @@ Verilator 5.044 2026-01-01 * Support clocking output delay `1step` (#6681). [Ondrej Ille] * Support parsing of dotted `bins_expression` (#6683). [Pawel Kojma, Antmicro Ltd.] * Support constant expression cycle delays in sequences (#6691). [Ryszard Rozak, Antmicro Ltd.] -* Support general global constraints (#6709) (#6711). [Yilou Wang] +* Support general global constraints (#6709) (#6711) (#7833) (#7838). [Yilou Wang] * Support complex std::randomize patterns (#6736) (#6737). [Yilou Wang] * Support `rand_mode` in global constraint gathering (#6740) (#6752). [Yilou Wang] * Support reduction or in constraints (#6840). [Pawel Kojma, Antmicro Ltd.] @@ -5714,7 +5752,7 @@ Verilator 3.104 2003-04-30 **Major:** * Indicate direction of ports with VL_IN and VL_OUT. -* Allow $c32, etc, to specify width of the $c statement for VCS. +* Allow $c32, etc, to specify width of the $c statement. * Numerous performance improvements, worth about 25% **Minor:** diff --git a/bin/verilator b/bin/verilator index 57fd60507..cb866e243 100755 --- a/bin/verilator +++ b/bin/verilator @@ -653,6 +653,7 @@ description of these arguments. +verilator+solver+file+ Set random solver log filename +verilator+V Show verbose version and config +verilator+version Show version and exit + +verilator+vpi+[:] Load VPI shared library +verilator+wno+unsatconstr+ Disable constraint warnings diff --git a/configure.ac b/configure.ac index 6917f0c4b..6376593ad 100644 --- a/configure.ac +++ b/configure.ac @@ -12,7 +12,7 @@ # Then 'make maintainer-dist' #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[5.049 devel], +AC_INIT([Verilator],[5.051 devel], [https://verilator.org], [verilator],[https://verilator.org]) @@ -589,6 +589,34 @@ m4_foreach([ldflag], [ AC_SUBST(CFG_LDLIBS_THREADS) AC_SUBST(CFG_LDFLAGS_THREADS_CMAKE) +# Find link flags for runtime VPI library loading (+verilator+vpi+). +# The model executable must export its VPI symbols so the dlopen'd library can +# resolve them: -rdynamic (GNU ld) or -Wl,-export_dynamic (Darwin); the first the +# linker accepts wins. -ldl provides dlopen/dlsym where it is a separate library. +_MY_LDLIBS_CHECK_SET(CFG_LDFLAGS_DYNAMIC, -rdynamic) +# -Wl,-export_dynamic contains a comma, so probe it directly rather than through +# the _MY_LDLIBS_CHECK_* macros (which re-expand their flag argument unquoted). +if test "$CFG_LDFLAGS_DYNAMIC" = ""; then + ACO_SAVE_LIBS="$LIBS" + LIBS="$LIBS -Wl,-export_dynamic" + AC_MSG_CHECKING([whether $CXX linker accepts -Wl,-export_dynamic]) + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[]])], + [_my_result=yes + if test -s conftest.err; then + if grep -e "-export_dynamic" conftest.err >/dev/null; then + _my_result=no + fi + fi], + [_my_result=no]) + AC_MSG_RESULT($_my_result) + LIBS="$ACO_SAVE_LIBS" + if test "$_my_result" = "yes"; then CFG_LDFLAGS_DYNAMIC="-Wl,-export_dynamic"; fi +fi +AC_SUBST(CFG_LDFLAGS_DYNAMIC) +_MY_LDLIBS_CHECK_OPT(CFG_LDLIBS_DYNAMIC, -ldl) +AC_SUBST(CFG_LDLIBS_DYNAMIC) + # 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) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 44f7ecb2c..24e3ced87 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -61,6 +61,7 @@ David Turner Dercury Diego Roux Dominick Grochowina +Dragon-Git Don Williamson Drew Ranck Drew Taussig @@ -69,6 +70,7 @@ Edgar E. Iglesias Eric Mejdrich Eric Müller Eric Rippey +Eryk Szpotański Eunseo Song Ethan Sifferman Eyck Jentzsch @@ -146,6 +148,7 @@ Jose Loyola Josep Sans Joseph Nwabueze Josh Redford +Joshua Leahy Julian Carrier Julian Daube Julie Schwartz @@ -257,6 +260,7 @@ Samuel Riedel Sean Cross Sebastien Van Cauwenberghe Secturion +Sergey Chusov Sergey Fedorov Sergi Granell Seth Pellegrino @@ -273,6 +277,7 @@ Teng Huang Thomas Aldrian Thomas Brown Thomas Dybdahl Ahle +Thomas Santerre Tim Hutt Tim Snyder Tobias Jensen @@ -301,6 +306,7 @@ Vito Gamberini Wei-Lun Chiu William D. Jones Wilson Snyder +Wolfgang Mayerwieser Xi Zhang Yan Xu Yangyu Chen diff --git a/docs/guide/connecting.rst b/docs/guide/connecting.rst index 1d714ce4e..35ec9742b 100644 --- a/docs/guide/connecting.rst +++ b/docs/guide/connecting.rst @@ -179,7 +179,7 @@ DPI Example In the SYSTEMC example above, if you wanted to import C++ functions into Verilog, put in our.v: -.. code-block:: sv +.. code-block:: import "DPI-C" function int add (input int a, input int b); @@ -211,7 +211,7 @@ Verilator extends the DPI format to allow using the same scheme to efficiently add system functions. Use a dollar-sign prefixed system function name for the import, but note it must be escaped. -.. code-block:: sv +.. code-block:: import "DPI-C" function integer \$myRand; diff --git a/docs/guide/exe_sim.rst b/docs/guide/exe_sim.rst index ac2b73f16..190367346 100644 --- a/docs/guide/exe_sim.rst +++ b/docs/guide/exe_sim.rst @@ -139,6 +139,20 @@ Options: Displays program version and exits. +.. option:: +verilator+vpi+[:] + + Load a VPI shared library before simulation starts. Only available when the + model was Verilated with :vlopt:`--vpi` and :vlopt:`--main` (or + :vlopt:`--binary`). ```` is the path to the shared library. If + ``:`` is given, that named no-argument function is called; + otherwise the library's ``vlog_startup_routines`` array (IEEE 1800 38.37.2) is + invoked. May be repeated to load multiple libraries. + + Runtime loading is supported on POSIX platforms only (it relies on the + executable exporting its VPI symbols to the loaded library); on Windows the + argument is rejected and the VPI code must instead be statically linked + into the model. + .. option:: +verilator+wno+unsatconstr+ Disable unsatisfied constraint warnings at simulation runtime. When set to diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index 952500400..807216565 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -662,6 +662,10 @@ Summary: .. option:: -fno-assemble +.. option:: -fno-bit-scan-loops + + Rarely needed. Disable converting bit counting loops into built-in operations. + .. option:: -fno-case Rarely needed. Disable all case statement optimizations. diff --git a/docs/spelling.txt b/docs/spelling.txt index fa7fae5e9..f99491317 100644 --- a/docs/spelling.txt +++ b/docs/spelling.txt @@ -477,6 +477,7 @@ Syms Synopsys SystemC SystemVerilog +Szpotanski Takatsukasa Tambe Tarik @@ -537,6 +538,7 @@ Verilog Vighnesh Viktor Vilp +VlRNG VlWide Vlip Vm @@ -684,6 +686,7 @@ countones cout covergroup covergroups +coverpoint coverpoints cpp cppstyle @@ -946,6 +949,7 @@ misconnected misconversion misdetecting misoptimized +misoptimizing missized mk mno @@ -1207,6 +1211,7 @@ typename uint un unbased +unclocked uncomment undef undefineall diff --git a/include/verilated.cpp b/include/verilated.cpp index 9cbb58ffc..d981f7c0a 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -89,6 +89,12 @@ # include # define _VL_HAVE_GETRLIMIT #endif +#if VM_VPI +# include +# ifndef _WIN32 +# include // dlopen +# endif +#endif #include "verilated_threads.h" // clang-format on @@ -260,6 +266,58 @@ void VL_WARN_MT(const char* filename, int linenum, const char* hier, const char* }}); } +//=========================================================================== +// Runtime VPI shared library loading (--vpi) + +// Load one VPI shared library named by a +verilator+vpi+[:] argument. +// 'arg' is the payload after the prefix: either "" (invoke the library's +// vlog_startup_routines array) or ":" (invoke the named bootstrap). +void Verilated::loadVpiLib(const std::string& arg) VL_MT_UNSAFE { +#if VM_VPI + if (arg.empty()) return; +#ifdef _WIN32 + VL_FATAL_MT("", 0, "", + "+verilator+vpi+: runtime VPI library loading is not supported on" + " Windows; link the VPI code into the model instead"); +#else + using vlog_startup_t = void (*)(); + // Split : on the last ':' + const std::string::size_type colon_pos = arg.rfind(':'); + const bool has_entry = (colon_pos != std::string::npos); + const std::string libpath = has_entry ? arg.substr(0, colon_pos) : arg; + const std::string entry_name = has_entry ? arg.substr(colon_pos + 1) : std::string{}; + void* handle = dlopen(libpath.c_str(), RTLD_LAZY); + if (!handle) + // The library path is stable; the dlerror() text is platform-specific, so put it on + // a separate "- " line (test golden files strip "- " lines, keeping output portable). + VL_FATAL_MT( + "", 0, "", + (std::string{"Cannot load VPI library: "} + libpath + "\n- dlerror: " + dlerror()) + .c_str()); + if (has_entry) { + vlog_startup_t bsp = reinterpret_cast(dlsym(handle, entry_name.c_str())); + if (!bsp) + VL_FATAL_MT( + "", 0, "", + (std::string{"Cannot find VPI bootstrap '"} + entry_name + "' in: " + libpath) + .c_str()); + bsp(); + } else { + vlog_startup_t* routinesp + = reinterpret_cast(dlsym(handle, "vlog_startup_routines")); + if (!routinesp) + VL_FATAL_MT( + "", 0, "", + (std::string{"Cannot find 'vlog_startup_routines' in: "} + libpath).c_str()); + for (int j = 0; routinesp[j]; ++j) routinesp[j](); + } +#endif +#else + // Never reached: the command-line handler only calls this when compiled with --vpi. + (void)arg; +#endif +} + //=========================================================================== // Debug prints @@ -319,7 +377,6 @@ void VL_PRINTF_MT(const char* formatp, ...) VL_MT_SAFE { } void VL_FFLUSH_MT() VL_MT_SAFE { - va_list ap; VerilatedThreadMsgQueue::post(VerilatedMsg{[=]() { // Verilated::runFlushCallbacks(); }}); @@ -506,9 +563,10 @@ IData VL_URANDOM_SEEDED_II(IData seed) VL_MT_SAFE { } IData VL_SCOPED_RAND_RESET_I(int obits, uint64_t scopeHash, uint64_t salt) VL_MT_UNSAFE { - if (Verilated::threadContextp()->randReset() == 0) return 0; + const int randReset = Verilated::threadContextp()->randReset(); + if (randReset == 0) return 0; IData data = ~0; - if (Verilated::threadContextp()->randReset() != 1) { // if 2, randomize + if (randReset != 1) { // if 2, randomize VlRNG rng{Verilated::threadContextp()->randSeed() ^ scopeHash ^ salt}; data = rng.rand64(); } @@ -517,9 +575,10 @@ IData VL_SCOPED_RAND_RESET_I(int obits, uint64_t scopeHash, uint64_t salt) VL_MT } QData VL_SCOPED_RAND_RESET_Q(int obits, uint64_t scopeHash, uint64_t salt) VL_MT_UNSAFE { - if (Verilated::threadContextp()->randReset() == 0) return 0; + const int randReset = Verilated::threadContextp()->randReset(); + if (randReset == 0) return 0; QData data = ~0ULL; - if (Verilated::threadContextp()->randReset() != 1) { // if 2, randomize + if (randReset != 1) { // if 2, randomize VlRNG rng{Verilated::threadContextp()->randSeed() ^ scopeHash ^ salt}; data = rng.rand64(); } @@ -529,10 +588,17 @@ QData VL_SCOPED_RAND_RESET_Q(int obits, uint64_t scopeHash, uint64_t salt) VL_MT WDataOutP VL_SCOPED_RAND_RESET_W(int obits, WDataOutP outwp, uint64_t scopeHash, uint64_t salt) VL_MT_UNSAFE { - if (Verilated::threadContextp()->randReset() != 2) { return VL_RAND_RESET_W(obits, outwp); } - VlRNG rng{Verilated::threadContextp()->randSeed() ^ scopeHash ^ salt}; - for (int i = 0; i < VL_WORDS_I(obits) - 1; ++i) outwp[i] = rng.rand64(); - outwp[VL_WORDS_I(obits) - 1] = rng.rand64() & VL_MASK_E(obits); + const int words = VL_WORDS_I(obits); + const int randReset = Verilated::threadContextp()->randReset(); + if (randReset == 0) { + VL_MEMSET_ZERO_W(outwp, words); + } else if (randReset == 1) { + VL_MEMSET_ONES_W(outwp, words); + } else { + VlRNG rng{Verilated::threadContextp()->randSeed() ^ scopeHash ^ salt}; + for (int i = 0; i < words; ++i) outwp[i] = rng.rand64(); + } + outwp[words - 1] &= VL_MASK_E(obits); return outwp; } @@ -557,30 +623,14 @@ WDataOutP VL_SCOPED_RAND_RESET_ASSIGN_W(int obits, WDataOutP outwp, uint64_t sco } IData VL_RAND_RESET_I(int obits) VL_MT_SAFE { - if (Verilated::threadContextp()->randReset() == 0) return 0; + const int randReset = Verilated::threadContextp()->randReset(); + if (randReset == 0) return 0; IData data = ~0; - if (Verilated::threadContextp()->randReset() != 1) { // if 2, randomize - data = VL_RANDOM_I(); - } + if (randReset != 1) data = VL_RANDOM_I(); // if 2, randomize data &= VL_MASK_I(obits); return data; } -QData VL_RAND_RESET_Q(int obits) VL_MT_SAFE { - if (Verilated::threadContextp()->randReset() == 0) return 0; - QData data = ~0ULL; - if (Verilated::threadContextp()->randReset() != 1) { // if 2, randomize - data = VL_RANDOM_Q(); - } - data &= VL_MASK_Q(obits); - return data; -} - -WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE { - for (int i = 0; i < VL_WORDS_I(obits) - 1; ++i) outwp[i] = VL_RAND_RESET_I(32); - outwp[VL_WORDS_I(obits) - 1] = VL_RAND_RESET_I(32) & VL_MASK_E(obits); - return outwp; -} WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE { // Not inlined to speed up compilation of slowpath code return VL_ZERO_W(obits, outwp); @@ -3544,6 +3594,17 @@ void VerilatedContextImp::commandArgVl(const std::string& arg) { // and the run can be reproduced by passing +verilator+seed+. if (u64 == 0) u64 = pickRandomSeed(); randSeed(static_cast(u64)); + } else if (commandArgVlString(arg, "+verilator+vpi+", str)) { + // With --vpi, load the requested shared library now. Without --vpi there is + // no VPI runtime, so warn the argument is ignored. +#if VM_VPI + Verilated::loadVpiLib(str); +#else + VL_WARN_MT( + "COMMAND_LINE", 0, "", + ("+verilator+vpi+ ignored: simulation was not compiled with --vpi '" + arg + "'") + .c_str()); // LCOV_EXCL_LINE (gcov zeroes this wrapped continuation line) +#endif } else if (arg == "+verilator+V") { VerilatedImp::versionDump(); // Someday more info too VL_FATAL_MT("COMMAND_LINE", 0, "", diff --git a/include/verilated.h b/include/verilated.h index 59ae1ad8c..73c7e5b2a 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -1036,6 +1036,9 @@ public: static void scTraceBeforeElaborationError() VL_ATTR_NORETURN VL_MT_SAFE; static void stackCheck(QData needSize) VL_MT_UNSAFE; + // Internal: Load a VPI shared library (+verilator+vpi+[:]) + static void loadVpiLib(const std::string& arg) VL_MT_UNSAFE; + // Internal: Get and set DPI context static const VerilatedScope* dpiScope() VL_MT_SAFE { return t_s.t_dpiScopep; } static void dpiScope(const VerilatedScope* scopep) VL_MT_SAFE { t_s.t_dpiScopep = scopep; } diff --git a/include/verilated.mk.in b/include/verilated.mk.in index 9d3f3b2e7..a90907755 100644 --- a/include/verilated.mk.in +++ b/include/verilated.mk.in @@ -52,6 +52,9 @@ CFG_GCH_IF_CLANG = @CFG_GCH_IF_CLANG@ CFG_LDFLAGS_VERILATED = @CFG_LDFLAGS_VERILATED@ # Linker libraries for multithreading CFG_LDLIBS_THREADS = @CFG_LDLIBS_THREADS@ +# Linker flags/libraries for runtime VPI library loading (+verilator+vpi+) +CFG_LDFLAGS_DYNAMIC = @CFG_LDFLAGS_DYNAMIC@ +CFG_LDLIBS_DYNAMIC = @CFG_LDLIBS_DYNAMIC@ ###################################################################### # Programs @@ -93,6 +96,7 @@ VK_CPPFLAGS_ALWAYS += \ -DVM_TRACE_FST=$(VM_TRACE_FST) \ -DVM_TRACE_VCD=$(VM_TRACE_VCD) \ -DVM_TRACE_SAIF=$(VM_TRACE_SAIF) \ + -DVM_VPI=$(VM_VPI) \ $(CFG_CXXFLAGS_NO_UNUSED) \ ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users diff --git a/include/verilated_covergroup.cpp b/include/verilated_covergroup.cpp index 6dc7006f1..9bf0fc53f 100644 --- a/include/verilated_covergroup.cpp +++ b/include/verilated_covergroup.cpp @@ -14,7 +14,8 @@ /// \file /// \brief Verilated functional-coverage collection runtime implementation /// -/// Compiled and linked when "verilator --coverage" is used with covergroups. +/// Linked when covergroups are present. The coverage-database registration +/// is compiled only with "verilator --coverage". /// //============================================================================= @@ -22,7 +23,9 @@ #include "verilated_covergroup.h" +#if VM_COVERAGE #include "verilated_cov.h" +#endif void VlCoverpoint::init(const char* hier, uint32_t atLeast, int nBins) { m_hier = hier; @@ -54,6 +57,7 @@ std::string VlCoverpoint::binName(int i) const { return name; } +#if VM_COVERAGE void VlCoverpoint::registerBins(VerilatedCovContext* covcontextp, const char* page) { for (int i = 0; i < binCount(); ++i) { const VlCovNamer& nm = namerFor(i); @@ -76,3 +80,4 @@ void VlCoverpoint::registerBins(VerilatedCovContext* covcontextp, const char* pa } } } +#endif // VM_COVERAGE diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index d69bca256..349fe44da 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -124,10 +124,6 @@ extern WDataOutP VL_SCOPED_RAND_RESET_ASSIGN_W(int obits, WDataOutP outwp, uint6 /// Random reset a signal of given width (init time only) extern IData VL_RAND_RESET_I(int obits) VL_MT_SAFE; -/// Random reset a signal of given width (init time only) -extern QData VL_RAND_RESET_Q(int obits) VL_MT_SAFE; -/// Random reset a signal of given width (init time only) -extern WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE; /// Zero reset a signal (slow - else use VL_ZERO_W) extern WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE; @@ -903,15 +899,31 @@ static inline IData VL_CLOG2_W(int words, WDataInP const lwp) VL_PURE { return 0; } +static inline IData VL_MOSTSETBITP1_I(IData lhs) VL_PURE { + if (VL_UNLIKELY(!lhs)) return 0; // __builtin_clz is undefined for 0 +#if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(VL_NO_BUILTINS) + return VL_EDATASIZE - __builtin_clz(lhs); +#else + for (int bit = VL_EDATASIZE - 1; bit >= 0; --bit) { + if (VL_BITISSET_E(lhs, bit)) return bit + 1; + } + return 0; // LCOV_EXCL_LINE // Can't get here - one bit must be set +#endif +} +static inline IData VL_MOSTSETBITP1_Q(QData lhs) VL_PURE { + if (VL_UNLIKELY(!lhs)) return 0; +#if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(VL_NO_BUILTINS) + return 64 - __builtin_clzll(static_cast(lhs)); +#else + const IData hi = static_cast(lhs >> 32ULL); + return hi ? (VL_EDATASIZE + VL_MOSTSETBITP1_I(hi)) + : VL_MOSTSETBITP1_I(static_cast(lhs)); +#endif +} static inline IData VL_MOSTSETBITP1_W(int words, WDataInP const lwp) VL_PURE { - // MSB set bit plus one; similar to FLS. 0=value is zero for (int i = words - 1; i >= 0; --i) { - if (VL_UNLIKELY(lwp[i])) { // Shorter worst case if predict not taken - for (int bit = VL_EDATASIZE - 1; bit >= 0; --bit) { - if (VL_UNLIKELY(VL_BITISSET_E(lwp[i], bit))) return i * VL_EDATASIZE + bit + 1; - } - // Can't get here - one bit must be set - } + // Shorter worst case if predict not taken + if (VL_UNLIKELY(lwp[i])) return i * VL_EDATASIZE + VL_MOSTSETBITP1_I(lwp[i]); } return 0; } @@ -1009,14 +1021,10 @@ static inline IData VL_EQ_R(int words, VlQueue q, WDataInP const rwp) VL_PURE } else if (sizeof(T) == 4) { for (int i = 0; (i < wordsInQ + 1); ++i) { nequal |= (q.at(wordsInQ - i) ^ rwp[i]); } } else if (sizeof(T) == 8) { - QData temp = 0; int qSize = q.size() - 1; for (int i = 0; (i < qSize); i += 2) { - temp = q.at(qSize - i); nequal |= (static_cast(q.at(qSize - i)) >> 32 ^ rwp[i + 1]); - temp = rwp[i + 1]; nequal |= (static_cast(q.at(qSize - i)) ^ rwp[i]); - temp = rwp[i]; } } return (nequal == 0); @@ -1026,7 +1034,6 @@ template static inline IData VL_EQ_R(int words, const VlQueue>& q, WDataInP const rwp) VL_PURE { EData nequal = 0; - const int wordsInQ = q.size() * N_Words; if ((q.size() * N_Words) != words) { return false; } int count = 0; for (int qIndex = q.size() - 1; qIndex >= 0; qIndex--) { @@ -1937,7 +1944,6 @@ static inline void VL_STREAMR_RRI(int lbits, VlQueue& to_q, const VlQueue>& from_q, IData rd) VL_MT_SAFE { to_q.clear(); - VL_CONSTEXPR_CXX17 size_t otherSize = 4 * N_Words; VL_CONSTEXPR_CXX17 size_t sizeOfThis = sizeof(T_Value); T_Value temp = 0; for (auto val : from_q) { diff --git a/include/verilated_types.h b/include/verilated_types.h index 40847b65e..a48b99c4c 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -337,6 +337,7 @@ public: ~VlProcess() { if (m_parentp) m_parentp->detach(this); + if (t_currentp == this) t_currentp = m_parentp.get(); } void attach(VlProcess* childp) { m_children.insert(childp); } @@ -2069,8 +2070,24 @@ struct VlNull final { operator T*() const { return nullptr; } + template + bool operator==(T* rhs) const { + return !rhs; + } + template + bool operator==(const T* rhs) const { + return !rhs; + } }; -inline bool operator==(const void* ptr, VlNull) { return !ptr; } + +template +inline bool operator==(T* lhs, VlNull) { + return !lhs; +} +template +inline bool operator==(const T* lhs, VlNull) { + return !lhs; +} //=================================================================== // Verilog class reference container diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 18c19ac26..30d82d8ef 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -288,6 +288,9 @@ class AssertVisitor final : public VNVisitor { AstNode* m_failsp = nullptr; // Current fail statement AstNodeCoverOrAssert* m_assertp = nullptr; // Current assertion AstFinal* m_finalp = nullptr; // Current final block + VDouble0 m_statLiftedCaseExprs; // Count of purified case expressions + AstNodeFTask* m_ftaskp = nullptr; // Current function/task + V3UniqueNames m_caseTempNames{"__VCase"}; // Map from (expression, senTree) to AstAlways that computes delayed values of the expression std::unordered_map, std::unordered_map, AstAlways*>> m_modExpr2Sen2DelayedAlwaysp; @@ -338,30 +341,26 @@ class AssertVisitor final : public VNVisitor { } VL_UNREACHABLE; } - static string assertActionControlPrefix(VAssertDirectiveType directiveType) { - const int controlled = !!(static_cast(directiveType) - & (static_cast(VAssertDirectiveType::ASSERT) - | static_cast(VAssertDirectiveType::COVER) - | static_cast(VAssertDirectiveType::ASSUME))); - const int checkRuntime = controlled & static_cast(v3Global.opt.assertOn()); - return "("s + std::to_string(controlled ^ 1) + " || ("s + std::to_string(checkRuntime) - + " && "s; + + static bool isControlled(VAssertDirectiveType directiveType) { + return (static_cast(directiveType) + & (static_cast(VAssertDirectiveType::ASSERT) + | static_cast(VAssertDirectiveType::COVER) + | static_cast(VAssertDirectiveType::ASSUME))); } static AstNodeExpr* assertPassOnCond(FileLine* fl, VAssertType type, VAssertDirectiveType directiveType, bool vacuous) { + if (!isControlled(directiveType)) return new AstConst{fl, AstConst::BitTrue{}}; + if (!v3Global.opt.assertOn()) return new AstConst{fl, AstConst::BitFalse{}}; return new AstCExpr{fl, AstCExpr::Pure{}, - assertActionControlPrefix(directiveType) - + assertCtlGetCall(assertPassOnQuery(vacuous), type, directiveType) - + "))"s, - 1}; + assertCtlGetCall(assertPassOnQuery(vacuous), type, directiveType), 1}; } static AstNodeExpr* assertFailOnCond(FileLine* fl, VAssertType type, VAssertDirectiveType directiveType) { + if (!isControlled(directiveType)) return new AstConst{fl, AstConst::BitTrue{}}; + if (!v3Global.opt.assertOn()) return new AstConst{fl, AstConst::BitFalse{}}; return new AstCExpr{fl, AstCExpr::Pure{}, - assertActionControlPrefix(directiveType) - + assertCtlGetCall("ASSERT_CTL_FAIL_ON", type, directiveType) - + "))"s, - 1}; + assertCtlGetCall("ASSERT_CTL_FAIL_ON", type, directiveType), 1}; } string assertDisplayMessage(const AstNode* nodep, const string& prefix, const string& message, VDisplayType severity) { @@ -434,6 +433,7 @@ class AssertVisitor final : public VNVisitor { AstNodeIf* const newp = new AstIf{fl, condp, bodyp}; newp->isBoundsCheck(true); // To avoid LATCH warning newp->user1(true); // Don't assert/cover this if + newp->user2(true); // Mark as an assertOn() check return newp; } static AstNodeStmt* newIfAssertFailOn(AstNode* bodyp, VAssertDirectiveType directiveType, @@ -445,6 +445,7 @@ class AssertVisitor final : public VNVisitor { AstNodeIf* const newp = new AstIf{fl, condp, bodyp}; newp->isBoundsCheck(true); // To avoid LATCH warning newp->user1(true); // Don't assert/cover this if + newp->user2(true); // Mark as an assertOn() check return newp; } @@ -760,10 +761,10 @@ class AssertVisitor final : public VNVisitor { VL_DO_DANGLING(pushDeletep(nodep), nodep); return; } - - iterateChildren(nodep); } + iterateChildren(nodep); + if (nodep->user2()) { // Combine consecutive assertOn checks if possible if (AstIf* const backp = VN_CAST(nodep->backp(), If)) { @@ -821,6 +822,28 @@ class AssertVisitor final : public VNVisitor { //========== Case assertions void visit(AstCase* nodep) override { + // Introduce temporary variable for AstCase if needed - it is done here and not in V3Case + // because this phase is before V3Scope and V3Case is not. Doing it before V3Scope ensures + // that V3Scope will take care of a scope creation + // We also need to do it before V3Begin, co that pragmas like `unique0` also work correctly + if (!nodep->exprp()->isPure()) { + ++m_statLiftedCaseExprs; + FileLine* const fl = nodep->exprp()->fileline(); + AstVar* const varp = new AstVar{fl, VVarType::BLOCKTEMP, m_caseTempNames.get(nodep), + nodep->exprp()->dtypep()}; + AstNodeExpr* const origp = nodep->exprp()->unlinkFrBack(); + nodep->addHereThisAsNext( + new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, origp}); + nodep->exprp(new AstVarRef{fl, varp, VAccess::READ}); + if (m_ftaskp) { + varp->funcLocal(true); + varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT); + m_ftaskp->stmtsp()->addHereThisAsNext(varp); + } else { + m_modp->stmtsp()->addHereThisAsNext(varp); + } + VIsCached::clearCacheTree(); + } iterateChildren(nodep); if (!nodep->user1SetOnce()) { bool has_default = false; @@ -1246,6 +1269,9 @@ public: V3Stats::addStat("Assertions, $past variables", m_statPastVars); V3Stats::addStat("Assertions, assertOn checks combined", m_statAssertOnCombined); V3Stats::addStat("Assertions, assertOn checks hoisted", m_statAssertOnHoisted); + V3Stats::addStat("Assertions, lifted impure case expressions", m_statLiftedCaseExprs); + // Rewrites can change purity, e.g. by compiling out assertion statements with --no-assert + VIsCached::clearCacheTree(); } }; diff --git a/src/V3AssertNfa.cpp b/src/V3AssertNfa.cpp index b6ec6964f..6a35273a5 100644 --- a/src/V3AssertNfa.cpp +++ b/src/V3AssertNfa.cpp @@ -384,6 +384,74 @@ class SvaNfaBuilder final { return 0; } + // Contiguous match-length range [lo,hi] for an operand whose length varies + // from AT MOST ONE ranged cycle delay; {-1,-1} otherwise. Drives the + // variable-length `intersect` lowering (IEEE 1800-2023 16.9.6): more than + // one ranged delay would make the per-length realization ambiguous, so it + // is reported unsupported rather than mis-paired. + static std::pair lengthRange(AstNodeExpr* nodep) { + if (AstSExpr* const sexprp = VN_CAST(nodep, SExpr)) { + AstDelay* const delayp = VN_CAST(sexprp->delayp(), Delay); + if (!delayp || !delayp->isCycleDelay()) return {-1, -1}; + std::pair delayRange; + if (delayp->isRangeDelay()) { + if (delayp->isUnbounded()) return {-1, -1}; + const int minD = getConstInt(delayp->lhsp()); + const int maxD = getConstInt(delayp->rhsp()); + if (minD < 0 || maxD < 0 || maxD < minD) return {-1, -1}; + delayRange = {minD, maxD}; + } else { + const int d = getConstInt(delayp->lhsp()); + if (d < 0) return {-1, -1}; + delayRange = {d, d}; + } + std::pair preRange{0, 0}; + if (AstNodeExpr* const prep = sexprp->preExprp()) { + preRange = lengthRange(prep); + if (preRange.first < 0) return {-1, -1}; + } + const std::pair bodyRange = lengthRange(sexprp->exprp()); + if (bodyRange.first < 0) return {-1, -1}; + const int variableParts = (preRange.first != preRange.second) + + (delayRange.first != delayRange.second) + + (bodyRange.first != bodyRange.second); + if (variableParts > 1) return {-1, -1}; + return {preRange.first + delayRange.first + bodyRange.first, + preRange.second + delayRange.second + bodyRange.second}; + } + if (AstSThroughout* const throughp = VN_CAST(nodep, SThroughout)) { + return lengthRange(throughp->rhsp()); + } + if (nodep->isMultiCycleSva()) return {-1, -1}; + return {0, 0}; // plain boolean -- 0 cycles + } + + // Clone `operand` with its sole variable ranged cycle delay pinned so the + // total match length is exactly `len`. `lo` is the operand's minimum length + // (lengthRange().first). A fixed operand has no such delay and is returned + // as a plain clone (callers only request its single achievable length). + static AstNodeExpr* realizeAtLength(AstNodeExpr* operand, int len, int lo) { + AstNodeExpr* const clonep = operand->cloneTreePure(false); + AstDelay* rangeDelayp = nullptr; + clonep->foreach([&](AstDelay* dp) { + if (!rangeDelayp && dp->isRangeDelay() && !dp->isUnbounded() + && getConstInt(dp->lhsp()) != getConstInt(dp->rhsp())) { + rangeDelayp = dp; + } + }); + if (rangeDelayp) { + FileLine* const flp = rangeDelayp->fileline(); + const int pinned = getConstInt(rangeDelayp->lhsp()) + (len - lo); + AstNodeExpr* const oldMinp = rangeDelayp->lhsp(); + oldMinp->replaceWith(new AstConst{flp, static_cast(pinned)}); + VL_DO_DANGLING(oldMinp->deleteTree(), oldMinp); + // Drop the max bound so it lowers as a fixed `##d`, not `##[d:d]`. + AstNode* const oldMaxp = rangeDelayp->rhsp()->unlinkFrBack(); + VL_DO_DANGLING(oldMaxp->deleteTree(), oldMaxp); + } + return clonep; + } + // Cuts AST size from O(N * sizeof(exprp)) to O(N) + O(sizeof(exprp)) by // sharing a single `VarRef` across N check edges. Hoist also matches the // IEEE 1800-2023 16.9.9 "single preponed-region snapshot" semantic for @@ -1028,6 +1096,188 @@ class SvaNfaBuilder final { return result; } + // Collect the boolean leaf checks of a fixed-length sequence keyed by their + // clock offset from the start. Returns false for anything other than nested + // AstSExpr with fixed cycle delays over boolean leaves (e.g. throughout). + static bool flattenFixedSeq(AstNodeExpr* nodep, int baseOffset, + std::map>& out) { + if (AstSExpr* const sexprp = VN_CAST(nodep, SExpr)) { + AstDelay* const delayp = VN_CAST(sexprp->delayp(), Delay); + if (!delayp || !delayp->isCycleDelay() || delayp->isUnbounded()) return false; + const int delayCycles = getConstInt(delayp->lhsp()); + if (delayCycles < 0) return false; + if (delayp->isRangeDelay() && getConstInt(delayp->rhsp()) != delayCycles) return false; + int preLen = 0; + if (AstNodeExpr* const prep = sexprp->preExprp()) { + if (!flattenFixedSeq(prep, baseOffset, out)) return false; + preLen = fixedLength(prep); + if (preLen < 0) return false; + } + return flattenFixedSeq(sexprp->exprp(), baseOffset + preLen + delayCycles, out); + } + if (nodep->isMultiCycleSva()) return false; + out[baseOffset].push_back(nodep); + return true; + } + + // Conjoin two equal-length fixed sequences into one: at each clock offset + // AND the boolean checks of both operands (IEEE 1800-2023 16.9.6 -- both + // operands match the same window). Returns null if either operand is not a + // plain fixed sequence of boolean leaves. + static AstNodeExpr* conjoinFixedSeqs(AstNodeExpr* lhsp, AstNodeExpr* rhsp, FileLine* flp) { + std::map> checks; + if (!flattenFixedSeq(lhsp, 0, checks) || !flattenFixedSeq(rhsp, 0, checks)) return nullptr; + if (checks.empty()) return nullptr; + AstNodeExpr* resultp = nullptr; + int prevOffset = 0; + for (const auto& offsetChecks : checks) { + const int offset = offsetChecks.first; + AstNodeExpr* condp = nullptr; + for (AstNodeExpr* const leafp : offsetChecks.second) { + AstNodeExpr* const clonep = leafp->cloneTreePure(false); + if (!condp) { + condp = clonep; + } else { + condp = new AstLogAnd{flp, condp, clonep}; + condp->dtypeSetBit(); + } + } + if (!resultp) { + if (offset > 0) { + AstDelay* const delayp = new AstDelay{ + flp, new AstConst{flp, static_cast(offset)}, /*isCycle=*/true}; + resultp + = new AstSExpr{flp, new AstConst{flp, AstConst::BitTrue{}}, delayp, condp}; + resultp->dtypeSetBit(); + } else { + resultp = condp; + } + } else { + AstDelay* const delayp = new AstDelay{ + flp, new AstConst{flp, static_cast(offset - prevOffset)}, + /*isCycle=*/true}; + resultp = new AstSExpr{flp, resultp, delayp, condp}; + resultp->dtypeSetBit(); + } + prevOffset = offset; + } + return resultp; + } + + // `seq` is a simple ranged sequence `start ##[m:n] end` (start/end boolean, + // start may be absent). Used to collapse a both-variable intersect to one + // ranged delay. + struct SimpleRanged final { + bool ok = false; + AstNodeExpr* startp = nullptr; // may be null (absent start) + AstNodeExpr* endp = nullptr; + }; + static SimpleRanged asSimpleRanged(AstNodeExpr* nodep) { + AstSExpr* const sexprp = VN_CAST(nodep, SExpr); + if (!sexprp) return {}; + AstDelay* const delayp = VN_CAST(sexprp->delayp(), Delay); + if (!delayp || !delayp->isCycleDelay() || !delayp->isRangeDelay() || delayp->isUnbounded()) + return {}; + if (getConstInt(delayp->lhsp()) == getConstInt(delayp->rhsp())) return {}; + AstNodeExpr* const prep = sexprp->preExprp(); + if (prep && fixedLength(prep) != 0) return {}; + if (fixedLength(sexprp->exprp()) != 0) return {}; + return {true, prep, sexprp->exprp()}; + } + + // Build the NFA for a synthesized intersect lowering tree, then free it. + // buildExpr returns the terminal condition (finalCondp) by reference into the + // tree; detach a clone so the tree can be freed here. The graph already holds + // clones/hoists of every edge condition, so nothing else dangles. + BuildResult buildFromLoweringTree(AstNodeExpr* treep, SvaStateVertex* entryVtxp, + bool isTopLevelStep) { + BuildResult result = buildExpr(treep, entryVtxp, isTopLevelStep); + if (result.valid() && result.finalCondp) { + result.finalCondp = result.finalCondp->cloneTreePure(false); + } + VL_DO_DANGLING(treep->deleteTree(), treep); + return result; + } + + // Empty common-length intersection -- unequal fixed lengths, or disjoint + // ranged lengths. IEEE 1800-2023 16.9.6 requires both operands to match + // over a window of the same length, so with no common length the intersect + // simply never matches. This is legal (matching nothing), not an error, so + // lower to a constant false rather than rejecting legal code. + BuildResult buildNeverMatchIntersect(AstNodeExpr* nodep, SvaStateVertex* entryVtxp, + bool isTopLevelStep) { + AstNodeExpr* const falsep = new AstConst{nodep->fileline(), AstConst::BitFalse{}}; + return buildFromLoweringTree(falsep, entryVtxp, isTopLevelStep); + } + + // Lower `seq1 intersect seq2` when an operand's match length varies + // (IEEE 1800-2023 16.9.6: both match over one window, equal start and end). + // The common length range is [lo,hi] = intersection of the two operands' + // achievable lengths. The equal-length combiner is avoided -- it mis-handles + // operands with an internal boolean check -- by lowering to plain sequences: + // - lo == hi (one shared length, e.g. one fixed + one ranged operand): + // pin each operand to that length and conjoin them cycle-by-cycle into a + // single fixed sequence. + // - lo < hi with simple `bool ##[m:n] bool` operands: collapse to one + // ranged delay `(start1 & start2) ##[lo:hi] (end1 & end2)`. (An OR of + // per-length branches cannot reject correctly -- a single missed length + // would fail the whole intersect, cf. Lesson 48.) + // - otherwise unsupported (clean error, not the legacy fall-through crash). + BuildResult buildVarLenIntersect(AstSIntersect* nodep, SvaStateVertex* entryVtxp, + bool isTopLevelStep) { + const std::pair lhsRange = lengthRange(nodep->lhsp()); + const std::pair rhsRange = lengthRange(nodep->rhsp()); + if (lhsRange.first < 0 || rhsRange.first < 0) { + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: intersect with this variable-length operand"); + return BuildResult::failWithError(); + } + const int lo = std::max(lhsRange.first, rhsRange.first); + const int hi = std::min(lhsRange.second, rhsRange.second); + if (lo > hi) { + // Disjoint length ranges share no common length -> never matches. + return buildNeverMatchIntersect(nodep, entryVtxp, isTopLevelStep); + } + FileLine* const flp = nodep->fileline(); + if (lo == hi) { + AstNodeExpr* const lp = realizeAtLength(nodep->lhsp(), lo, lhsRange.first); + AstNodeExpr* const rp = realizeAtLength(nodep->rhsp(), lo, rhsRange.first); + AstNodeExpr* const conjp = conjoinFixedSeqs(lp, rp, flp); + VL_DO_DANGLING(lp->deleteTree(), lp); + VL_DO_DANGLING(rp->deleteTree(), rp); + if (!conjp) { + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: intersect operand is not a plain boolean sequence"); + return BuildResult::failWithError(); + } + return buildFromLoweringTree(conjp, entryVtxp, isTopLevelStep); + } + const SimpleRanged sl = asSimpleRanged(nodep->lhsp()); + const SimpleRanged sr = asSimpleRanged(nodep->rhsp()); + if (!sl.ok || !sr.ok) { + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: intersect of two sequences that each vary in length over a" + " range with internal structure"); + return BuildResult::failWithError(); + } + const auto andBool = [&](AstNodeExpr* ap, AstNodeExpr* bp) -> AstNodeExpr* { + AstNodeExpr* const aClonep + = ap ? ap->cloneTreePure(false) : new AstConst{flp, AstConst::BitTrue{}}; + AstNodeExpr* const bClonep + = bp ? bp->cloneTreePure(false) : new AstConst{flp, AstConst::BitTrue{}}; + AstLogAnd* const andp = new AstLogAnd{flp, aClonep, bClonep}; + andp->dtypeSetBit(); + return andp; + }; + AstDelay* const delayp = new AstDelay{flp, new AstConst{flp, static_cast(lo)}, + /*isCycle=*/true}; + delayp->rhsp(new AstConst{flp, static_cast(hi)}); + AstSExpr* const reducedp + = new AstSExpr{flp, andBool(sl.startp, sr.startp), delayp, andBool(sl.endp, sr.endp)}; + reducedp->dtypeSetBit(); + return buildFromLoweringTree(reducedp, entryVtxp, isTopLevelStep); + } + BuildResult buildThroughout(AstSThroughout* nodep, SvaStateVertex* entryVtxp, bool isTopLevelStep = false) { // Mark entryVtxp so "cond false at tick 0" is detected as throughout-drop. @@ -1232,18 +1482,26 @@ public: return buildAndCombiner(andp->lhsp(), andp->rhsp(), entryVtxp, andp->fileline()); } if (AstSIntersect* const intp = VN_CAST(nodep, SIntersect)) { - // IEEE 1800-2023 16.9.6: SAnd with equal-length constraint. - // Variable-length intersect deferred to follow-up. + // IEEE 1800-2023 16.9.6: both operands match over one window with + // equal start and end (equal length). Lower to a single sequence + // that conjoins both operands' per-cycle checks -- correct under + // concurrent attempts, where the done-latch combiner conflates the + // two operands' start times and over-accepts. The combiner remains + // only as a fallback for operands that do not flatten. const int lhsLen = fixedLength(intp->lhsp()); const int rhsLen = fixedLength(intp->rhsp()); - if (lhsLen < 0 || rhsLen < 0) return BuildResult::fail(); - if (lhsLen != rhsLen) { - intp->v3error("Intersect sequence length mismatch: left " + std::to_string(lhsLen) - + " cycles, right " + std::to_string(rhsLen) - + " cycles (IEEE 1800-2023 16.9.6)"); - return BuildResult::failWithError(); + if (lhsLen >= 0 && rhsLen >= 0) { + if (lhsLen != rhsLen) { + // Unequal fixed lengths share no common length -> never matches. + return buildNeverMatchIntersect(intp, entryVtxp, isTopLevelStep); + } + if (AstNodeExpr* const conjp + = conjoinFixedSeqs(intp->lhsp(), intp->rhsp(), intp->fileline())) { + return buildFromLoweringTree(conjp, entryVtxp, isTopLevelStep); + } + return buildAndCombiner(intp->lhsp(), intp->rhsp(), entryVtxp, intp->fileline()); } - return buildAndCombiner(intp->lhsp(), intp->rhsp(), entryVtxp, intp->fileline()); + return buildVarLenIntersect(intp, entryVtxp, isTopLevelStep); } if (AstSWithin* const withinp = VN_CAST(nodep, SWithin)) { return buildSWithin(withinp, entryVtxp, isTopLevelStep); @@ -1725,8 +1983,18 @@ class SvaNfaLowering final { AstNodeExpr*& sigp = c.vtx[i]->datap()->stateSigp; if (sigp) VL_DO_DANGLING(sigp->deleteTree(), sigp); } - // Disable iff gating on throughout/required-step rejects (IEEE 16.12). + // Disable iff gating (IEEE 1800-2023 16.12). The edge counter misses a + // continuously-true disable, so gate on the current level value too. if (c.disableExprp) { + // terminalActivep is always set, so gate it unconditionally. + AstNodeExpr* const notTermp + = new AstLogNot{c.flp, c.disableExprp->cloneTreePure(false)}; + sigs.terminalActivep = new AstLogAnd{c.flp, sigs.terminalActivep, notTermp}; + if (sigs.rejectBasep) { + AstNodeExpr* const notDisp + = new AstLogNot{c.flp, c.disableExprp->cloneTreePure(false)}; + sigs.rejectBasep = new AstLogAnd{c.flp, sigs.rejectBasep, notDisp}; + } if (sigs.throughoutRejectp) { AstNodeExpr* const notDisp = new AstLogNot{c.flp, c.disableExprp->cloneTreePure(false)}; diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp index 22f4112b7..f45df83f3 100644 --- a/src/V3AssertPre.cpp +++ b/src/V3AssertPre.cpp @@ -93,7 +93,10 @@ private: fromAlways = true; } if (!senip) { - nodep->v3warn(E_UNSUPPORTED, "Unsupported: Unclocked assertion"); + nodep->v3error("Concurrent assertion has no clock (IEEE 1800-2023 16.16)\n" + << nodep->warnMore() + << "... Suggest provide a clocking event, a default" + " clocking, or a clocked procedural context"); newp = new AstSenTree{nodep->fileline(), nullptr}; } else { if (cassertp && fromAlways) cassertp->senFromAlways(true); diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 85c5b0892..e8f065861 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -5737,6 +5737,22 @@ public: void dump(std::ostream& str) const override; void dumpJson(std::ostream& str) const override; }; +class AstMostSetBitP1 final : public AstNodeUniop { + // Most-significant set bit plus one (bit-width); 0 if value is zero +public: + AstMostSetBitP1(FileLine* fl, AstNodeExpr* lhsp) + : ASTGEN_SUPER_MostSetBitP1(fl, lhsp) { + dtypeSetInteger2State(); + } + ASTGEN_MEMBERS_AstMostSetBitP1; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opMostSetBitP1(lhs); } + string emitVerilog() override { return "%f$mostsetbitp1(%l)"; } + string emitC() override { return "VL_MOSTSETBITP1_%lq(%lW, %P, %li)"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } + int instrCount() const override { return widthInstrs() * 16; } +}; class AstNToI final : public AstNodeUniop { // String to any-size integral public: diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 19f4d07ee..3c25a9992 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -1000,8 +1000,8 @@ public: // this matters, the caller must handle the dtype difference as appropriate. If 'mergeDType' is // false, the returned VarScope will have _->dtypep()->sameTree(initp->dtypep()) return true. AstVarScope* findConst(AstConst* initp, bool mergeDType); - // Rebuild hashes after potential removals - void reCache(); + // Rebuild hashes and missing variable scopes after potential removals + void rebuildVarScopesAndCache(); }; class AstConstraint final : public AstNode { // Constraint @@ -1185,12 +1185,21 @@ public: }; class AstCoverpointRef final : public AstNode { // Reference to a coverpoint used in a cross - const string m_name; // coverpoint name + // @astgen op1 := exprp : Optional[AstNodeExpr] // Non-standard: hierarchical/dotted + // // reference (implicit coverpoint), e.g. + // // 'cross a.b'; nullptr for a plain coverpoint + // // name. An AstDot at parse time, resolved + // // by the time V3Covergroup runs. + const string m_name; // coverpoint name; empty when exprp() carries a hierarchical reference public: AstCoverpointRef(FileLine* fl, const string& name) : ASTGEN_SUPER_CoverpointRef(fl) , m_name{name} {} + AstCoverpointRef(FileLine* fl, AstNodeExpr* exprp) + : ASTGEN_SUPER_CoverpointRef(fl) { + this->exprp(exprp); + } ASTGEN_MEMBERS_AstCoverpointRef; void dump(std::ostream& str) const override; void dumpJson(std::ostream& str) const override; diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 5f9041ffe..26126e5fd 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include // Routines for dumping dict fields (NOTE: due to leading ',' they can't be used for first field in @@ -1779,14 +1780,28 @@ AstVarScope* AstConstPool::findConst(AstConst* initp, bool mergeDType) { return varScopep; } -void AstConstPool::reCache() { +void AstConstPool::rebuildVarScopesAndCache() { m_tables.clear(); m_consts.clear(); + std::unordered_map varScopeps; for (AstVarScope* vscp = m_scopep->varsp(); vscp; vscp = VN_CAST(vscp->nextp(), VarScope)) { - AstNode* const valuep = vscp->varp()->valuep(); - const V3Hash hash = V3Hasher::uncachedHash(valuep); - if (VN_IS(valuep, InitArray)) m_tables.emplace(hash.value(), vscp); - if (VN_IS(valuep, Const)) m_consts.emplace(hash.value(), vscp); + varScopeps.emplace(vscp->varp(), vscp); + } + for (AstNode* nodep = m_modp->stmtsp(); nodep; nodep = nodep->nextp()) { + AstVar* const varp = VN_CAST(nodep, Var); + if (!varp) continue; + AstNode* const valuep = varp->valuep(); + if (!valuep) continue; + const bool isTable = VN_IS(valuep, InitArray); + const AstConst* const constp = VN_CAST(valuep, Const); + if (!isTable && !constp) continue; + AstVarScope*& vscp = varScopeps[varp]; + if (!vscp) { + vscp = new AstVarScope{varp->fileline(), m_scopep, varp}; + m_scopep->addVarsp(vscp); + } + if (isTable) m_tables.emplace(V3Hasher::uncachedHash(valuep).value(), vscp); + if (constp) m_consts.emplace(constp->num().toHash().value(), vscp); } } diff --git a/src/V3CUse.cpp b/src/V3CUse.cpp index 2fddf7f82..51d6fd688 100644 --- a/src/V3CUse.cpp +++ b/src/V3CUse.cpp @@ -65,6 +65,7 @@ class CUseVisitor final : public VNVisitorConst { iterateConst(nodep->lhsp()->dtypep()); } void visit(AstNodeDType* nodep) override { + if (nodep->user1SetOnce()) return; // Process once if (nodep->virtRefDTypep()) iterateConst(nodep->virtRefDTypep()); if (nodep->virtRefDType2p()) iterateConst(nodep->virtRefDType2p()); diff --git a/src/V3Coverage.cpp b/src/V3Coverage.cpp index 12bb973dc..9c19319d8 100644 --- a/src/V3Coverage.cpp +++ b/src/V3Coverage.cpp @@ -375,6 +375,8 @@ class CoverageVisitor final : public VNVisitor { } else { itemp->addElsesp(stmtp); } + } else if (AstBegin* const itemp = VN_CAST(nodep, Begin)) { + itemp->addStmtsp(stmtp); } else { nodep->v3fatalSrc("Bad node type"); } @@ -776,6 +778,8 @@ class CoverageVisitor final : public VNVisitor { // covers the code in that line.) VL_RESTORER(m_beginHier); VL_RESTORER(m_inToggleOff); + VL_RESTORER(m_exprStmtsp); + m_exprStmtsp = nodep; m_inToggleOff = true; if (nodep->name() != "") { m_beginHier = m_beginHier + (m_beginHier != "" ? "__DOT__" : "") + nodep->name(); @@ -820,6 +824,7 @@ class CoverageVisitor final : public VNVisitor { if (pair.second) { varp = new AstVar{fl, VVarType::MODULETEMP, m_exprTempNames.get(frefp), dtypep}; + varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT); pair.first->second = varp; if (m_ftaskp) { varp->funcLocal(true); diff --git a/src/V3Covergroup.cpp b/src/V3Covergroup.cpp index 054f27c34..b1890e001 100644 --- a/src/V3Covergroup.cpp +++ b/src/V3Covergroup.cpp @@ -98,7 +98,7 @@ class FunctionalCoverageVisitor final : public VNVisitor { for (AstCoverCross* crossp : m_coverCrosses) { for (AstNode* itemp = crossp->itemsp(); itemp; itemp = itemp->nextp()) { if (const AstCoverpointRef* const refp = VN_CAST(itemp, CoverpointRef)) - m_crossedCpNames.insert(refp->name()); + if (!refp->exprp()) m_crossedCpNames.insert(refp->name()); } } @@ -1295,6 +1295,18 @@ class FunctionalCoverageVisitor final : public VNVisitor { while (itemp) { AstNode* const nextp = itemp->nextp(); AstCoverpointRef* const refp = VN_AS(itemp, CoverpointRef); + if (refp->exprp()) { + // Non-standard hierarchical/dotted cross item (e.g. 'cross a.b'): an implicit + // coverpoint over the referenced expression (carried in refp->exprp()). The + // grammar already warned NONSTD; implicit coverpoints are not yet implemented, so + // generate no sampling code for this cross. When support is added the implicit + // coverpoint should be synthesized upstream (V3LinkParse) as a real AstCoverpoint + // so it flows through the normal coverpoint path - by here coverpoint lowering has + // already run. + refp->v3warn(COVERIGN, + "Unsupported: cross of hierarchical reference (implicit coverpoint)"); + return; + } // Find the referenced coverpoint via name map (O(log n) vs O(n) linear scan) const auto it = m_coverpointMap.find(refp->name()); AstCoverpoint* const foundCpp = (it != m_coverpointMap.end()) ? it->second : nullptr; diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index 677f0b2aa..411ec57eb 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -597,7 +597,7 @@ public: // We may have removed some datatypes, cleanup nodep->typeTablep()->repairCache(); VIsCached::clearCacheTree(); // Removing assignments may affect isPure - nodep->constPoolp()->reCache(); + nodep->constPoolp()->rebuildVarScopesAndCache(); } ~DeadVisitor() override { V3Stats::addStatSum("Optimizations, deadified FTasks", m_statFTasksDeadified); diff --git a/src/V3Dfg.cpp b/src/V3Dfg.cpp index fc6be54ce..2fd5afb95 100644 --- a/src/V3Dfg.cpp +++ b/src/V3Dfg.cpp @@ -620,6 +620,12 @@ DfgVertex::DfgVertex(DfgGraph& dfg, VDfgType type, FileLine* flp, const DfgDataT dfg.addVertex(*this); } +bool DfgVertex::unsafe() const { + if (is()) return true; + if (is()) return !as()->bitp()->is(); + return false; +} + void DfgVertex::typeCheck(const DfgGraph& dfg) const { #define CHECK(cond, msg) \ diff --git a/src/V3Dfg.h b/src/V3Dfg.h index b93c1c716..d80be4d84 100644 --- a/src/V3Dfg.h +++ b/src/V3Dfg.h @@ -195,6 +195,8 @@ public: UASSERT_OBJ(m_dtype.isPacked(), this, "Non packed vertex has no 'width'"); return m_dtype.size(); } + // Has terminating side-effect + bool unsafe() const; // Type check vertex (for debugging) void typeCheck(const DfgGraph& dfg) const; diff --git a/src/V3DfgPeephole.cpp b/src/V3DfgPeephole.cpp index de92790a8..fa29339fe 100644 --- a/src/V3DfgPeephole.cpp +++ b/src/V3DfgPeephole.cpp @@ -2269,7 +2269,7 @@ class V3DfgPeephole final : public DfgVisitor { } void visit(DfgLogAnd* const vtxp) override { - if (binary(vtxp)) return; + if (binary(vtxp) || vtxp->rhsp()->unsafe()) return; DfgVertex* const lhsp = vtxp->lhsp(); DfgVertex* const rhsp = vtxp->rhsp(); @@ -2287,11 +2287,11 @@ class V3DfgPeephole final : public DfgVisitor { } void visit(DfgLogIf* const vtxp) override { - if (binary(vtxp)) return; + if (binary(vtxp) || vtxp->rhsp()->unsafe()) return; } void visit(DfgLogOr* const vtxp) override { - if (binary(vtxp)) return; + if (binary(vtxp) || vtxp->rhsp()->unsafe()) return; DfgVertex* const lhsp = vtxp->lhsp(); DfgVertex* const rhsp = vtxp->rhsp(); @@ -2890,13 +2890,13 @@ class V3DfgPeephole final : public DfgVisitor { } if (vtxp->dtype() == m_bitDType) { - if (isSame(condp, thenp)) { // a ? a : b becomes a | b + if (isSame(condp, thenp) && !elsep->unsafe()) { // a ? a : b becomes a | b APPLYING(REPLACE_COND_WITH_THEN_BRANCH_COND) { replace(make(vtxp, condp, elsep)); return; } } - if (isSame(condp, elsep)) { // a ? b : a becomes a & b + if (isSame(condp, elsep) && !thenp->unsafe()) { // a ? b : a becomes a & b APPLYING(REPLACE_COND_WITH_ELSE_BRANCH_COND) { replace(make(vtxp, condp, thenp)); return; @@ -2905,28 +2905,28 @@ class V3DfgPeephole final : public DfgVisitor { } if (vtxp->width() <= VL_QUADSIZE) { - if (isZero(thenp)) { // a ? 0 : b becomes ~a & b + if (isZero(thenp) && !elsep->unsafe()) { // a ? 0 : b becomes ~a & b APPLYING(REPLACE_COND_WITH_THEN_BRANCH_ZERO) { DfgVertex* const maskp = replicate(vtxp, make(condp, condp)); replace(make(vtxp, maskp, elsep)); return; } } - if (isOnes(thenp)) { // a ? 1 : b becomes a | b + if (isOnes(thenp) && !elsep->unsafe()) { // a ? 1 : b becomes a | b APPLYING(REPLACE_COND_WITH_THEN_BRANCH_ONES) { DfgVertex* const maskp = replicate(vtxp, condp); replace(make(vtxp, maskp, elsep)); return; } } - if (isZero(elsep)) { // a ? b : 0 becomes a & b + if (isZero(elsep) && !thenp->unsafe()) { // a ? b : 0 becomes a & b APPLYING(REPLACE_COND_WITH_ELSE_BRANCH_ZERO) { DfgVertex* const maskp = replicate(vtxp, condp); replace(make(vtxp, maskp, thenp)); return; } } - if (isOnes(elsep)) { // a ? b : 1 becomes ~a | b + if (isOnes(elsep) && !thenp->unsafe()) { // a ? b : 1 becomes ~a | b APPLYING(REPLACE_COND_WITH_ELSE_BRANCH_ONES) { DfgVertex* const maskp = replicate(vtxp, make(condp, condp)); replace(make(vtxp, maskp, thenp)); @@ -2935,7 +2935,8 @@ class V3DfgPeephole final : public DfgVisitor { } if (DfgOr* const tOrp = thenp->cast()) { - if (isSame(tOrp->lhsp(), elsep)) { // a ? b | c : b becomes b | (a & c) + if (isSame(tOrp->lhsp(), elsep) + && !tOrp->rhsp()->unsafe()) { // a ? b | c : b becomes b | (a & c) APPLYING(REPLACE_COND_THEN_OR_LHS) { DfgVertex* const maskp = replicate(vtxp, condp); DfgAnd* const andp = make(vtxp, maskp, tOrp->rhsp()); @@ -2943,7 +2944,8 @@ class V3DfgPeephole final : public DfgVisitor { return; } } - if (isSame(tOrp->rhsp(), elsep)) { // a ? b | c : c becomes c | (a & b) + if (isSame(tOrp->rhsp(), elsep) + && !tOrp->lhsp()->unsafe()) { // a ? b | c : c becomes c | (a & b) APPLYING(REPLACE_COND_THEN_OR_RHS) { DfgVertex* const maskp = replicate(vtxp, condp); DfgAnd* const andp = make(vtxp, maskp, tOrp->lhsp()); diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp index 2a3197112..8b2f2add0 100644 --- a/src/V3EmitCHeaders.cpp +++ b/src/V3EmitCHeaders.cpp @@ -683,7 +683,8 @@ class EmitCHeader final : public EmitCConstInit { if (v3Global.opt.mtasks()) puts("#include \"verilated_threads.h\"\n"); if (v3Global.opt.savable()) puts("#include \"verilated_save.h\"\n"); if (v3Global.opt.coverage()) puts("#include \"verilated_cov.h\"\n"); - if (v3Global.opt.coverage()) puts("#include \"verilated_covergroup.h\"\n"); + if (v3Global.opt.coverage() || v3Global.useCovergroup()) + puts("#include \"verilated_covergroup.h\"\n"); if (v3Global.usesTiming()) puts("#include \"verilated_timing.h\"\n"); if (v3Global.useRandomizeMethods()) puts("#include \"verilated_random.h\"\n"); if (v3Global.usesForce()) puts("#include \"verilated_force.h\"\n"); diff --git a/src/V3EmitCMain.cpp b/src/V3EmitCMain.cpp index 000567eaf..0d3fd0b6d 100644 --- a/src/V3EmitCMain.cpp +++ b/src/V3EmitCMain.cpp @@ -104,6 +104,8 @@ private: puts("\n"); if (v3Global.opt.vpi()) { + // VPI shared libraries requested via +verilator+vpi+ are loaded by + // contextp->commandArgs() above, before the statically-linked startup routines. puts("// Hook VPI startup routines and invoke callback\n"); puts("if (vlog_startup_routines) {\n"); puts(/**/ "for (auto routinep = &vlog_startup_routines[0]; *routinep; routinep++)" diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp index 6ddd53e77..034b1e807 100644 --- a/src/V3EmitCModel.cpp +++ b/src/V3EmitCModel.cpp @@ -70,7 +70,8 @@ class EmitCModel final : public EmitCFunc { if (v3Global.opt.mtasks()) puts("#include \"verilated_threads.h\"\n"); if (v3Global.opt.savable()) puts("#include \"verilated_save.h\"\n"); if (v3Global.opt.coverage()) puts("#include \"verilated_cov.h\"\n"); - if (v3Global.opt.coverage()) puts("#include \"verilated_covergroup.h\"\n"); + if (v3Global.opt.coverage() || v3Global.useCovergroup()) + puts("#include \"verilated_covergroup.h\"\n"); if (v3Global.dpi()) puts("#include \"svdpi.h\"\n"); // Declare foreign instances up front to make C++ happy diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index f76945279..a63d328f3 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -567,6 +567,12 @@ public: of.puts("VM_TRACE_VCD = "); of.puts(v3Global.opt.traceEnabledVcd() ? "1" : "0"); of.puts("\n"); + of.puts("# VPI enabled? 0/1 (from --vpi)\n"); + of.puts("VM_VPI = "); + of.puts(v3Global.opt.vpi() ? "1" : "0"); + of.puts("\n"); + // Link flags for runtime VPI library loading are emitted by emitOverallMake() after + // verilated.mk is included (so $(CFG_LDFLAGS_DYNAMIC)/$(CFG_LDLIBS_DYNAMIC) are defined). of.puts("\n### Object file lists...\n"); for (int support = 0; support < 3; ++support) { @@ -729,6 +735,17 @@ public: of.puts("\n### Executable rules... (from --exe)\n"); of.puts("VPATH += $(VM_USER_DIR)\n"); of.puts("\n"); + + if (v3Global.opt.vpi()) { + // Runtime VPI library loading (+verilator+vpi+) needs the executable to + // export its VPI symbols so the dlopen'd library can resolve them, plus the + // dl library for dlopen/dlsym. The exact flags are probed at configure time + // (CFG_LDFLAGS_DYNAMIC / CFG_LDLIBS_DYNAMIC in verilated.mk). + of.puts("# Runtime VPI library loading (+verilator+vpi+) link requirements\n"); + of.puts("LDFLAGS += $(CFG_LDFLAGS_DYNAMIC)\n"); + of.puts("LDLIBS += $(CFG_LDLIBS_DYNAMIC)\n"); + of.puts("\n"); + } } const string compilerIncludePch diff --git a/src/V3Global.cpp b/src/V3Global.cpp index 2e7c25fc7..3fd207be3 100644 --- a/src/V3Global.cpp +++ b/src/V3Global.cpp @@ -245,7 +245,8 @@ std::vector V3Global::verilatedCppFiles() { if (v3Global.opt.vpi()) result.emplace_back("verilated_vpi.cpp"); if (v3Global.opt.savable()) result.emplace_back("verilated_save.cpp"); if (v3Global.opt.coverage()) result.emplace_back("verilated_cov.cpp"); - if (v3Global.opt.coverage()) result.emplace_back("verilated_covergroup.cpp"); + if (v3Global.opt.coverage() || v3Global.useCovergroup()) + result.emplace_back("verilated_covergroup.cpp"); for (const string& base : v3Global.opt.traceSourceBases()) result.emplace_back(base + "_c.cpp"); if (v3Global.usesProbDist()) result.emplace_back("verilated_probdist.cpp"); diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index 87b9e0b26..7b0a4ecd3 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -29,6 +29,7 @@ #include "V3Inline.h" #include "V3AstUserAllocator.h" +#include "V3Graph.h" #include "V3Inst.h" #include "V3Stats.h" @@ -41,208 +42,334 @@ VL_DEFINE_DEBUG_FUNCTIONS; static const int INLINE_MODS_SMALLER = 100; // If a mod is < this # nodes, can always inline it //###################################################################### -// Inlining state. Kept as AstNodeModule::user1p via AstUser1Allocator +// Bipartite module instantiation graph containing module and cell vertices -namespace { +class InlineModModuleVertex; +class InlineModCellVertex; -struct ModuleState final { - bool m_inlined = false; // Whether to inline this module - unsigned m_cellRefs = 0; // Number of AstCells instantiating this module - std::vector m_childCells; // AstCells under this module (to speed up traversal) -}; - -using ModuleStateUser1Allocator = AstUser1Allocator; - -} // namespace - -//###################################################################### -// Visitor that determines which modules will be inlined - -class InlineMarkVisitor final : public VNVisitor { +class InlineModGraph final : public V3Graph { // NODE STATE - // Output - // AstNodeModule::user1() // OUTPUT: ModuleState instance (via m_moduleState) - // Internal state (can be cleared after this visit completes) - // AstNodeModule::user2() // CIL_*. Allowed to automatically inline module - // AstNodeModule::user4() // int. Statements in module - const VNUser2InUse m_inuser2; - const VNUser4InUse m_inuser4; + // AstNodeModule::user4p() -> InlineModModuleVertex*, the module vertex + // AstCell::user4p() -> InlineModCellVertex*, the cell vertex - ModuleStateUser1Allocator& m_moduleState; + VNUser4InUse m_user4InUse; - // For the user2 field: - enum : uint8_t { - CIL_NOTHARD = 0, // Inline not supported - CIL_NOTSOFT, // Don't inline unless user overrides - CIL_MAYBE, // Might inline - CIL_USER - }; // Pragma suggests inlining - - // STATE - AstNodeModule* m_modp = nullptr; // Current module - VDouble0 m_statUnsup; // Statistic tracking - std::vector m_allMods; // All modules, in top-down order. - - // Within the context of a given module, LocalInstanceMap maps - // from child modules to the count of each child's local instantiations. - using LocalInstanceMap = std::unordered_map; - - // We keep a LocalInstanceMap for each module in the design - std::unordered_map m_instances; +public: + InlineModGraph() + : V3Graph{} {} + ~InlineModGraph() override = default; // METHODS - void cantInline(const char* reason, bool hard) { - if (hard) { - if (m_modp->user2() != CIL_NOTHARD) { - UINFO(4, " No inline hard: " << reason << " " << m_modp); - m_modp->user2(CIL_NOTHARD); - ++m_statUnsup; - } - } else { - if (m_modp->user2() == CIL_MAYBE) { - UINFO(4, " No inline soft: " << reason << " " << m_modp); - m_modp->user2(CIL_NOTSOFT); + InlineModModuleVertex* getInlineModModuleVertexp(AstNodeModule* modp); + InlineModCellVertex* getInlineModCellVertexp(AstCell* cellp); + void addEdge(InlineModModuleVertex& from, InlineModCellVertex& to); + void addEdge(InlineModCellVertex& from, InlineModModuleVertex& to); + + // debug + std::string dotRankDir() const override { return "LR"; } +}; + +class InlineModEitherVertex VL_NOT_FINAL : public V3GraphVertex { + VL_RTTI_IMPL(InlineModEitherVertex, V3GraphVertex) +protected: + explicit InlineModEitherVertex(InlineModGraph& graph) + : V3GraphVertex{&graph} {} +}; + +class InlineModModuleVertex final : public InlineModEitherVertex { + VL_RTTI_IMPL(InlineModModuleVertex, InlineModEitherVertex) + AstNodeModule* const m_modp; // The module + const char* m_noInlineHardWyp = nullptr; // First reason the module can never be inlined + const char* m_noInlineSoftWyp = nullptr; // First reason not to inline unless forced + const char* m_shouldInlineWhyp = nullptr; // First reason why this module should be inlined + size_t m_size = 0; // The size (statement count) of the module + size_t mutable m_flattenedSize = 0; // The size of the module if flattened + bool mutable m_flattenedSizeValid = false; // Whether the flattened size is valid + size_t mutable m_instanceCount = 0; // The number of total instances of this module + bool mutable m_instanceCountValid = false; // Whether the instance count is valid + +public: + InlineModModuleVertex(InlineModGraph& graph, AstNodeModule* modp) + : InlineModEitherVertex{graph} + , m_modp{modp} {} + ~InlineModModuleVertex() override = default; + + // ACCESSORS + AstNodeModule* modp() const { return m_modp; } + size_t size() const { return m_size; } + void size(size_t value) { m_size = value; } + void sizeInc(size_t value = 1) { m_size += value; } + bool noInlineHard() const { return m_noInlineHardWyp; } + void setNoInlineHard(const char* whyp) { + if (!m_noInlineHardWyp) m_noInlineHardWyp = whyp; + } + bool noInlineSoft() const { return m_noInlineSoftWyp; } + void setNoInlineSoft(const char* whyp) { + if (!m_noInlineSoftWyp) m_noInlineSoftWyp = whyp; + } + bool shouldInline() const { return m_shouldInlineWhyp; } + void setShouldInline(const char* whyp) { + if (!m_shouldInlineWhyp) m_shouldInlineWhyp = whyp; + } + // Mark every instance below this module for inlining + void setFlatten(); + + // Total size of module, with all hierarchy below flattened + size_t flattenedSize() const { + if (!m_flattenedSizeValid) { + m_flattenedSizeValid = true; + m_flattenedSize = m_size; + for (const V3GraphEdge& e1 : outEdges()) { + for (const V3GraphEdge& e2 : e1.top()->outEdges()) { + InlineModModuleVertex* const mVtxp = e2.top()->as(); + m_flattenedSize += mVtxp->flattenedSize(); + } } } + return m_flattenedSize; } + // Total number of instances of this module in the whole hierarchy of the design + size_t instanceCount() const { + if (!m_instanceCountValid) { + m_instanceCountValid = true; + m_instanceCount = 0; + for (const V3GraphEdge& e1 : inEdges()) { + for (const V3GraphEdge& e2 : e1.fromp()->inEdges()) { + InlineModModuleVertex* const mVtxp = e2.fromp()->as(); + m_instanceCount += mVtxp->instanceCount(); + } + } + if (!m_instanceCount) { + UASSERT_OBJ(m_modp->isTop(), m_modp, "non-top level module should have instances"); + m_instanceCount = 1; + } + } + return m_instanceCount; + } + + // debug + FileLine* fileline() const override { return m_modp->fileline(); } + std::string dotShape() const override { return "box"; } + std::string dotColor() const override { + return m_noInlineHardWyp ? "red" + : m_shouldInlineWhyp ? "blue" + : m_noInlineSoftWyp ? "orange" + : "black"; + } + std::string name() const override VL_MT_STABLE { + std::string str = m_modp->typeName() + " "s + cvtToHex(m_modp); + str += "\n" + m_modp->name() + " @ " + fileline()->ascii(); + str += "\ninstanceCount: " + std::to_string(instanceCount()); + str += "\nsize: " + std::to_string(m_size); + str += "\nflattenedSize: " + std::to_string(flattenedSize()); + if (m_shouldInlineWhyp) str += "\nShouldInline: "s + m_shouldInlineWhyp; + if (m_noInlineHardWyp) str += "\nNoInlineHard: "s + m_noInlineHardWyp; + if (m_noInlineSoftWyp) str += "\nNoInlineSoft: "s + m_noInlineSoftWyp; + str += "\n"; + return str; + } +}; + +class InlineModCellVertex final : public InlineModEitherVertex { + VL_RTTI_IMPL(InlineModCellVertex, InlineModEitherVertex) + AstCell* const m_cellp; // The cell (instance) + const char* m_doInlineWyp = nullptr; // First reason this instance should be inlined + bool m_flatten = false; // Whether this cell and below already flattened (avoid O(n^2)) + +public: + InlineModCellVertex(InlineModGraph& graph, AstCell* cellp) + : InlineModEitherVertex{graph} + , m_cellp{cellp} {} + ~InlineModCellVertex() override = default; + + // ACCESSORS + AstCell* cellp() const { return m_cellp; } + bool doInline() const { return m_doInlineWyp; } + void setDoInline(const char* whyp) { + if (!m_doInlineWyp) m_doInlineWyp = whyp; + } + bool flatten() const { return m_flatten; } + void setFlatten() { m_flatten = true; } + + // The module vertx this cell is instantiating + InlineModModuleVertex& instanceOf() const { + UASSERT_OBJ(outSize1(), this, "Cell should have exactly one outgoing edge"); + return *outEdges().frontp()->top()->as(); + } + // The module vertex this cell is instantiated in + InlineModModuleVertex& instanceIn() const { + UASSERT_OBJ(inSize1(), this, "Cell should have exactly one incoming edge"); + return *inEdges().frontp()->fromp()->as(); + } + + // debug + FileLine* fileline() const override { return m_cellp->fileline(); } + std::string dotColor() const override { return m_doInlineWyp ? "green" : "black"; } + std::string dotShape() const override { return "ellipse"; } + std::string name() const override VL_MT_STABLE { + std::string str = m_cellp->typeName() + " "s + cvtToHex(m_cellp); + str += "\n" + m_cellp->name() + " @ " + fileline()->ascii(); + if (m_doInlineWyp) str += "\nDoInline: "s + m_doInlineWyp; + str += "\n"; + return str; + } +}; + +InlineModModuleVertex* InlineModGraph::getInlineModModuleVertexp(AstNodeModule* modp) { + if (!modp->user4p()) modp->user4p(new InlineModModuleVertex{*this, modp}); + return modp->user4u().to(); +} +InlineModCellVertex* InlineModGraph::getInlineModCellVertexp(AstCell* cellp) { + if (!cellp->user4p()) cellp->user4p(new InlineModCellVertex{*this, cellp}); + return cellp->user4u().to(); +} + +void InlineModGraph::addEdge(InlineModModuleVertex& parent, InlineModCellVertex& cell) { + UASSERT_OBJ(cell.inEmpty(), &cell, "Cell should have at most one incoming edge"); + new V3GraphEdge{this, &parent, &cell, 1, /* cutable: */ false}; +} +void InlineModGraph::addEdge(InlineModCellVertex& cell, InlineModModuleVertex& submodule) { + UASSERT_OBJ(cell.outEmpty(), &cell, "Cell should have at most one outgoing edge"); + new V3GraphEdge{this, &cell, &submodule, 1, /* cutable: */ false}; +} + +void InlineModModuleVertex::setFlatten() { + for (V3GraphEdge& edge : outEdges()) { + InlineModCellVertex& cVtx = *edge.top()->as(); + if (cVtx.flatten()) continue; + cVtx.setFlatten(); + InlineModModuleVertex& iVtx = cVtx.instanceOf(); + if (!iVtx.noInlineHard() && !iVtx.noInlineSoft()) cVtx.setDoInline("flatten parent"); + iVtx.setFlatten(); + } +} + +//###################################################################### +// Visitor that builds the bipartite module instantiation graph + +class InlineModGraphBuilder final : public VNVisitor { + // STATE + std::unique_ptr m_graphp{new InlineModGraph}; // The graph being built + InlineModModuleVertex* m_modVtxp = nullptr; // Vertex of module currently being iterated // VISITORS void visit(AstNodeModule* nodep) override { - UASSERT_OBJ(!m_modp, nodep, "Unsupported: Nested modules"); - VL_RESTORER(m_modp); - m_modp = nodep; - m_allMods.push_back(nodep); - m_modp->user2(CIL_MAYBE); - m_modp->user4(0); // statement count - if (VN_IS(m_modp, Iface)) { - // Inlining an interface means we no longer have a cell handle to resolve to. - // If inlining moves post-scope this can perhaps be relaxed. - cantInline("modIface", true); - } - if (m_modp->modPublic() && (m_modp->isTop() || !v3Global.opt.flatten())) { - cantInline("modPublic", false); - } - // If the instance is a --lib-create library stub instance, and need tracing, - // then don't inline as we need to know its a lib stub for sepecial handling - // in V3TraceDecl. See #7001. - if (m_modp->verilatorLib() && v3Global.opt.trace()) { - cantInline("verilatorLib with --trace", false); + if (nodep == v3Global.rootp()->constPoolp()->modp()) return; // Ignore const pool module + + UASSERT_OBJ(!m_modVtxp, nodep, "Unsupported: Nested modules"); + + // Create the module vertex + InlineModModuleVertex* const vtxp = m_graphp->getInlineModModuleVertexp(nodep); + + // Check if the module itself is not inlineable + + // Inlining an interface means we no longer have a cell handle to resolve to. + // If inlining moves post-scope this can perhaps be relaxed. + if (VN_IS(nodep, Iface)) vtxp->setNoInlineHard("Interface"); + // Never inline packages - TODO: conceptually fine, but why not? + if (VN_IS(nodep, Package)) vtxp->setNoInlineHard("Package"); + // A --lib-create library stub instance that needs tracing must not be + // inlined, so we still know it is a lib stub in V3TraceDecl (see #7001) + if (nodep->verilatorLib() && v3Global.opt.trace()) { + vtxp->setNoInlineHard("verilatorLib with --trace"); } - iterateChildren(nodep); + // Don't inline public modules by default + if (nodep->modPublic()) vtxp->setNoInlineSoft("Public module"); + + // Iterate children + VL_RESTORER(m_modVtxp); + m_modVtxp = vtxp; + iterateChildrenConst(nodep); } + void visit(AstClass* nodep) override { - // TODO allow inlining of modules that have classes - // (Probably wait for new inliner scheme) - cantInline("class", true); - iterateChildren(nodep); + // TODO allow inlining of modules that contain classes + if (m_modVtxp) m_modVtxp->setNoInlineHard("Contains class"); + iterateChildrenConst(nodep); // TODO: this is only needed or FTaskRef cleanup } + + // Cells instantiate modules void visit(AstCell* nodep) override { - m_moduleState(nodep->modp()).m_cellRefs++; - m_moduleState(m_modp).m_childCells.push_back(nodep); - m_instances[m_modp][nodep->modp()]++; - iterateChildren(nodep); + UASSERT_OBJ(m_modVtxp, nodep, "Cell should be under a module"); + + // Create the cell vertex + InlineModCellVertex* const vtxp = m_graphp->getInlineModCellVertexp(nodep); + + // Add containing-module/instantiated-module edges + m_graphp->addEdge(*m_modVtxp, *vtxp); + m_graphp->addEdge(*vtxp, *m_graphp->getInlineModModuleVertexp(nodep->modp())); + + // Iterate children + iterateChildrenConst(nodep); } + void visit(AstPragma* nodep) override { if (nodep->pragType() == VPragmaType::INLINE_MODULE) { - if (!m_modp) { + if (!m_modVtxp) { nodep->v3error("Inline pragma not under a module"); // LCOV_EXCL_LINE - } else if (m_modp->user2() == CIL_MAYBE || m_modp->user2() == CIL_NOTSOFT) { - m_modp->user2(CIL_USER); + } else { + m_modVtxp->setShouldInline("Pragma INLINE_MODULE"); } - // Remove so it does not propagate to upper cell - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - } else if (nodep->pragType() == VPragmaType::NO_INLINE_MODULE) { - if (!m_modp) { - nodep->v3error("Inline pragma not under a module"); // LCOV_EXCL_LINE - } else if (!v3Global.opt.flatten()) { - cantInline("Pragma NO_INLINE_MODULE", false); - } - // Remove so it does not propagate to upper cell - // Remove so don't propagate to upper cell... VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + return; } + + if (nodep->pragType() == VPragmaType::NO_INLINE_MODULE) { + if (!m_modVtxp) { + nodep->v3error("Inline pragma not under a module"); // LCOV_EXCL_LINE + } else { + m_modVtxp->setNoInlineSoft("Pragma NO_INLINE_MODULE"); + } + VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + return; + } + + iterateChildrenConst(nodep); } - void visit(AstVarXRef* nodep) override { - // Keep varp - V3Const::constifyEdit is called during pinReconnectSimple - // which needs varp to be set. V3LinkDot will re-resolve after inlining. - } + + // TODO: Bit nasty to do this here, but historically present, and still necessary void visit(AstNodeFTaskRef* nodep) override { + if (m_modVtxp) m_modVtxp->sizeInc(); // Remove link. V3LinkDot will reestablish it after inlining. // MethodCalls not currently supported by inliner, so keep linked if (!nodep->classOrPackagep() && !VN_IS(nodep, MethodCall)) { nodep->taskp(nullptr); VIsCached::clearCacheTree(); } - iterateChildren(nodep); + iterateChildrenConst(nodep); } - void visit(AstAlways* nodep) override { - if (nodep->keyword() != VAlwaysKwd::CONT_ASSIGN) nodep->user4Inc(); // statement count - iterateChildren(nodep); - } - void visit(AstNodeAssign* nodep) override { - // Don't count assignments, as they'll likely flatten out - // Still need to iterate though to nullify VarXRefs - const int oldcnt = m_modp->user4(); - iterateChildren(nodep); - m_modp->user4(oldcnt); - } - void visit(AstNetlist* nodep) override { - // Build ModuleState, user2, and user4 for all modules. - // Also build m_allMods and m_instances. - iterateChildren(nodep); - // Iterate through all modules in bottom-up order. - // Make a final inlining decision for each. - for (AstNodeModule* const modp : vlstd::reverse_view(m_allMods)) { - - // If we're going to inline some modules into this one, - // update user4 (statement count) to reflect that: - int statements = modp->user4(); - for (const auto& pair : m_instances[modp]) { - const AstNodeModule* const childp = pair.first; - if (m_moduleState(childp).m_inlined) { // inlining child - statements += childp->user4() * pair.second; - } - } - modp->user4(statements); - - const int allowed = modp->user2(); - const int refs = m_moduleState(modp).m_cellRefs; - - // Should we automatically inline this module? - // If --flatten is specified, then force everything to be inlined that can be. - // inlineMult = 2000 by default. - // If a mod*#refs is < this # nodes, can inline it - // Packages aren't really "under" anything so they confuse this algorithm - const bool doit = !VN_IS(modp, Package) // - && allowed != CIL_NOTHARD // - && allowed != CIL_NOTSOFT // - && (allowed == CIL_USER // - || v3Global.opt.flatten() // - || refs == 1 // - || statements < INLINE_MODS_SMALLER // - || v3Global.opt.inlineMult() < 1 // - || refs * statements < v3Global.opt.inlineMult()); - m_moduleState(modp).m_inlined = doit; - UINFO(4, " Inline=" << doit << " Possible=" << allowed << " Refs=" << refs - << " Stmts=" << statements << " " << modp); - } - } - //-------------------- + // Base node void visit(AstNode* nodep) override { - if (m_modp) m_modp->user4Inc(); // Inc statement count - iterateChildren(nodep); + if (m_modVtxp) m_modVtxp->sizeInc(); + iterateChildrenConst(nodep); } + // CONSTRUCTORS + explicit InlineModGraphBuilder(AstNetlist* nodep) { + // Build the module instantiation graph + iterateConst(nodep); + // Order vertices (any topological order is fine), can't be cyclic at this point + m_graphp->order(); + // Check that the first vertex is the top level module (everything, including packages, + // have a corresponding AstCell under the top level at this point). + UASSERT_OBJ(m_graphp->vertices().frontp()->as()->modp()->isTop(), + nodep, "First vertex should be top level module"); +#ifdef VL_DEBUG + for (const V3GraphVertex& vtx : m_graphp->vertices()) { + // First vertex is the top levelmodule, we checked above + if (&vtx == m_graphp->vertices().frontp()) continue; + // Otherwise it should have instantiations + UASSERT_OBJ(!vtx.inEmpty(), &vtx, "Should have edges from root"); + } +#endif + } + ~InlineModGraphBuilder() override = default; + public: - // CONSTRUCTORS - explicit InlineMarkVisitor(AstNode* nodep, ModuleStateUser1Allocator& moduleState) - : m_moduleState{moduleState} { - iterate(nodep); - } - ~InlineMarkVisitor() override { - V3Stats::addStat("Optimizations, Inline unsupported", m_statUnsup); + static std::unique_ptr apply(AstNetlist* nodep) { + return std::move(InlineModGraphBuilder{nodep}.m_graphp); } }; @@ -264,8 +391,12 @@ class InlineRelinkVisitor final : public VNVisitor { m_pinSubstitutedXRefs; // VarXRefs created by pin substitution in this relink pass. // Their dotted/inlinedDots already represent the parent's scope // and must not be rewritten on the immediate visit. + InlineModGraph& m_graph; // The instance graph AstNodeModule* const m_modp; // The module we are inlining into + // The vertex of the module we are inlining into, for updating the graph + InlineModModuleVertex* const m_mVtxp = m_graph.getInlineModModuleVertexp(m_modp); const AstCell* const m_cellp; // The cell being inlined + size_t m_nPlaceholders = 0; // Unique identifier sequence number for placeholder variables // VISITORS @@ -282,6 +413,11 @@ class InlineRelinkVisitor final : public VNVisitor { void visit(AstCell* nodep) override { // Cell under the inline cell, need to rename to avoid conflicts nodep->name(m_cellp->name() + "__DOT__" + nodep->name()); + // Need to update graph + nodep->user4p(nullptr); // clone copied user4p, reset to make new vertex + InlineModCellVertex* const vtxp = m_graph.getInlineModCellVertexp(nodep); + m_graph.addEdge(*m_mVtxp, *vtxp); + m_graph.addEdge(*vtxp, *m_graph.getInlineModModuleVertexp(nodep->modp())); iterateChildren(nodep); } void visit(AstClass* nodep) override { @@ -464,8 +600,10 @@ class InlineRelinkVisitor final : public VNVisitor { public: // CONSTRUCTORS - InlineRelinkVisitor(AstNodeModule* cloneModp, AstNodeModule* oldModp, AstCell* cellp) - : m_modp{oldModp} + InlineRelinkVisitor(AstNodeModule* cloneModp, AstNodeModule* oldModp, AstCell* cellp, + InlineModGraph& graph) + : m_graph{graph} + , m_modp{oldModp} , m_cellp{cellp} { // CellInlines added by V3Begin for generate/named blocks have origModName // "__BEGIN__"; only those added by prior V3Inline passes carry a real module @@ -607,7 +745,7 @@ void connectPort(AstNodeModule* modp, AstVar* nodep, AstNodeExpr* pinExprp) { } // Inline 'cellp' into 'modp'. 'last' indicatest this is tha last instance of the inlined module -void inlineCell(AstNodeModule* modp, AstCell* cellp, bool last) { +void inlineCell(AstNodeModule* modp, AstCell* cellp, bool last, InlineModGraph& graph) { UINFO(5, " Inline Cell " << cellp); UINFO(5, " into Module " << modp); @@ -662,8 +800,8 @@ void inlineCell(AstNodeModule* modp, AstCell* cellp, bool last) { connectPort(modp, newModVarp, pinExprp); } - // Cleanup var names, etc, to not conflict, relink replaced variables - { InlineRelinkVisitor{inlinedp, modp, cellp}; } + // Cleanup var names, etc, to not conflict, relink replaced variables, adjust graph + { InlineRelinkVisitor{inlinedp, modp, cellp, graph}; } // Move statements from the inlined module into the module we are inlining into if (AstNode* const stmtsp = inlinedp->stmtsp()) { modp->addStmtsp(stmtsp->unlinkFrBackWithNext()); @@ -675,39 +813,60 @@ void inlineCell(AstNodeModule* modp, AstCell* cellp, bool last) { } // Apply all inlining decisions -void process(AstNetlist* netlistp, ModuleStateUser1Allocator& moduleStates) { +void process(AstNetlist* netlistp, InlineModGraph& graph) { // NODE STATE - // Input: - // AstNodeModule::user1p() // ModuleState instance (via moduleState) - // // Cleared entire netlist // AstIfaceRefDType::user1() // Whether the cell pointed to by this // // AstIfaceRefDType has been inlined // AstCell::user3p() // AstCell*, the clone - // AstVar::user3p() // AstVar*, the clone clone + // AstVar::user3p() // AstVar*, the clone // Cleared each cell // AstVar::user2p() // AstVarRef*/AstConst* This port is connected to (AstPin::expr()) - const VNUser3InUse m_user3InUse; + const VNUser1InUse user1InUse; + const VNUser3InUse user3InUse; // Number of inlined instances, for statistics VDouble0 m_nInlined; - // We want to inline bottom up. The modules under the netlist are in - // dependency order (top first, leaves last), so find the end of the list. - AstNode* nodep = netlistp->modulesp(); - while (nodep->nextp()) nodep = nodep->nextp(); + // Gather all cells that need to be inlined (this is in topological order) + std::vector cVtxps; + for (V3GraphVertex& vtx : graph.vertices()) { + InlineModCellVertex* const cVtxp = vtx.cast(); + if (!cVtxp) continue; + if (!cVtxp->doInline()) continue; + cVtxps.push_back(cVtxp); + } - // Iterate module list backwards (stop when we get back to the Netlist) - while (AstNodeModule* const modp = VN_CAST(nodep, NodeModule)) { - nodep = nodep->backp(); + // Inline cells bottom up (leaves into roots) + for (InlineModCellVertex* const cVtxp : vlstd::reverse_view(cVtxps)) { + // Pick up parts before deleting + InlineModModuleVertex& mVtx = cVtxp->instanceIn(); + InlineModModuleVertex* const iVtxp = &cVtxp->instanceOf(); + AstCell* const cellp = cVtxp->cellp(); + const bool last = iVtxp->inSize1(); + UASSERT_OBJ(!iVtxp->noInlineHard(), cellp, "Should not be inlining if not possible"); - // Consider each cell inside the current module for inlining - for (AstCell* const cellp : moduleStates(modp).m_childCells) { - ModuleState& childState = moduleStates(cellp->modp()); - if (!childState.m_inlined) continue; - ++m_nInlined; - inlineCell(modp, cellp, --childState.m_cellRefs == 0); + // Update + ++m_nInlined; + mVtx.sizeInc(iVtxp->size()); // For debug dump only + + // Delete the cell we are inlining + VL_DO_DANGLING(cVtxp->unlinkDelete(&graph), cVtxp); + // Delete the module we are inlining if this is the last instance + if (last) { + while (!iVtxp->outEmpty()) { + InlineModCellVertex* const tVtxp + = iVtxp->outEdges().frontp()->top()->as(); + // Bottom up ordering ensures this + UASSERT_OBJ(!tVtxp->doInline(), tVtxp, "Should have been inlined"); + VL_DO_DANGLING(tVtxp->unlinkDelete(&graph), tVtxp); + } + VL_DO_DANGLING(iVtxp->unlinkDelete(&graph), iVtxp); } + + // Do it + inlineCell(mVtx.modp(), cellp, last, graph); + if (dumpGraphLevel() >= 9) graph.dumpDotFilePrefixed("inlinemod-cell"); } V3Stats::addStat("Optimizations, Inlined instances", m_nInlined); @@ -729,25 +888,65 @@ void process(AstNetlist* netlistp, ModuleStateUser1Allocator& moduleStates) { void V3Inline::inlineAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ":"); - { - const VNUser1InUse m_inuser1; // output of InlineMarkVisitor, input to InlineVisitor. - ModuleStateUser1Allocator moduleState; // AstUser1Allocator + // Build the bipartite module instantiation graph + std::unique_ptr graphp = InlineModGraphBuilder::apply(nodep); + if (dumpGraphLevel() >= 6) graphp->dumpDotFilePrefixed("inlinemod-graph"); - // Scoped to clean up temp userN's - { InlineMarkVisitor{nodep, moduleState}; } - - // Inline the modles we decided to inline - ModuleInliner::process(nodep, moduleState); - - // Check inlined modules have been removed during traversal. Otherwise we might have blown - // up Verilator memory consumption. - for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; - modp = VN_AS(modp->nextp(), NodeModule)) { - UASSERT_OBJ(!moduleState(modp).m_inlined, modp, - "Inlined module should have been deleted when the last instance " - "referencing it was inlined"); + // Decide which instances to inline + const size_t designSize + = graphp->vertices().frontp()->as()->flattenedSize(); + for (V3GraphVertex& vtx : graphp->vertices()) { + if (InlineModModuleVertex* const mVtxp = vtx.cast()) { + // If this module is less than 10% of the design, flatten this module + if (mVtxp->flattenedSize() * 10 < designSize) mVtxp->setFlatten(); + // Don't inline if can't inline + if (mVtxp->noInlineHard()) continue; + // Don't inline if soft off + if (mVtxp->noInlineSoft()) continue; + // If all instances of this module combined are less than 20% of the design, inline all + size_t totalSize = mVtxp->flattenedSize() * mVtxp->instanceCount(); + if (totalSize * 5 < designSize) { + for (V3GraphEdge& edge : mVtxp->inEdges()) { + InlineModCellVertex* const cVtxp = edge.fromp()->as(); + cVtxp->setDoInline("< 20% of design"); + } + } + // No more decisions based on module vertex + continue; } + + // The instantiation + InlineModCellVertex& cVtx = *vtx.as(); + // The module instantiated by this cell + InlineModModuleVertex& mVtx = cVtx.instanceOf(); + + // Don't inline if can't inline, duh! + if (mVtx.noInlineHard()) continue; + + // If it should be inlined, inlined it + if (mVtx.shouldInline()) cVtx.setDoInline("should inline"); + // If --flatten, inline it + if (v3Global.opt.flatten()) cVtx.setDoInline("--flatten"); + + // Don't inline for other reasons if soft off + if (mVtx.noInlineSoft()) continue; + + // If instatiated in exactly one static site, inline it + if (mVtx.inSize1()) cVtx.setDoInline("Single static instance"); + // If small, inline it + if (mVtx.size() < INLINE_MODS_SMALLER) cVtx.setDoInline("Small"); + // If inlineMult is 0, inline it + if (v3Global.opt.inlineMult() < 1) cVtx.setDoInline("inlineMult < 1"); + // If it would yield less than the given number of ops, inline it + const size_t inlinedSize = mVtx.inEdges().size() * mVtx.size(); + const size_t limit = v3Global.opt.inlineMult(); + if (inlinedSize < limit) cVtx.setDoInline("inlinedSize < inlineMult"); } + if (dumpGraphLevel() >= 6) graphp->dumpDotFilePrefixed("inlinemod-decision"); + + // Inline the modles we decided to inline + ModuleInliner::process(nodep, *graphp); + if (dumpGraphLevel() >= 6) graphp->dumpDotFilePrefixed("inlinemod-inlined"); V3Global::dumpCheckGlobalTree("inline", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 7dd5fe3ea..33e2d38b5 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1013,18 +1013,23 @@ public: if (checkUnresolvedRef(VN_CAST(dtypep, RefDType))) return true; } else if (const AstParamTypeDType* const paramTypep = VN_CAST(symp->nodep(), ParamTypeDType)) { - // ParamTypeDType child may be wrapped in RequireDType or unwrapped + // Before V3Param the declared default is in childDTypep (possibly + // wrapped in a RequireDType); after V3Param it is consumed and the + // bound type is the resolved data type, e.g. a type parameter + // inherited from a specialized base class (REQ #(Item) -> class Item). AstNode* childp = paramTypep->childDTypep(); if (const AstRequireDType* const reqp = VN_CAST(childp, RequireDType)) { childp = reqp->lhsp(); } - if (isValidTypeNode(childp)) return true; - if (checkUnresolvedRef(VN_CAST(childp, RefDType))) return true; + const AstNode* const checkp = childp ? childp : paramTypep->skipRefp(); + if (isValidTypeNode(checkp)) return true; + if (checkUnresolvedRef(VN_CAST(checkp, RefDType))) return true; } return false; } VSymEnt* resolveClassOrPackage(VSymEnt* lookSymp, AstClassOrPackageRef* nodep, bool fallback, - bool classOnly, const string& forWhat) { + bool classOnly, const string& forWhat, + bool deferIfUnresolved = false) { if (nodep->classOrPackageSkipp()) return getNodeSym(nodep->classOrPackageSkipp()); VSymEnt* foundp; VSymEnt* searchSymp = lookSymp; @@ -1050,6 +1055,7 @@ public: nodep->classOrPackageNodep(foundp->nodep()); return foundp; } + if (deferIfUnresolved) return nullptr; const string suggest = suggestSymFallback(lookSymp, nodep->name(), LinkNodeMatcherClassOrPackage{}); nodep->v3error((classOnly ? "Class" : "Package/class") @@ -4758,8 +4764,9 @@ class LinkDotResolveVisitor final : public VNVisitor { VL_RESTORER(m_pinSymp); if (!nodep->classOrPackageSkipp() && nodep->name() != "local::") { + const bool deferIfUnresolved = m_statep->forPrimary() && m_insideClassExtParam; m_statep->resolveClassOrPackage(m_ds.m_dotSymp, nodep, m_ds.m_dotPos != DP_PACKAGE, - false, ":: reference"); + false, ":: reference", deferIfUnresolved); } // ClassRef's have pins, so track diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp index f8e3c6138..e473325cd 100644 --- a/src/V3LinkInc.cpp +++ b/src/V3LinkInc.cpp @@ -307,6 +307,7 @@ class LinkIncVisitor final : public VNVisitor { return new AstSub{nodep->fileline(), lhsp, rhsp}; case AstAssignCompound::operation::Xor: return new AstXor{nodep->fileline(), lhsp, rhsp}; + default:; // Error below // LCOV_EXCL_LINE } } nodep->v3fatalSrc("Unhandled compound assignment operation"); diff --git a/src/V3Number.cpp b/src/V3Number.cpp index a9c505359..d97e4ed50 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -1464,6 +1464,20 @@ V3Number& V3Number::opCLog2(const V3Number& lhs) { setZero(); return *this; } +V3Number& V3Number::opMostSetBitP1(const V3Number& lhs) { + // Most-significant set bit plus one (bit-width / find-last-set); 0 if value is zero + NUM_ASSERT_OP_ARGS1(lhs); + NUM_ASSERT_LOGIC_ARGS1(lhs); + if (lhs.isFourState()) return setAllBitsX(); + for (int bit = lhs.width() - 1; bit >= 0; bit--) { + if (lhs.bitIs1(bit)) { + setLong(bit + 1); + return *this; + } + } + setZero(); + return *this; +} V3Number& V3Number::opLogNot(const V3Number& lhs) { NUM_ASSERT_OP_ARGS1(lhs); diff --git a/src/V3Number.h b/src/V3Number.h index 3791f2f19..d81e32d72 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -761,6 +761,7 @@ public: V3Number& opOneHot(const V3Number& lhs); V3Number& opOneHot0(const V3Number& lhs); V3Number& opCLog2(const V3Number& lhs); + V3Number& opMostSetBitP1(const V3Number& lhs); V3Number& opClean(const V3Number& lhs, uint32_t bits); V3Number& opConcat(const V3Number& lhs, const V3Number& rhs); V3Number& opLenN(const V3Number& lhs); diff --git a/src/V3Options.cpp b/src/V3Options.cpp index a23a408b2..f9502e00c 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -542,7 +542,7 @@ bool V3Options::fileStatNormal(const string& filename) { } string V3Options::fileExists(const string& filename) { - // Surprisingly, for VCS and other simulators, this process + // Surprisingly, for some other simulators, this process // is quite slow; presumably because of re-reading each directory // many times. So we read a whole dir at once and cache it @@ -1448,6 +1448,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, DECL_OPTION("-facyc-simp", FOnOff, &m_fAcycSimp); DECL_OPTION("-fassemble", FOnOff, &m_fAssemble); + DECL_OPTION("-fbit-scan-loops", FOnOff, &m_fBitScanLoops); DECL_OPTION("-fcase", CbFOnOff, [this](bool flag) { m_fCaseDecoder = flag; m_fCaseTable = flag; @@ -2359,6 +2360,7 @@ void V3Options::optimize(int level) { const bool flag = level > 0; m_fAcycSimp = flag; m_fAssemble = flag; + m_fBitScanLoops = flag; m_fCaseDecoder = flag; m_fCaseTable = flag; m_fCaseTree = flag; diff --git a/src/V3Options.h b/src/V3Options.h index f3dd59863..182379fe9 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -392,6 +392,7 @@ private: // MEMBERS (optimizations) bool m_fAcycSimp; // main switch: -fno-acyc-simp: acyclic pre-optimizations bool m_fAssemble; // main switch: -fno-assemble: assign assemble + bool m_fBitScanLoops; // main switch: -fno-bit-scan-loops: convert bit scan loops to builtins bool m_fCaseDecoder; // main switch: -fno-case-decoder: case decoder conversion bool m_fCaseTable; // main switch: -fno-case-table: case table conversion bool m_fCaseTree; // main switch: -fno-case-tree: case tree conversion @@ -731,6 +732,7 @@ public: // ACCESSORS (optimization options) bool fAcycSimp() const { return m_fAcycSimp; } bool fAssemble() const { return m_fAssemble; } + bool fBitScanLoops() const { return m_fBitScanLoops; } bool fCaseDecoder() const { return m_fCaseDecoder; } bool fCaseTable() const { return m_fCaseTable; } bool fCaseTree() const { return m_fCaseTree; } diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 36699526d..2786ea305 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -1053,7 +1053,7 @@ class ConstraintExprVisitor final : public VNVisitor { nodep->user1(false); return; } - bool anyChild = false; + int anyChild = false; // Used as bool if (AstNodeExpr* const cp = VN_CAST(nodep->op1p(), NodeExpr)) { propagateUser1InlineRecurse(cp); anyChild |= cp->user1(); @@ -1171,16 +1171,18 @@ class ConstraintExprVisitor final : public VNVisitor { // else: Global constraints keep nodep alive for write_var processing relinker.relink(exprp); - // For global constraints: check shared path-level set - // For inline constraints: check per-instance set (each __Vrandwith has own randomizer) - // For class-level constraints: check varp->user3() + // Global / inline / class-level member-select refs key on the full path + // (so same-type sub-objects c1.x, c2.x stay distinct); a plain class-level + // variable keys on user3(). const bool alreadyWritten = isGlobalConstrained ? m_writtenVars.count(smtName) > 0 : m_inlineInitTaskp ? m_inlineWrittenVars.count(smtName) > 0 + : membersel ? m_writtenVars.count(smtName) > 0 : varp->user3(); const bool shouldWriteVar = !alreadyWritten; if (shouldWriteVar) { // Track this variable path as written - if (isGlobalConstrained) m_writtenVars.insert(smtName); + if (isGlobalConstrained || (membersel && !m_inlineInitTaskp)) + m_writtenVars.insert(smtName); if (m_inlineInitTaskp) m_inlineWrittenVars.insert(smtName); // For global constraints, delete nodep after processing if (isGlobalConstrained && !nodep->backp()) VL_DO_DANGLING(pushDeletep(nodep), nodep); @@ -3882,6 +3884,22 @@ class RandomizeVisitor final : public VNVisitor { return VN_IS(dtypep, ClassRefDType); }); } + // True if this class owns a global constraint: a member-select chain rooted + // at a rand class-typed handle reaching into a sub-object. + bool classOwnsGlobalConstraint(const AstClass* classp) const { + return classp->existsMember([](const AstClass*, const AstConstraint* constrp) { + bool owns = false; + constrp->foreach([&](const AstMemberSel* memberSelp) { + const AstNode* rootp = memberSelp->fromp(); + while (const AstMemberSel* const sp = VN_CAST(rootp, MemberSel)) + rootp = sp->fromp(); + if (const AstVarRef* const refp = VN_CAST(rootp, VarRef)) { + if (VN_IS(refp->varp()->dtypep()->skipRefp(), ClassRefDType)) owns = true; + } + }); + return owns; + }); + } // Get or create __VrandCb_pre/__VrandCb_post task for nested callbacks AstTask* getCreateNestedCallbackTask(AstClass* classp, const string& suffix) { const string name = "__VrandCb_" + suffix; @@ -4773,6 +4791,10 @@ class RandomizeVisitor final : public VNVisitor { UINFO(9, "Define randomize() for " << nodep); nodep->baseMostClassp()->needRNG(true); + // Detect global-constraint ownership BEFORE the constraint items are + // unlinked into setup tasks below (after that the member-selects are gone). + const bool basicFirst = classOwnsGlobalConstraint(nodep); + FileLine* fl = nodep->fileline(); AstFunc* const randomizep = V3Randomize::newRandomizeFunc(m_memberMap, nodep); AstVar* const fvarp = VN_AS(randomizep->fvarp(), Var); @@ -5081,29 +5103,41 @@ class RandomizeVisitor final : public VNVisitor { beginValp = new AstConst{fl, AstConst::WidthedValue{}, 32, 1}; } + AstFunc* const basicRandomizep + = V3Randomize::newRandomizeFunc(m_memberMap, nodep, BASIC_RANDOMIZE_FUNC_NAME); + addBasicRandomizeBody(basicRandomizep, nodep, randModeVarp); + // A basicFirst owner basic-randomizes first, then the solver overrides the + // constrained leaves, so a globally-constrained leaf (not user3) is still + // basic-randomized when its type is randomized standalone. AstVarRef* const fvarRefp = new AstVarRef{fl, fvarp, VAccess::WRITE}; - randomizep->addStmtsp(new AstAssign{fl, fvarRefp, beginValp}); + randomizep->addStmtsp(new AstAssign{ + fl, fvarRefp, basicFirst ? new AstFuncRef{fl, basicRandomizep} : beginValp}); const auto sizeArraysIt = m_sizeConstrainedArrays.find(nodep); const bool needsSizePhase = sizeArraysIt != m_sizeConstrainedArrays.end() && !sizeArraysIt->second.empty(); - if (!needsSizePhase) { + // Size-only resize fallback (no element constraint, so no two-pass phase). + // Must run after the solver .next() that sets the size variable; emit it + // after whichever assignment below holds the solver call. + const auto emitResizeFallback = [&]() { + if (needsSizePhase) return; if (AstTask* const resizeAllTaskp = VN_AS(m_memberMap.findMember(nodep, "__Vresize_constrained_arrays"), Task)) { AstTaskRef* const resizeTaskRefp = new AstTaskRef{fl, resizeAllTaskp}; randomizep->addStmtsp(resizeTaskRefp->makeStmt()); } - } + }; + if (!basicFirst) emitResizeFallback(); AstVarRef* const fvarRefReadp = fvarRefp->cloneTree(false); fvarRefReadp->access(VAccess::READ); - AstFunc* const basicRandomizep - = V3Randomize::newRandomizeFunc(m_memberMap, nodep, BASIC_RANDOMIZE_FUNC_NAME); - addBasicRandomizeBody(basicRandomizep, nodep, randModeVarp); - AstFuncRef* const basicRandomizeCallp = new AstFuncRef{fl, basicRandomizep}; + AstNodeExpr* const secondHalfp + = basicFirst ? beginValp : new AstFuncRef{fl, basicRandomizep}; randomizep->addStmtsp(new AstAssign{fl, fvarRefp->cloneTree(false), - new AstAnd{fl, fvarRefReadp, basicRandomizeCallp}}); + new AstAnd{fl, fvarRefReadp, secondHalfp}}); + + if (basicFirst) emitResizeFallback(); // Call nested post_randomize on rand class-type members (IEEE 18.4.1) if (classHasRandClassMembers(nodep)) { @@ -5643,15 +5677,21 @@ public: explicit RandomizeVisitor(AstNetlist* nodep) : m_inlineUniqueNames{"__Vrandwith"} { createRandomizeClassVars(nodep); - // Mark variables in global constraints - // These should not be randomized in nested class's __VBasicRand - nodep->foreach([&](AstConstraint* constrp) { - constrp->foreach([&](AstMemberSel* memberSelp) { - // Only mark if this MemberSel was created during constraint cloning - if (memberSelp->user2p()) { + // Flag local constraint leaves as solver-owned so __VBasicRand skips them. + // Runs before any class is lowered. Only a randomized class counts, and + // only a leaf owned by the constraint's own class: a leaf reached through + // a global constraint stays basic-randomized so a standalone randomize() + // of its type still randomizes it (issue #7833); a class-typed sub-object + // is skipped so its own members are still basic-randomized. + nodep->foreach([&](AstClass* const classp) { + if (!classp->user1()) return; + classp->foreachMember([&](AstClass* const ownerClassp, AstConstraint* const constrp) { + constrp->foreach([&](AstMemberSel* const memberSelp) { AstVar* const varp = memberSelp->varp(); + if (VN_IS(varp->dtypep()->skipRefp(), ClassRefDType)) return; + if (VN_AS(varp->user2p(), NodeModule) != ownerClassp) return; if (!varp->user3()) varp->user3(true); - } + }); }); }); diff --git a/src/V3SchedVirtIface.cpp b/src/V3SchedVirtIface.cpp index 4dd95662d..41684cd2b 100644 --- a/src/V3SchedVirtIface.cpp +++ b/src/V3SchedVirtIface.cpp @@ -39,11 +39,18 @@ namespace { class VirtIfaceVisitor final : public VNVisitor { private: // STATE + using IfaceMember = std::pair; + using IfaceCallable = std::pair; + // Set of (iface, member) pairs written through VIF -- defines which members need triggers - std::set> m_vifWrittenMembers; + std::set m_vifWrittenMembers; // All candidate VarScopes of interface members (keyed by interface type + member name) - std::map, std::vector> - m_candidateVscps; + std::map> m_candidateVscps; + std::set> m_seenCandidateVscps; + // VarScope index and callable worklist for VIF method-body writes. + std::map> m_vscpsByVar; + std::vector m_reachableIfaceCallables; + std::set m_seenReachableIfaceCallables; VirtIfaceTriggers m_triggers; // METHODS @@ -70,12 +77,24 @@ private: } iterateChildren(nodep); } + void visit(AstCMethodCall* nodep) override { + if (const AstIfaceRefDType* const dtypep + = VN_CAST(nodep->fromp()->dtypep()->skipRefp(), IfaceRefDType)) { + if (VL_UNCOVERABLE(!dtypep->isVirtual())) { + // Concrete interface method calls are lowered before this pass. + } else { + addReachableIfaceCallable(dtypep->ifaceViaCellp(), nodep->funcp()); + } + } + iterateChildren(nodep); + } void visit(AstVarScope* nodep) override { // Collect candidate VarScopes. sensIfacep() is set on interface members // accessed via any MemberSel (virtual or non-virtual). - if (const AstIface* const ifacep = nodep->varp()->sensIfacep()) { - m_candidateVscps[{ifacep, nodep->varp()->name()}].push_back(nodep); - } + AstVar* const varp = nodep->varp(); + if (varp->isTemp()) return; + m_vscpsByVar[varp].push_back(nodep); + if (const AstIface* const ifacep = varp->sensIfacep()) addCandidateVscp(ifacep, nodep); } void visit(AstNodeProcedure* nodep) override { // Disable lifetime optimization for variables in AlwaysPost blocks @@ -87,6 +106,19 @@ private: } void visit(AstNode* nodep) override { iterateChildren(nodep); } + void addCandidateVscp(const AstIface* const ifacep, AstVarScope* const vscp) { + const IfaceMember member{ifacep, vscp->varp()->name()}; + if (m_seenCandidateVscps.emplace(member, vscp).second) + m_candidateVscps[member].push_back(vscp); + } + + void addReachableIfaceCallable(AstIface* const ifacep, AstCFunc* const funcp) { + const IfaceCallable callable{ifacep, funcp}; + if (m_seenReachableIfaceCallables.emplace(callable).second) { + m_reachableIfaceCallables.push_back(callable); + } + } + // Build final trigger list by intersecting VIF writes with candidate VarScopes void buildTriggers() { for (const auto& written : m_vifWrittenMembers) { @@ -103,6 +135,29 @@ public: // CONSTRUCTORS explicit VirtIfaceVisitor(AstNetlist* nodep) { iterate(nodep); + for (size_t i = 0; i < m_reachableIfaceCallables.size(); ++i) { + const IfaceCallable callable = m_reachableIfaceCallables[i]; + callable.second->foreach([this, callable](AstNodeExpr* const nodep) { + if (AstVarRef* const refp = VN_CAST(nodep, VarRef)) { + // Only persistent interface storage is observable through a VIF read. + UASSERT_OBJ(refp->varScopep(), refp, "No var scope"); + AstVar* const varp = refp->varp(); + if (!refp->access().isWriteOrRW() || varp->isFuncLocal() || varp->isTemp() + || varp->isEvent() || !VN_IS(refp->varScopep()->scopep()->modp(), Iface)) { + return; + } + varp->sensIfacep(callable.first); + m_vifWrittenMembers.emplace(callable.first, varp->name()); + const auto it = m_vscpsByVar.find(varp); + UASSERT_OBJ(it != m_vscpsByVar.end(), varp, + "No VarScope for interface member"); + for (AstVarScope* const vscp : it->second) + addCandidateVscp(callable.first, vscp); + } else if (AstNodeCCall* const callp = VN_CAST(nodep, NodeCCall)) { + addReachableIfaceCallable(callable.first, callp->funcp()); + } + }); + } buildTriggers(); } ~VirtIfaceVisitor() override = default; diff --git a/src/V3Unroll.cpp b/src/V3Unroll.cpp index b5413e8b6..62cf42fa9 100644 --- a/src/V3Unroll.cpp +++ b/src/V3Unroll.cpp @@ -62,6 +62,8 @@ struct UnrollStats final { Stat m_nPragmaDisabled{"Pragma unroll_disable"}; Stat m_nUnrolledLoops{"Unrolled loops"}; Stat m_nUnrolledIters{"Unrolled iterations"}; + Stat m_bitScanLowered{"Lowered priority-encoder to mostsetbitp1"}; + Stat m_countOnesLowered{"Lowered count-set-bits to countones"}; }; //###################################################################### @@ -422,6 +424,157 @@ class UnrollAllVisitor final : VNVisitor { UnrollStats m_stats; // Statistic tracking UnrolllBindings m_bindings; // Variable bindings + // METHODS + // Peel value-preserving width casts (Extend/ExtendS, or a low-bits Sel with lsb 0) to the + // underlying VarRef. A Sel kept narrower than 'minWidth' is a lossy narrowing (idx[1:0]) + // and is rejected. + static AstVarRef* unwrapToVarRef(AstNodeExpr* nodep, int minWidth) { + while (true) { + if (AstVarRef* const refp = VN_CAST(nodep, VarRef)) return refp; + if (AstExtend* const ep = VN_CAST(nodep, Extend)) { + nodep = ep->lhsp(); + } else if (AstExtendS* const ep = VN_CAST(nodep, ExtendS)) { + nodep = ep->lhsp(); + } else if (AstSel* const sp = VN_CAST(nodep, Sel)) { + const AstConst* const lsbp = VN_CAST(sp->lsbp(), Const); + if (!lsbp || lsbp->toUInt() != 0 || sp->width() < minWidth) return nullptr; + nodep = sp->fromp(); + } else { + return nullptr; + } + } + } + // True if 'nodep' is exactly '1 + var' for 'vscp' (V3Const puts the constant on the LHS). + // Passing the add's width as minWidth rejects a lossy increment like 32'(i[1:0]) + 1. + bool isVarPlus1(AstNode* nodep, const AstVarScope* vscp) { + AstAdd* const addp = VN_CAST(nodep, Add); + if (!addp || !addp->lhsp()->isOne()) return false; + const AstVarRef* const r = unwrapToVarRef(addp->rhsp(), addp->width()); + return r && r->varScopep() == vscp; + } + // Resize the 32-bit reduction to the accumulator width; truncating the low bits matches + // the original counted loop's wrap-around. + static AstNodeExpr* resizeToWidth(AstNodeExpr* exprp, const AstVarRef* targetRefp) { + const int width = targetRefp->width(); + if (width == 32) return exprp; + FileLine* const flp = exprp->fileline(); + if (width < 32) return new AstSel{flp, exprp, 0, width}; + AstExtend* const extp = new AstExtend{flp, exprp}; + extp->dtypeFrom(targetRefp); + return extp; + } + // Match a strict ascending loop bound 'idx < W'. V3Const canonicalizes this to the + // 'W > idx' form (Gt unsigned, GtS signed), so only that form is matched. + static bool ascendingBound(AstNodeExpr* condp, AstConst*& wp, AstVarRef*& idxRefp) { + if (!VN_IS(condp, Gt) && !VN_IS(condp, GtS)) return false; + AstNodeBiop* const bp = VN_AS(condp, NodeBiop); + wp = VN_CAST(bp->lhsp(), Const); + idxRefp = VN_CAST(bp->rhsp(), VarRef); + return wp && idxRefp && !wp->num().isFourState(); + } + // Recognize the redundant in-range guard Verilator auto-inserts for a select into a + // non-power-of-two vector. V3Const canonicalizes 'idx <= C' to '(C >= idx)' (Gte/GteS, + // const on the LHS), so only that form occurs; with C >= W-1 it is always true for idx + // in 0..W-1. + static bool isInRangeGuard(AstNodeExpr* condp, const AstVarScope* idxVscp, uint32_t width, + int addrBits) { + if (!VN_IS(condp, Gte) && !VN_IS(condp, GteS)) return false; + AstNodeBiop* const bp = VN_AS(condp, NodeBiop); + const AstConst* const cp = VN_CAST(bp->lhsp(), Const); + if (!cp || cp->num().isFourState() || cp->toUInt() < width - 1) return false; + const AstVarRef* const r = unwrapToVarRef(bp->rhsp(), addrBits); + return r && r->varScopep() == idxVscp; + } + // Recognize a single-bit scan loop over all W bits of 'vec' (idx 0..W-1, target + // pre-zeroed) and lower it to a bit-reduction primitive. Two idioms are matched: + // target = 0; idx = 0; + // loop { looptest(W > idx); if (...vec[idx]...) target = ; idx = idx + 1; } + // where, when W == width(vec): + // = idx + 1 => target = $mostsetbitp1(vec) (leading-one / bit-width) + // = target + 1 => target = $countones(vec) (population count) + bool tryLowerBitScanLoop(AstLoop* loopp) { + AstLoopTest* const testp = VN_CAST(loopp->stmtsp(), LoopTest); + if (!testp) return false; + AstIf* const ifp = VN_CAST(testp->nextp(), If); + if (!ifp) return false; + AstAssign* const incp = VN_CAST(ifp->nextp(), Assign); + if (!incp || incp->nextp()) return false; + AstConst* wp = nullptr; + AstVarRef* idxRefp = nullptr; + if (!ascendingBound(testp->condp(), wp, idxRefp)) return false; + AstVarScope* const idxVscp = idxRefp->varScopep(); + const uint32_t width = wp->toUInt(); + // Bits needed to address all W bits of 'vec' (clog2(W)); a narrower index is lossy. + const int addrBits = width <= 1 ? 1 : V3Number::log2b(width - 1) + 1; + const AstConst* const idxInitp = m_bindings.get(idxVscp); + if (!idxInitp || !idxInitp->isZero()) return false; + AstVarRef* const incLhsp = VN_CAST(incp->lhsp(), VarRef); + if (!incLhsp || incLhsp->varScopep() != idxVscp) return false; + if (!isVarPlus1(incp->rhsp(), idxVscp)) return false; + if (ifp->elsesp()) return false; + AstAssign* const thenp = VN_CAST(ifp->thensp(), Assign); + if (!thenp || thenp->nextp()) return false; + AstVarRef* const targetRefp = VN_CAST(thenp->lhsp(), VarRef); + if (!targetRefp) return false; + AstVarScope* const targetVscp = targetRefp->varScopep(); + if (targetVscp == idxVscp) return false; + const bool isLeadingOne = isVarPlus1(thenp->rhsp(), idxVscp); + const bool isCountOnes = !isLeadingOne && isVarPlus1(thenp->rhsp(), targetVscp); + if (!isLeadingOne && !isCountOnes) return false; + // If-cond is the 1-bit select 'vec[idx]', possibly wrapped in the redundant in-range + // guard Verilator auto-inserts (as 'guard && sel') for a non-power-of-two vector: + // '(idx <= W-1) && vec[idx]' (default / --x-assign 0; a LogAnd), or + // '(idx <= W-1) ? vec[idx] : ' (--x-assign unique; a Cond). + // The guard is always true for idx in 0..W-1, so peel it to reach the select. Any + // other compound condition (e.g. 'vec[idx] && en') leaves a non-select, rejected below. + AstNodeExpr* condp = ifp->condp(); + if (AstLogAnd* const andp = VN_CAST(condp, LogAnd)) { + if (isInRangeGuard(andp->lhsp(), idxVscp, width, addrBits)) condp = andp->rhsp(); + } else if (AstCond* const ternp = VN_CAST(condp, Cond)) { + if (isInRangeGuard(ternp->condp(), idxVscp, width, addrBits)) condp = ternp->thenp(); + } + AstSel* const selp = VN_CAST(condp, Sel); + if (!selp || selp->width() != 1) return false; + const AstVarRef* const fromp = VN_CAST(selp->fromp(), VarRef); + if (!fromp) return false; + const AstVarScope* const fromVscp = fromp->varScopep(); + if (fromVscp == idxVscp || fromVscp == targetVscp) return false; + AstNodeExpr* const vecExprp = selp->fromp(); + // Must scan all W bits of 'vec', indexed by exactly 'idx' (address kept >= clog2(W), + // so a lossy narrowing like vec[idx[2:0]] is rejected). + if (static_cast(width) != vecExprp->width()) return false; + const AstVarRef* const idxInSel = unwrapToVarRef(selp->lsbp(), addrBits); + if (!idxInSel || idxInSel->varScopep() != idxVscp) return false; + // 'target' must be const-0 immediately before the loop (collected in m_bindings), + // so that an all-zero 'vec' yields 0, matching $mostsetbitp1's definition. + const AstConst* const targetInitp = m_bindings.get(targetVscp); + if (!targetInitp || !targetInitp->isZero()) return false; + // Rewrite to 'target = (vec); idx = W'. The 'idx = W' store preserves the + // loop's exit value, so this is sound even if idx is read afterwards (else DCE drops it). + FileLine* const flp = loopp->fileline(); + AstNodeExpr* reducep; + if (isLeadingOne) { + reducep = new AstMostSetBitP1{flp, vecExprp->cloneTree(false)}; + } else { + AstCountOnes* const conep = new AstCountOnes{flp, vecExprp->cloneTree(false)}; + conep->dtypeSetInteger2State(); + reducep = conep; + } + reducep = resizeToWidth(reducep, targetRefp); + AstAssign* const newp = new AstAssign{flp, targetRefp->cloneTree(false), reducep}; + newp->addNext(new AstAssign{flp, incLhsp->cloneTree(false), wp->cloneTree(false)}); + loopp->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(loopp), loopp); + if (isLeadingOne) { + UINFO(4, "Lowered priority-encoder loop to $mostsetbitp1: " << newp); + ++m_stats.m_bitScanLowered; + } else { + UINFO(4, "Lowered count-set-bits loop to $countones: " << newp); + ++m_stats.m_countOnesLowered; + } + return true; + } + // VISIT void visit(AstLoop* nodep) override { // Gather variable bindings from the preceding statements @@ -450,6 +603,9 @@ class UnrollAllVisitor final : VNVisitor { m_bindings.set(lhsp->varScopep(), valp); } + // Recognize a bit counting loop and lower it to a builtin + if (v3Global.opt.fBitScanLoops() && tryLowerBitScanLoop(nodep)) return; + // Attempt to unroll this loop const std::pair pair = UnrollOneVisitor::apply(m_stats, m_bindings, nodep); diff --git a/src/VlcTop.cpp b/src/VlcTop.cpp index ccaec527e..de5160c2d 100644 --- a/src/VlcTop.cpp +++ b/src/VlcTop.cpp @@ -240,7 +240,7 @@ void VlcTop::writeInfo(const string& filename) { // FNF: // FNH: // Branches: - // BRDA:,,, + // BRDA:,,, // BRF: // BRH: // Line counts: @@ -273,8 +273,14 @@ void VlcTop::writeInfo(const string& filename) { for (const VlcPoint* point : infoPoints) { os << "BRDA:" << sc.lineno() << ","; os << "0,"; - os << point_num << ","; - os << point->count() << "\n"; + if (point->comment().empty()) { + os << point_num; + } else { + std::string comment(point->comment()); + std::replace(comment.begin(), comment.end(), ',', '_'); + os << comment; + } + os << "," << point->count() << "\n"; branchesHit += opt.countOk(point->count()); ++point_num; diff --git a/src/verilog.y b/src/verilog.y index 6d6efea6b..db145ea8e 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -7339,8 +7339,29 @@ cross_itemList: // IEEE: part of list_of_cross_items ; cross_item: // ==IEEE: cross_item - id/*cover_point_identifier*/ - { $$ = new AstCoverpointRef{$1, *$1}; } + // // IEEE: cover_point_identifier | variable_identifier - both are a + // // simple identifier. We parse idDotted (a plain hierarchical + // // reference a.b.c, with no bit/array selects) to also accept the + // // non-standard dotted form (e.g. 'cross a.b') that several + // // simulators support; the common simple-identifier case is detected + // // and handled exactly as before. + idDotted + { + if (AstParseRef* const refp = VN_CAST($1, ParseRef)) { + // Standard: simple cover_point_identifier / variable_identifier + $$ = new AstCoverpointRef{refp->fileline(), refp->name()}; + VL_DO_DANGLING(refp->deleteTree(), refp); + } else { + // Verilator extension beyond strict IEEE (cross_item is a simple + // identifier): some tools accept a hierarchical/dotted reference. + // Carry the reference expression (still an AstDot here) out of the + // parser unchanged; later stages resolve and, eventually, implement + // it as an implicit coverpoint. + $1->v3warn(NONSTD, "Non-standard hierarchical reference as a coverage " + "cross item (an implicit coverpoint)"); + $$ = new AstCoverpointRef{$1->fileline(), $1}; + } + } ; cross_body: // ==IEEE: cross_body diff --git a/test_regress/t/t_array_packed_sysfunct.v b/test_regress/t/t_array_packed_sysfunct.v index e31d38929..c380fa898 100644 --- a/test_regress/t/t_array_packed_sysfunct.v +++ b/test_regress/t/t_array_packed_sysfunct.v @@ -33,9 +33,7 @@ module t ( initial begin `checkh($dimensions (array_unpk), 3); -`ifndef VCS `checkh($unpacked_dimensions (array_unpk), 2); // IEEE 2009 -`endif `checkh($bits (array_unpk), 2*2*2); `checkh($low (array_unpk), 2); `checkh($high (array_unpk), 3); diff --git a/test_regress/t/t_assert_always_unbounded.v b/test_regress/t/t_assert_always_unbounded.v index 9f41a2627..f408c5885 100644 --- a/test_regress/t/t_assert_always_unbounded.v +++ b/test_regress/t/t_assert_always_unbounded.v @@ -35,7 +35,7 @@ module t ( assert property (@(posedge clk) always [2:$] a_low) else low2_fail_q.push_back(cyc); // a_drop is high then drops at cyc 5 and stays low: deterministic single - // transition, so Verilator and Questa agree on the failing ticks exactly. + // transition, so Verilator and others agree on the failing ticks exactly. assert property (@(posedge clk) always [2:$] a_drop) else drop_fail_q.push_back(cyc); always @(posedge clk) begin @@ -43,12 +43,12 @@ module t ( if (cyc >= 4) a_drop <= 1'b0; if (cyc == 19) begin // Counts pinned to Verilator (NFA per-cycle reject). For all-fail windows - // Questa is one lower (it does not fire the end-of-sim tick); see the sva + // others are one lower (it does not fire the end-of-sim tick); see the sva // lessons "multi-cycle end-of-simulation offset" note. - `checkd(high_fail_q.size(), 0); // Questa: 0 - `checkd(low0_fail_q.size(), 20); // Questa: 19 - `checkd(low2_fail_q.size(), 18); // Questa: 17 - `checkd(drop_fail_q[0], 5); // first fail tick: a_drop sampled low from cyc 5 + `checkd(high_fail_q.size(), 0); + `checkd(low0_fail_q.size(), 20); // All others: 19 + `checkd(low2_fail_q.size(), 18); // All others: 17 + `checkd(drop_fail_q[0], 5); // All others: 6; first fail tick: a_drop sampled low from cyc 5 $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_assert_bang_in_seq.v b/test_regress/t/t_assert_bang_in_seq.v index b0c831229..784dd338a 100644 --- a/test_regress/t/t_assert_bang_in_seq.v +++ b/test_regress/t/t_assert_bang_in_seq.v @@ -66,12 +66,12 @@ module t ( end else if (cyc == 99) begin `checkh(crc, 64'hc77bb9b3784ea091); - `checkd(count_fail1, 66); // Questa: 66 - `checkd(count_fail2, 69); // Questa: 69 - `checkd(count_fail3, 26); // Questa: 26 - `checkd(count_fail4, 66); // Questa: 66 - `checkd(count_fail5, 80); // Questa: 80 - `checkd(count_fail6, 27); // Questa: 27 + `checkd(count_fail1, 66); + `checkd(count_fail2, 69); + `checkd(count_fail3, 26); + `checkd(count_fail4, 66); + `checkd(count_fail5, 80); + `checkd(count_fail6, 27); $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_assert_consec_rep.v b/test_regress/t/t_assert_consec_rep.v index 8a4d87040..206b49886 100644 --- a/test_regress/t/t_assert_consec_rep.v +++ b/test_regress/t/t_assert_consec_rep.v @@ -95,23 +95,23 @@ module t ( end else if (cyc == 99) begin `checkh(crc, 64'hc77bb9b3784ea091); - `checkd(count_fail1, 5); // Questa: 5 - `checkd(count_fail2, 25); // Questa: 25 - `checkd(count_fail3, 9); // Questa: 9 - `checkd(count_fail4, 49); // Questa: 49 - `checkd(count_fail5, 0); // Questa: 0 - // NFA merge-node range [*M:N] over-counts rejects (Questa: 51); match + `checkd(count_fail1, 5); + `checkd(count_fail2, 25); // One other sim: 19 + `checkd(count_fail3, 9); + `checkd(count_fail4, 49); + `checkd(count_fail5, 0); + // NFA merge-node range [*M:N] over-counts rejects; match // detection is correct, only reject counting is imprecise - `checkd(count_fail6, 59); - `checkd(count_fail7, 51); // Questa: 51 - `checkd(count_fail8, 20); // Questa: 20 + `checkd(count_fail6, 59); // All other sims: 51 + `checkd(count_fail7, 51); + `checkd(count_fail8, 20); // IEEE 1800-2023 16.9.2 permits empty match of [*0]; NFA reports - // rejects on each tick while Questa suppresses (Questa: 20) - `checkd(count_fail9, 49); - `checkd(count_fail10, 59); // Questa: 59 + // rejects on each tick while others suppress + `checkd(count_fail9, 49); // Most others: 20, one other 49 + `checkd(count_fail10, 59); // a[*] ##1 b: NFA treats unbounded [*] as liveness (no reject); - // Questa treats as definite antecedent (Questa: 29) - `checkd(count_fail11, 0); + // Should be definite antecedent + `checkd(count_fail11, 0); // All other sims: 29 $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_assert_consec_rep_large.v b/test_regress/t/t_assert_consec_rep_large.v index 359537ce7..4df36f7bc 100644 --- a/test_regress/t/t_assert_consec_rep_large.v +++ b/test_regress/t/t_assert_consec_rep_large.v @@ -40,8 +40,8 @@ module t ( else if (cyc == 99) begin `checkh(crc, 64'hc77bb9b3784ea091); `checkd(count_fail_257, 0); - // Questa: 31 -- pre-existing ~26.5% NFA reject gap on |-> ##1 [*N] - `checkd(count_fail_513, 23); + // Mismatch due to pre-existing ~26.5% NFA reject gap on |-> ##1 [*N] + `checkd(count_fail_513, 23); // All other sims: 31 $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_assert_ctl_lock.v b/test_regress/t/t_assert_ctl_lock.v index 59c98a006..c47e3b341 100644 --- a/test_regress/t/t_assert_ctl_lock.v +++ b/test_regress/t/t_assert_ctl_lock.v @@ -5,6 +5,8 @@ // SPDX-License-Identifier: CC0-1.0 // verilog_format: off +`define stop $stop +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); `ifdef verilator `define no_optimize(v) $c(v) `else @@ -12,7 +14,7 @@ `endif // verilog_format: on -module t ( /*AUTOARG*/); +module t; logic clk = 0; int imm_fails = 0, conc_fails = 0; logic a = 1'b1; // antecedent always true @@ -58,11 +60,8 @@ module t ( /*AUTOARG*/); end final begin - // Concrete counts cross-checked against Questa 2022.3: imm_fails=5 conc_fails=7. - if (imm_fails != 5 || conc_fails != 7) begin - $display("%%Error: imm_fails=%0d (exp 5) conc_fails=%0d (exp 7)", imm_fails, conc_fails); - $stop; - end + `checkd(imm_fails, 5); + `checkd(conc_fails, 7); // Other sims: 7 or 1 $write("*-* All Finished *-*\n"); end endmodule diff --git a/test_regress/t/t_assert_ctl_pass_actions.v b/test_regress/t/t_assert_ctl_pass_actions.v index 3768f4bd1..3a7065569 100644 --- a/test_regress/t/t_assert_ctl_pass_actions.v +++ b/test_regress/t/t_assert_ctl_pass_actions.v @@ -36,7 +36,8 @@ interface AssertCtlIface; $assertcontrol(3, 2, 1); endfunction function void fail_check(); - assert (0) `stop; else fails++; + assert (0) `stop; + else fails++; endfunction function void run_checks(); assert_off(); @@ -69,12 +70,13 @@ module t; $assertcontrol(3, 2, 1); endfunction function void fail_check(); - assert (0) `stop; else class_fails++; + assert (0) `stop; + else class_fails++; endfunction endclass AssertCtlClass assert_ctl_class; - AssertCtlIface assert_ctl_iface(); + AssertCtlIface assert_ctl_iface (); virtual AssertCtlIface v_assert_ctl_iface = assert_ctl_iface; always #5 clk = !clk; @@ -84,17 +86,17 @@ module t; assert property (@(posedge clk) 1'b0 |-> ##1 1'b1) begin vacuous_passes++; - end else - `stop; + end + else `stop; assert property (@(posedge clk) 1'b1 |-> ##1 1'b1) begin nonvacuous_passes++; - end else - `stop; + end + else `stop; assert property (@(posedge clk) 1'b1 |-> ##1 1'b0) begin - end else - concurrent_fails++; + end + else concurrent_fails++; task automatic tick_and_check(input int exp_vacuous, input int exp_nonvacuous, input int exp_concurrent_fails); @@ -110,62 +112,73 @@ module t; $assertcontrol(4, 16, 1); $assertcontrol(5, 16, 1); - $assertcontrol(3*`IMPURE_ONE, 2*`IMPURE_ONE); + $assertcontrol(3 * `IMPURE_ONE, 2 * `IMPURE_ONE); $assertcontrol(3, 255, 7); $assertcontrol(6, 255, 7); $assertcontrol(8, 255, 7); - assert (1) imm_passes++; else `stop; + assert (1) imm_passes++; + else `stop; `checkd(imm_passes, 1); $assertcontrol(1, 2, 1); $assertcontrol(4, 2, 1); - assert (1) imm_passes++; else `stop; + assert (1) imm_passes++; + else `stop; `checkd(imm_passes, 2); $assertcontrol(2, 2, 1); $assertcontrol(4, 2, 1); - assert (1) imm_passes++; else `stop; + assert (1) imm_passes++; + else `stop; `checkd(imm_passes, 2); $assertcontrol(3, 2, 1); $assertcontrol(1, 2, 1); $assertcontrol(7, 2, 1); - assert (1) imm_passes++; else `stop; + assert (1) imm_passes++; + else `stop; `checkd(imm_passes, 3); $assertcontrol(2, 2, 1); $assertcontrol(7, 2, 1); - assert (1) imm_passes++; else `stop; + assert (1) imm_passes++; + else `stop; `checkd(imm_passes, 3); $assertcontrol(10, 2, 1); - assert (1) imm_passes++; else `stop; + assert (1) imm_passes++; + else `stop; `checkd(imm_passes, 4); $assertcontrol(11, 2, 1); - assert (1) imm_passes++; else `stop; + assert (1) imm_passes++; + else `stop; `checkd(imm_passes, 5); $assertcontrol(6, 2, 1); - assert (0) `stop; else imm_fails++; + assert (0) `stop; + else imm_fails++; `checkd(imm_fails, 1); $assertcontrol(1, 2, 1); $assertcontrol(9, 2, 1); - assert (0) `stop; else imm_fails++; + assert (0) `stop; + else imm_fails++; `checkd(imm_fails, 2); $assertcontrol(2, 2, 1); $assertcontrol(9, 2, 1); - assert (0) `stop; else imm_fails++; + assert (0) `stop; + else imm_fails++; `checkd(imm_fails, 2); $assertcontrol(8, 2, 1); - assert (0) `stop; else imm_fails++; + assert (0) `stop; + else imm_fails++; `checkd(imm_fails, 3); assert_ctl_class.assert_off(); diff --git a/test_regress/t/t_assert_ctl_type_runtime_bad.v b/test_regress/t/t_assert_ctl_type_runtime_bad.v index d35421daf..ab48ce35f 100644 --- a/test_regress/t/t_assert_ctl_type_runtime_bad.v +++ b/test_regress/t/t_assert_ctl_type_runtime_bad.v @@ -14,7 +14,7 @@ module t; initial begin - $assertcontrol(100*`IMPURE_ONE); + $assertcontrol(100 * `IMPURE_ONE); $finish; end endmodule diff --git a/test_regress/t/t_assert_disabled.v b/test_regress/t/t_assert_disabled.v index 447253c68..b09690d85 100644 --- a/test_regress/t/t_assert_disabled.v +++ b/test_regress/t/t_assert_disabled.v @@ -16,10 +16,8 @@ module t ( integer action_hits = 0; integer cyc = 0; - assert property (@(posedge clk) ##1 1'b1) - action_hits++; - else - action_hits--; + assert property (@(posedge clk) ##1 1'b1) action_hits++; + else action_hits--; always @(posedge clk) begin cyc++; diff --git a/test_regress/t/t_assert_goto_rep.v b/test_regress/t/t_assert_goto_rep.v index f926a3b5b..1a209444b 100644 --- a/test_regress/t/t_assert_goto_rep.v +++ b/test_regress/t/t_assert_goto_rep.v @@ -75,14 +75,14 @@ module t ( end else if (cyc == 99) begin `checkh(crc, 64'hc77bb9b3784ea091); - `checkd(count_fail1, 20); // Questa: 20 - `checkd(count_fail2, 25); // Questa: 25 - `checkd(count_fail3, 19); // Questa: 19 - `checkd(count_fail4, 0); // Questa: 0 - `checkd(count_fail5, 20); // Questa: 20 - `checkd(count_fail6, 25); // Questa: 25 - `checkd(count_fail7, 20); // Questa: 20 - `checkd(count_fail8, 20); // Questa: 20 + `checkd(count_fail1, 20); + `checkd(count_fail2, 25); + `checkd(count_fail3, 19); + `checkd(count_fail4, 0); + `checkd(count_fail5, 20); + `checkd(count_fail6, 25); + `checkd(count_fail7, 20); + `checkd(count_fail8, 20); $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_assert_nonconsec_rep.v b/test_regress/t/t_assert_nonconsec_rep.v index 6d759b9c2..c69db8bf9 100644 --- a/test_regress/t/t_assert_nonconsec_rep.v +++ b/test_regress/t/t_assert_nonconsec_rep.v @@ -56,10 +56,10 @@ module t ( end else if (cyc == 99) begin `checkh(crc, 64'hc77bb9b3784ea091); - `checkd(count_fail1, 34); // Questa: 29 - `checkd(count_fail2, 27); // Questa: 32 - `checkd(count_fail3, 25); // Questa: 29 - `checkd(count_fail4, 0); // Questa: 0 + `checkd(count_fail1, 34); // Other sims: 29, one other: 20 + `checkd(count_fail2, 27); // Other sims: 32, one other: 25 + `checkd(count_fail3, 25); // Other sims: 29, one other: 25 + `checkd(count_fail4, 0); $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_assert_opt_check.py b/test_regress/t/t_assert_opt_check.py index 62b5a95d0..0e970d46e 100755 --- a/test_regress/t/t_assert_opt_check.py +++ b/test_regress/t/t_assert_opt_check.py @@ -15,7 +15,7 @@ test.compile(verilator_flags2=['--binary', '--stats']) test.execute(check_finished=True) -test.file_grep(test.stats, r'Assertions, assertOn checks combined\s+(\d+)', 3) -test.file_grep(test.stats, r'Assertions, assertOn checks hoisted\s+(\d+)', 16) +test.file_grep(test.stats, r'Assertions, assertOn checks combined\s+(\d+)', 4) +test.file_grep(test.stats, r'Assertions, assertOn checks hoisted\s+(\d+)', 42) test.passes() diff --git a/test_regress/t/t_assert_procedural_gated.v b/test_regress/t/t_assert_procedural_gated.v index 9ed88121f..56e38ed41 100644 --- a/test_regress/t/t_assert_procedural_gated.v +++ b/test_regress/t/t_assert_procedural_gated.v @@ -57,9 +57,8 @@ module t ( end else if (cyc == 99) begin `checkh(crc, 64'hc77bb9b3784ea091); - // Questa 2022.3 golden: count_gated=5, count_ref=12. - `checkd(count_gated, 5); - `checkd(count_ref, 12); + `checkd(count_gated, 5); // Other sims same, one other: 4 + `checkd(count_ref, 12); // Other sims same, one other: 10 $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_assert_seq_clocking.v b/test_regress/t/t_assert_seq_clocking.v index b835acb85..9c59d7287 100644 --- a/test_regress/t/t_assert_seq_clocking.v +++ b/test_regress/t/t_assert_seq_clocking.v @@ -44,10 +44,9 @@ module t ( end // Counts read in final (Postponed) to avoid same-timestep races. - // Concrete Verilator counts; Questa: fails_single=17 fails_multi=17 final begin - `checkd(fails_single, 17); - `checkd(fails_multi, 17); + `checkd(fails_single, 17); // Other sims: 0 + `checkd(fails_multi, 17); // Other sims: 0 $write("*-* All Finished *-*\n"); end endmodule diff --git a/test_regress/t/t_assert_seq_clocking_unsup.out b/test_regress/t/t_assert_seq_clocking_unsup.out index 5ab9bb741..ba12d4ad2 100644 --- a/test_regress/t/t_assert_seq_clocking_unsup.out +++ b/test_regress/t/t_assert_seq_clocking_unsup.out @@ -15,16 +15,20 @@ : ... note: In instance 't' 27 | @clk a | ^ -%Error-UNSUPPORTED: t/t_assert_seq_clocking_unsup.v:32:3: Unsupported: Unclocked assertion - : ... note: In instance 't' +%Error: t/t_assert_seq_clocking_unsup.v:32:3: Concurrent assertion has no clock (IEEE 1800-2023 16.16) + : ... note: In instance 't' + : ... Suggest provide a clocking event, a default clocking, or a clocked procedural context 32 | assert property (s_nest ##1 a); | ^~~~~~ -%Error-UNSUPPORTED: t/t_assert_seq_clocking_unsup.v:33:3: Unsupported: Unclocked assertion - : ... note: In instance 't' + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: t/t_assert_seq_clocking_unsup.v:33:3: Concurrent assertion has no clock (IEEE 1800-2023 16.16) + : ... note: In instance 't' + : ... Suggest provide a clocking event, a default clocking, or a clocked procedural context 33 | assert property (s_level); | ^~~~~~ -%Error-UNSUPPORTED: t/t_assert_seq_clocking_unsup.v:34:3: Unsupported: Unclocked assertion - : ... note: In instance 't' +%Error: t/t_assert_seq_clocking_unsup.v:34:3: Concurrent assertion has no clock (IEEE 1800-2023 16.16) + : ... note: In instance 't' + : ... Suggest provide a clocking event, a default clocking, or a clocked procedural context 34 | assert property (s_level2); | ^~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_assert_unclocked_bad.out b/test_regress/t/t_assert_unclocked_bad.out new file mode 100644 index 000000000..60590a943 --- /dev/null +++ b/test_regress/t/t_assert_unclocked_bad.out @@ -0,0 +1,22 @@ +%Error: t/t_assert_unclocked_bad.v:9:3: Concurrent assertion has no clock (IEEE 1800-2023 16.16) + : ... note: In instance 't' + : ... Suggest provide a clocking event, a default clocking, or a clocked procedural context + 9 | assert property (a); + | ^~~~~~ + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: t/t_assert_unclocked_bad.v:10:22: Concurrent assertion has no clock (IEEE 1800-2023 16.16) + : ... note: In instance 't' + : ... Suggest provide a clocking event, a default clocking, or a clocked procedural context + 10 | assert property (a |=> b); + | ^~~ +%Error: t/t_assert_unclocked_bad.v:10:3: Concurrent assertion has no clock (IEEE 1800-2023 16.16) + : ... note: In instance 't' + : ... Suggest provide a clocking event, a default clocking, or a clocked procedural context + 10 | assert property (a |=> b); + | ^~~~~~ +%Error: t/t_assert_unclocked_bad.v:11:3: Concurrent assertion has no clock (IEEE 1800-2023 16.16) + : ... note: In instance 't' + : ... Suggest provide a clocking event, a default clocking, or a clocked procedural context + 11 | cover property (a); + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_assert_unclocked_bad.py b/test_regress/t/t_assert_unclocked_bad.py new file mode 100755 index 000000000..77a0ac64b --- /dev/null +++ b/test_regress/t/t_assert_unclocked_bad.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('vlt') + +test.lint(expect_filename=test.golden_filename, fails=True) + +test.passes() diff --git a/test_regress/t/t_assert_unclocked_bad.v b/test_regress/t/t_assert_unclocked_bad.v new file mode 100644 index 000000000..ae659cf7b --- /dev/null +++ b/test_regress/t/t_assert_unclocked_bad.v @@ -0,0 +1,12 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 PlanV GmbH +// SPDX-License-Identifier: CC0-1.0 + +module t; + logic a, b; + assert property (a); + assert property (a |=> b); + cover property (a); +endmodule diff --git a/test_regress/t/t_assertcontrol.v b/test_regress/t/t_assertcontrol.v index 26f9d360b..5088aa280 100644 --- a/test_regress/t/t_assertcontrol.v +++ b/test_regress/t/t_assertcontrol.v @@ -33,13 +33,12 @@ module t; task automatic run_pass(); assert (1) begin pass_count++; - end else - `stop; + end + else `stop; endtask task automatic run_fail(); - assert (0) - `stop; + assert (0) `stop; else begin fail_count++; end diff --git a/test_regress/t/t_bit_scan_loops.py b/test_regress/t/t_bit_scan_loops.py new file mode 100755 index 000000000..07b7818b1 --- /dev/null +++ b/test_regress/t/t_bit_scan_loops.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('vlt') + +# --unroll-count 0 so the loops are recognized without relying on unrolling. +test.compile(verilator_flags2=['--stats', '--unroll-count', '0']) + +# The leading-one positives lower to $mostsetbitp1, the count-ones positive to +# $countones; the negatives are left as loops (a wrong lowering would raise a count). +test.file_grep(test.stats, + r'Optimizations, Loop unrolling, Lowered priority-encoder to mostsetbitp1\s+(\d+)', + 8) +test.file_grep(test.stats, + r'Optimizations, Loop unrolling, Lowered count-set-bits to countones\s+(\d+)', 1) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_bit_scan_loops.v b/test_regress/t/t_bit_scan_loops.v new file mode 100644 index 000000000..fa2c1df00 --- /dev/null +++ b/test_regress/t/t_bit_scan_loops.v @@ -0,0 +1,169 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Exercises the bit-counting loop idioms that V3Unroll lowers to builtins: +// leading-one for (b=0;b $mostsetbitp1(vec) +// count-ones for (b=0;b $countones(vec) +// Positives must lower (counted via --stats by the .py); negatives compute a +// different value than the builtin and so must be left as loops. +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Wilson Snyder +// SPDX-License-Identifier: CC0-1.0 + +// verilog_format: off +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0); +// verilog_format: on + +module t ( + input clk +); + + // ---- positives: must lower ---- + logic [31:0] p32; + logic [5:0] n32; // I path, narrow target (select resize) + logic [47:0] p48; + logic [6:0] n48; // Q path + logic [79:0] p80; + logic [6:0] n80; // W path + logic [31:0] pu; + logic [5:0] nu; // unsigned loop index + logic [31:0] p32e; + logic [31:0] n32e; // 32-bit target (no resize) + logic [31:0] p32w; + logic [39:0] n40; // >32-bit target (extend resize) + logic [31:0] pc; + logic [5:0] nc; // count-ones -> $countones + logic [31:0] kvec; // const (set in initial) -> exercises $mostsetbitp1 fold + logic [5:0] kn; + initial kvec = 32'h0000_0100; + logic [31:0] kvec0; // const 0 -> $mostsetbitp1(0)=0 (covers the zero path) + logic [5:0] kn0; + initial kvec0 = 32'h0; + always_comb begin + n32 = 0; + for (int b = 0; b < 32; b++) if (p32[b]) n32 = 6'(b + 1); + end + always_comb begin + n48 = 0; + for (int b = 0; b < 48; b++) if (p48[b]) n48 = 7'(b + 1); + end + always_comb begin + n80 = 0; + for (int b = 0; b < 80; b++) if (p80[b]) n80 = 7'(b + 1); + end + always_comb begin + nu = 0; + for (int unsigned b = 0; b < 32; b++) if (pu[b]) nu = 6'(b + 1); + end + always_comb begin + n32e = 0; + for (int b = 0; b < 32; b++) if (p32e[b]) n32e = 32'(b + 1); + end + always_comb begin + n40 = 0; + for (int b = 0; b < 32; b++) if (p32w[b]) n40 = 40'(b + 1); + end + always_comb begin + nc = 0; + for (int b = 0; b < 32; b++) if (pc[b]) nc = nc + 1; + end + always_comb begin + kn = 0; + for (int b = 0; b < 32; b++) if (kvec[b]) kn = 6'(b + 1); + end + always_comb begin + kn0 = 0; + for (int b = 0; b < 32; b++) if (kvec0[b]) kn0 = 6'(b + 1); + end + + // ---- negatives: must NOT lower (each yields a different value than the builtin) ---- + logic [31:0] vn; // shared input, bits {2,4,5,7} + logic [31:0] vw; // has a set bit above the scan bound + logic [31:0] vt; // for the truncated-index case + logic en1; // runtime gate for the compound-condition case + logic [5:0] e_step2; + logic [6:0] e_start1; + logic [6:0] e_mul; + logic [5:0] e_off; + logic [5:0] e_noP1; + logic [5:0] e_narrow; + logic [5:0] e_comp; + logic [5:0] e_trunc; + always_comb begin + e_step2 = 0; + for (int b = 0; b < 32; b += 2) if (vn[b]) e_step2 = 6'(b + 1); + end + always_comb begin + e_start1 = 0; + for (int b = 1; b < 32; b++) if (vn[b]) e_start1 = 7'(b + 1); + end + always_comb begin + e_mul = 0; + for (int b = 0; b < 32; b++) if (vn[b]) e_mul = 7'(2 * b + 1); + end + always_comb begin + e_off = 0; + for (int b = 0; b < 31; b++) if (vn[b+1]) e_off = 6'(b + 1); + end + always_comb begin + e_noP1 = 0; + for (int b = 0; b < 32; b++) if (vn[b]) e_noP1 = 6'(b); + end + always_comb begin + e_narrow = 0; + for (int b = 0; b < 16; b++) if (vw[b]) e_narrow = 6'(b + 1); + end + always_comb begin + e_comp = 0; + for (int b = 0; b < 32; b++) if (vn[b] && en1) e_comp = 6'(b + 1); + end + // verilator lint_off WIDTHEXPAND + always_comb begin + e_trunc = 0; + for (int b = 0; b < 32; b++) if (vt[b[2:0]]) e_trunc = 6'(b + 1); + end + // verilator lint_on WIDTHEXPAND + + int cyc = 0; + always @(posedge clk) begin + cyc <= cyc + 1; + if (cyc == 0) begin + p32 <= 32'h8000_0000; + p48 <= 48'h0; + p48[47] <= 1'b1; + p80 <= 80'h0; + p80[79] <= 1'b1; + pu <= 32'h0001_0000; // bit 16 + p32e <= 32'h8000_0000; + p32w <= 32'h8000_0000; + pc <= 32'hf0f0_f0f0; // 16 ones + vn <= 32'h0000_00b4; // bits {2,4,5,7} + vw <= 32'h0010_0008; // bits {3,20} + vt <= 32'h0000_0080; // bit 7 + en1 <= 1'b0; // gate off -> compound loop yields 0 + end + else if (cyc == 1) begin + `checkh(n32, 6'd32); + `checkh(n48, 7'd48); + `checkh(n80, 7'd80); + `checkh(nu, 6'd17); // unsigned-index leading-one, bit 16 -> 17 + `checkh(n32e, 32'd32); + `checkh(n40, 40'd32); + `checkh(nc, 6'd16); // popcount(0xF0F0F0F0) + `checkh(kn, 6'd9); // mostsetbitp1(0x100), constant-folded + `checkh(kn0, 6'd0); // mostsetbitp1(0)=0, constant-folded (zero path) + // negatives, hand-computed for vn = 0xB4 (bits 2,4,5,7): + `checkh(e_step2, 6'd5); // highest even set bit (4) + 1 + `checkh(e_start1, 7'd8); // highest set bit in [1,32) (7) + 1 + `checkh(e_mul, 7'd15); // 2*7 + 1 + `checkh(e_off, 6'd7); // idx where vec[idx+1]; highest 6 -> 7 + `checkh(e_noP1, 6'd7); // highest set bit (7), no +1 + `checkh(e_narrow, 6'd4); // W=16 != width(vec): only low bits scanned (bit 3) + `checkh(e_comp, 6'd0); // && en1 (=0); a wrong lowering would give 8 + `checkh(e_trunc, 6'd32); // vt[b[2:0]] last hits b=31; a wrong lowering would give 8 + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_bit_scan_loops_off.py b/test_regress/t/t_bit_scan_loops_off.py new file mode 100755 index 000000000..cdf34ea55 --- /dev/null +++ b/test_regress/t/t_bit_scan_loops_off.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('vlt') + +# Reuse the same design; only the optimization switch differs. +test.top_filename = "t/t_bit_scan_loops.v" + +test.compile(verilator_flags2=['--stats', '--unroll-count', '0', '-fno-bit-scan-loops']) + +# With the optimization disabled, nothing lowers. +test.file_grep(test.stats, r'Lowered priority-encoder to mostsetbitp1\s+([0-9])', 0) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_bit_scan_loops_xassign0.py b/test_regress/t/t_bit_scan_loops_xassign0.py new file mode 100755 index 000000000..b44c2cdf7 --- /dev/null +++ b/test_regress/t/t_bit_scan_loops_xassign0.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('vlt') + +# Reuse the same design. '--x-assign 0' makes the auto-inserted out-of-range guard on a +# non-power-of-two bit-select a plain '(idx <= W-1) && vec[idx]' (AstLogAnd), rather than +# the ternary '(idx <= W-1) ? vec[idx] : ' (AstCond) produced under the driver's default +# '--x-assign unique'. This exercises the matcher's other guard-peel branch. +test.top_filename = "t/t_bit_scan_loops.v" + +test.compile(verilator_flags2=['--stats', '--unroll-count', '0', '--x-assign', '0']) + +# Same lowering counts as the default run -- only the guard shape differs, not the result. +test.file_grep(test.stats, + r'Optimizations, Loop unrolling, Lowered priority-encoder to mostsetbitp1\s+(\d+)', + 8) +test.file_grep(test.stats, + r'Optimizations, Loop unrolling, Lowered count-set-bits to countones\s+(\d+)', 1) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_case_call_count.py b/test_regress/t/t_case_call_count.py index df91d0e3c..bf14a54dd 100755 --- a/test_regress/t/t_case_call_count.py +++ b/test_regress/t/t_case_call_count.py @@ -15,6 +15,7 @@ test.compile(verilator_flags2=['--stats']) test.execute() -test.file_grep(test.stats, r'LiftExpr, lifted calls\s+(\d+)', 3) +test.file_grep(test.stats, r'LiftExpr, lifted calls\s+(\d+)', 2) +test.file_grep(test.stats, r'Assertions, lifted impure case expressions\s+(\d+)', 2) test.passes() diff --git a/test_regress/t/t_case_inside_call_count.py b/test_regress/t/t_case_inside_call_count.py index df91d0e3c..bf14a54dd 100755 --- a/test_regress/t/t_case_inside_call_count.py +++ b/test_regress/t/t_case_inside_call_count.py @@ -15,6 +15,7 @@ test.compile(verilator_flags2=['--stats']) test.execute() -test.file_grep(test.stats, r'LiftExpr, lifted calls\s+(\d+)', 3) +test.file_grep(test.stats, r'LiftExpr, lifted calls\s+(\d+)', 2) +test.file_grep(test.stats, r'Assertions, lifted impure case expressions\s+(\d+)', 2) test.passes() diff --git a/test_regress/t/t_class_cpp_overload.py b/test_regress/t/t_class_cpp_overload.py new file mode 100755 index 000000000..0f1f5d0a0 --- /dev/null +++ b/test_regress/t/t_class_cpp_overload.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('vlt') + +test.compile(verilator_flags2=['--binary', '-Wno-WIDTHTRUNC']) + +test.passes() diff --git a/test_regress/t/t_class_cpp_overload.v b/test_regress/t/t_class_cpp_overload.v new file mode 100644 index 000000000..02f67f60f --- /dev/null +++ b/test_regress/t/t_class_cpp_overload.v @@ -0,0 +1,39 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Antmicro +// SPDX-License-Identifier: CC0-1.0 + +interface irq_if ( + input logic clk, + input logic resetn +); + logic irq; + logic te; + logic halted; + logic fault; + logic wfi; + clocking cb @(posedge clk); + default input #1step output #2ns; + output irq; + output te; + input halted; + input fault; + input wfi; + endclocking + modport DUT_IRQ_PORT(input clk, resetn, output halted, fault, wfi); +endinterface +class base_test_class; + function int foo(); + endfunction + virtual irq_if.DUT_IRQ_PORT irq_vif; + function new(string name); + endfunction + virtual function void build_phase(); + if (irq_vif == null) begin + if (foo()) $display(); + end + endfunction +endclass +module tb_top; +endmodule diff --git a/test_regress/t/t_property_pexpr_unsup.py b/test_regress/t/t_class_extends_param_scope.py similarity index 71% rename from test_regress/t/t_property_pexpr_unsup.py rename to test_regress/t/t_class_extends_param_scope.py index 9768aebfc..3cc73805c 100755 --- a/test_regress/t/t_property_pexpr_unsup.py +++ b/test_regress/t/t_class_extends_param_scope.py @@ -9,10 +9,10 @@ import vltest_bootstrap -test.scenarios('vlt') +test.scenarios('simulator') -test.compile(expect_filename=test.golden_filename, - verilator_flags2=['--timing', '--error-limit 1000'], - fails=test.vlt_all) +test.compile() + +test.execute() test.passes() diff --git a/test_regress/t/t_class_extends_param_scope.v b/test_regress/t/t_class_extends_param_scope.v new file mode 100644 index 000000000..d60ac9381 --- /dev/null +++ b/test_regress/t/t_class_extends_param_scope.v @@ -0,0 +1,47 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Sergey Chusov +// SPDX-License-Identifier: CC0-1.0 + +// A factory-like static method, as used by UVM's type_id::create(). +class registry #(type T = int); + static function T create(); + T r = new; + return r; + endfunction +endclass + +class item; + int val; + typedef registry#(item) type_id; + function new(); + val = 42; + endfunction +endclass + +class seq_base #(type REQ = int, type RSP = REQ); + REQ req; +endclass + +// Non-parameterized class extending a parameterized base. +// REQ is a type parameter inherited from the (specialized) base class and is +// here used as a '::' class scope: REQ::type_id::create(). Resolving REQ in +// this position requires deferring until after V3Param has bound REQ to item. +class seq extends seq_base #(item); + function int make(); + REQ r; + r = REQ::type_id::create(); + return r.val; + endfunction +endclass + +module t; + seq s; + initial begin + s = new; + if (s.make() != 42) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_member_shadow_type.v b/test_regress/t/t_class_member_shadow_type.v index e0d11a0c7..3e56ba5cd 100644 --- a/test_regress/t/t_class_member_shadow_type.v +++ b/test_regress/t/t_class_member_shadow_type.v @@ -21,7 +21,7 @@ class C; endclass class D; - my_t a; // second use of the type name after the shadowing variable... + my_t a; // second use of the type name after the shadowing variable... my_t my_t; // ... is also legal; both resolve to the $unit typedef endclass diff --git a/test_regress/t/t_config_libmap_inc.py b/test_regress/t/t_config_libmap_inc.py index 10db367a5..bbe991e93 100755 --- a/test_regress/t/t_config_libmap_inc.py +++ b/test_regress/t/t_config_libmap_inc.py @@ -9,7 +9,6 @@ import vltest_bootstrap -test.scenarios('simulator') test.scenarios('linter') test.lint(verilator_flags2=["-libmap t/t_config_libmap_inc.map"], diff --git a/test_regress/t/t_constraint_dist_foreach_if.v b/test_regress/t/t_constraint_dist_foreach_if.v index 3ae315711..5d6f1b2ec 100644 --- a/test_regress/t/t_constraint_dist_foreach_if.v +++ b/test_regress/t/t_constraint_dist_foreach_if.v @@ -8,17 +8,21 @@ // values only within the declared distribution and cover all buckets. // verilog_format: off -`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); +`define stop $stop +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); // verilog_format: on // foreach (a[i]) if (gate) a[i] dist {...} class ClsIf; - rand bit [3:0] a [4]; + rand bit [3:0] a[4]; bit gate; constraint c { foreach (a[i]) { if (gate == 1'b1) { - a[i] dist { 4'd0 := 3, [4'd1:4'd4] := 1 }; + a[i] dist { + 4'd0 := 3, + [4'd1 : 4'd4] := 1 + }; } } } @@ -26,22 +30,30 @@ endclass // foreach (a[i]) gate -> a[i] dist {...} class ClsImpl; - rand bit [3:0] a [4]; + rand bit [3:0] a[4]; bit gate; constraint c { foreach (a[i]) { - gate -> (a[i] dist { 4'd0 := 3, [4'd1:4'd4] := 1 }); + gate -> + (a[i] dist { + 4'd0 := 3, + [4'd1 : 4'd4] := 1 + }); } } endclass // foreach (a[i]) gateA -> (gateB -> a[i] dist {...}) -- doubly-nested implication class ClsImplChained; - rand bit [3:0] a [4]; + rand bit [3:0] a[4]; bit gateA, gateB; constraint c { foreach (a[i]) { - gateA -> (gateB -> (a[i] dist { 4'd0 := 3, [4'd1:4'd4] := 1 })); + gateA -> + (gateB -> (a[i] dist { + 4'd0 := 3, + [4'd1 : 4'd4] := 1 + })); } } endclass @@ -59,8 +71,8 @@ module t; `checkd(obj.randomize(), 1) foreach (obj.a[i]) begin if (obj.a[i] > 4) begin - $write("%%Error: %s:%0d: if: value out of dist range: %0d\n", - `__FILE__, `__LINE__, obj.a[i]); + $write("%%Error: %s:%0d: if: value out of dist range: %0d\n", `__FILE__, `__LINE__, + obj.a[i]); $stop; end if (obj.a[i] == 0) seen_zero++; @@ -68,8 +80,9 @@ module t; end end if (seen_zero == 0 || seen_nonzero == 0) begin - $write("%%Error: %s:%0d: dist inside foreach+if: not all buckets hit (zero=%0d nonzero=%0d)\n", - `__FILE__, `__LINE__, seen_zero, seen_nonzero); + $write( + "%%Error: %s:%0d: dist inside foreach+if: not all buckets hit (zero=%0d nonzero=%0d)\n", + `__FILE__, `__LINE__, seen_zero, seen_nonzero); $stop; end end @@ -85,8 +98,8 @@ module t; `checkd(obj.randomize(), 1) foreach (obj.a[i]) begin if (obj.a[i] > 4) begin - $write("%%Error: %s:%0d: ->: value out of dist range: %0d\n", - `__FILE__, `__LINE__, obj.a[i]); + $write("%%Error: %s:%0d: ->: value out of dist range: %0d\n", `__FILE__, `__LINE__, + obj.a[i]); $stop; end if (obj.a[i] == 0) seen_zero++; @@ -94,8 +107,9 @@ module t; end end if (seen_zero == 0 || seen_nonzero == 0) begin - $write("%%Error: %s:%0d: dist inside foreach+->: not all buckets hit (zero=%0d nonzero=%0d)\n", - `__FILE__, `__LINE__, seen_zero, seen_nonzero); + $write( + "%%Error: %s:%0d: dist inside foreach+->: not all buckets hit (zero=%0d nonzero=%0d)\n", + `__FILE__, `__LINE__, seen_zero, seen_nonzero); $stop; end end @@ -112,8 +126,8 @@ module t; `checkd(obj.randomize(), 1) foreach (obj.a[i]) begin if (obj.a[i] > 4) begin - $write("%%Error: %s:%0d: ->->: value out of dist range: %0d\n", - `__FILE__, `__LINE__, obj.a[i]); + $write("%%Error: %s:%0d: ->->: value out of dist range: %0d\n", `__FILE__, `__LINE__, + obj.a[i]); $stop; end if (obj.a[i] == 0) seen_zero++; @@ -121,8 +135,9 @@ module t; end end if (seen_zero == 0 || seen_nonzero == 0) begin - $write("%%Error: %s:%0d: dist inside foreach+->->: not all buckets hit (zero=%0d nonzero=%0d)\n", - `__FILE__, `__LINE__, seen_zero, seen_nonzero); + $write( + "%%Error: %s:%0d: dist inside foreach+->->: not all buckets hit (zero=%0d nonzero=%0d)\n", + `__FILE__, `__LINE__, seen_zero, seen_nonzero); $stop; end end diff --git a/test_regress/t/t_constraint_dist_range.v b/test_regress/t/t_constraint_dist_range.v index fbddaf0a1..88ffe3e0b 100644 --- a/test_regress/t/t_constraint_dist_range.v +++ b/test_regress/t/t_constraint_dist_range.v @@ -14,13 +14,20 @@ // Scalar: uniform over [0:9] (10% each) class DistScalarRange; rand bit [3:0] x; - constraint c { x dist {[4'd0:4'd9] := 1}; } + constraint c { + x dist { + [4'd0 : 4'd9] := 1 + }; + } endclass // Array foreach: uniform over [0:4] (20% each per element) class DistForeachUniform; rand bit [2:0] a[5]; - constraint c { foreach (a[i]) a[i] dist {[3'd0:3'd4] := 1}; } + constraint c { + foreach (a[i]) + a[i] dist {[3'd0 : 3'd4] := 1}; + } endclass // Array foreach: mixed single + range @@ -28,32 +35,50 @@ endclass // 0: 5/14 ~= 35.7%, 1..9: 1/14 ~= 7.1% each class DistForeachMixed; rand bit [3:0] a[5]; - constraint c { foreach (a[i]) a[i] dist {4'd0 := 5, [4'd1:4'd9] := 1}; } + constraint c { + foreach (a[i]) + a[i] dist { + 4'd0 := 5, + [4'd1 : 4'd9] := 1 + }; + } endclass // Scalar signed int: uniform over negative range [-9:0] (10% each) class DistNegRange; rand int x; - constraint c { x dist {[-9:0] := 1}; } + constraint c { + x dist { + [-9 : 0] := 1 + }; + } endclass // Non-constant unsigned range bounds: uniform over [lo_val:hi_val] = [2:7] (6 values) class DistVarRangeUnsigned; rand bit [3:0] x; bit [3:0] lo_val = 4'd2, hi_val = 4'd7; - constraint c { x dist {[lo_val:hi_val] := 1}; } + constraint c { + x dist { + [lo_val : hi_val] := 1 + }; + } endclass // Mixed const/non-const bounds: lo is constant, hi is a variable [1:hi_val] = [1:7] class DistMixedBounds; rand bit [3:0] x; bit [3:0] hi_val = 4'd7; - constraint c { x dist {[4'd1:hi_val] := 1}; } + constraint c { + x dist { + [4'd1 : hi_val] := 1 + }; + } endclass module t; - parameter int N = 2000; // randomize() calls per test - parameter int TOL_PCT = 30; // +-% tolerance on expected counts + parameter int N = 2000; // randomize() calls per test + parameter int TOL_PCT = 30; // +-% tolerance on expected counts initial begin @@ -71,8 +96,7 @@ module t; end cnt[obj.x]++; end - foreach (cnt[v]) - `check_tol(cnt[v], N/10) + foreach (cnt[v]) `check_tol(cnt[v], N / 10) end // --- T2: array foreach uniform [0:4], 5 elements * N calls --- @@ -91,8 +115,7 @@ module t; cnt[obj.a[i]]++; end end - foreach (cnt[v]) - `check_tol(cnt[v], N) + foreach (cnt[v]) `check_tol(cnt[v], N) end // --- T3: array foreach mixed {0:=5, [1:9]:=1}, 5 elements * N calls --- @@ -113,9 +136,8 @@ module t; cnt[obj.a[i]]++; end end - `check_tol(cnt[0], N*5*5/14) - for (int v = 1; v <= 9; v++) - `check_tol(cnt[v], N*5*1/14) + `check_tol(cnt[0], N * 5 * 5 / 14) + for (int v = 1; v <= 9; v++) `check_tol(cnt[v], N * 5 * 1 / 14) end // --- T4: signed int, uniform over negative range [-9:0] --- @@ -131,10 +153,9 @@ module t; $write("%%Error: x=%0d outside valid range [-9:0]\n", obj.x); `stop; end - cnt[obj.x + 9]++; + cnt[obj.x+9]++; end - foreach (cnt[v]) - `check_tol(cnt[v], N/10) + foreach (cnt[v]) `check_tol(cnt[v], N / 10) end // --- T5: non-constant unsigned range bounds [lo_val:hi_val] = [2:7] --- @@ -151,8 +172,7 @@ module t; end cnt[obj.x]++; end - for (int v = 2; v <= 7; v++) - `check_tol(cnt[v], N/6) + for (int v = 2; v <= 7; v++) `check_tol(cnt[v], N / 6) end // --- T6: mixed const/non-const bounds [4'd1:hi_val] = [1:7] --- @@ -169,8 +189,7 @@ module t; end cnt[obj.x]++; end - for (int v = 1; v <= 7; v++) - `check_tol(cnt[v], N/7) + for (int v = 1; v <= 7; v++) `check_tol(cnt[v], N / 7) end $write("*-* All Finished *-*\n"); diff --git a/test_regress/t/t_constraint_global_subobj.py b/test_regress/t/t_constraint_global_subobj.py new file mode 100755 index 000000000..db1adb3f9 --- /dev/null +++ b/test_regress/t/t_constraint_global_subobj.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +if not test.have_solver: + test.skip("No constraint solver installed") + +test.compile() + +test.execute() + +test.passes() diff --git a/test_regress/t/t_constraint_global_subobj.v b/test_regress/t/t_constraint_global_subobj.v new file mode 100644 index 000000000..333695f2d --- /dev/null +++ b/test_regress/t/t_constraint_global_subobj.v @@ -0,0 +1,178 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 PlanV GmbH +// SPDX-License-Identifier: CC0-1.0 + +// Scenario 1 (issue #7833 literal): owner SA1 declares a global constraint on a +// sub-object's type but is NEVER randomized; a standalone randomize() of the +// holder must still randomize the nested fields. +class C1; + rand int x; + rand int y; +endclass + +class B1; + rand C1 c; + function new(); + c = new(); + endfunction +endclass + +class SA1; + rand B1 b; + constraint c_foo {b.c.x == 123;} +endclass + +// Scenario 2 (combined): the SAME design randomizes both the constraint owner +// and a standalone holder of the constrained type. +class C2; + rand int x; + rand int y; +endclass + +class B2; + rand C2 c; + function new(); + c = new(); + endfunction +endclass + +class SA2; + rand B2 b; + constraint c_foo {b.c.x == 123;} + function new(); + b = new(); + endfunction +endclass + +// Scenario 3 (multiple same-type sub-objects): two sub-objects of one type are +// each pinned by a global constraint while that type is also randomized +// standalone; the two share one underlying rand variable. +class C3; + rand int x; +endclass + +class M3; + rand C3 c1; + rand C3 c2; + constraint c { + c1.x == 11; + c2.x == 22; + } + function new(); + c1 = new(); + c2 = new(); + endfunction +endclass + +// Scenario 4 (global constraint owner with its own size-constrained array): the +// owner basic-randomizes first, the solver overrides last, and the size-only +// resize fallback still resizes from the solver-determined size. +class C4; + rand int x; +endclass + +class A4; + rand C4 c; + rand int arr[]; + constraint c_sub {c.x == 5;} + constraint c_size {arr.size() == 4;} + function new(); + c = new(); + endfunction +endclass + +module t_constraint_global_subobj; + B1 b1; + SA2 a2; + B2 b2; + M3 m3; + C3 s3; + A4 a4; + int prevx, prevy, p3; + bit varyx, varyy, vary3; + + initial begin + // Scenario 1: SA1 never randomized; standalone B1 must vary both fields. + b1 = new(); + varyx = 0; + varyy = 0; + if (b1.randomize() != 1) $stop; + prevx = b1.c.x; + prevy = b1.c.y; + for (int i = 0; i < 20; i++) begin + if (b1.randomize() != 1) $stop; + if (b1.c.x != prevx) varyx = 1; + if (b1.c.y != prevy) varyy = 1; + prevx = b1.c.x; + prevy = b1.c.y; + end + if (!varyx || !varyy) begin + $display("ERROR: standalone holder fields stuck (varyx=%0d varyy=%0d)", varyx, varyy); + $stop; + end + + // Scenario 2: randomize the owner (constraint applies) and a standalone + // holder (fields random) in the same design. + a2 = new(); + if (a2.randomize() != 1) $stop; + if (a2.b.c.x != 123) begin + $display("ERROR: owner constraint not applied, a2.b.c.x=%0d", a2.b.c.x); + $stop; + end + b2 = new(); + varyx = 0; + if (b2.randomize() != 1) $stop; + prevx = b2.c.x; + for (int i = 0; i < 20; i++) begin + if (b2.randomize() != 1) $stop; + if (b2.c.x != prevx) varyx = 1; + prevx = b2.c.x; + end + if (!varyx) begin + $display("ERROR: standalone holder x stuck while owner also randomized"); + $stop; + end + + // Scenario 3: two same-type sub-objects each pinned, plus standalone vary. + m3 = new(); + if (m3.randomize() != 1) $stop; + if (m3.c1.x != 11) begin + $display("ERROR: m3.c1.x should be 11, got %0d", m3.c1.x); + $stop; + end + if (m3.c2.x != 22) begin + $display("ERROR: m3.c2.x should be 22, got %0d", m3.c2.x); + $stop; + end + s3 = new(); + vary3 = 0; + if (s3.randomize() != 1) $stop; + p3 = s3.x; + for (int i = 0; i < 20; i++) begin + if (s3.randomize() != 1) $stop; + if (s3.x != p3) vary3 = 1; + p3 = s3.x; + end + if (!vary3) begin + $display("ERROR: standalone same-type x stuck"); + $stop; + end + + // Scenario 4: owner with a global constraint AND its own size constraint. + a4 = new(); + if (a4.randomize() != 1) $stop; + if (a4.c.x != 5) begin + $display("ERROR: a4.c.x should be 5, got %0d", a4.c.x); + $stop; + end + if (a4.arr.size() != 4) begin + $display("ERROR: a4.arr.size() should be 4, got %0d", a4.arr.size()); + $stop; + end + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_sequence_first_match_unsup.py b/test_regress/t/t_cover_expr_fork.py similarity index 74% rename from test_regress/t/t_sequence_first_match_unsup.py rename to test_regress/t/t_cover_expr_fork.py index 235ad76f1..57b6e30b1 100755 --- a/test_regress/t/t_sequence_first_match_unsup.py +++ b/test_regress/t/t_cover_expr_fork.py @@ -11,8 +11,8 @@ import vltest_bootstrap test.scenarios('simulator') -test.lint(expect_filename=test.golden_filename, - verilator_flags2=['--assert --error-limit 1000'], - fails=True) +test.compile(verilator_flags2=['--coverage-expr --binary']) + +test.execute(all_run_flags=[" +verilator+coverage+file+" + test.obj_dir + "/coverage.dat"]) test.passes() diff --git a/test_regress/t/t_cover_expr_fork.v b/test_regress/t/t_cover_expr_fork.v new file mode 100644 index 000000000..c111e5947 --- /dev/null +++ b/test_regress/t/t_cover_expr_fork.v @@ -0,0 +1,31 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain +// SPDX-FileCopyrightText: 2026 Antmicro +// SPDX-License-Identifier: CC0-1.0 + +module t; + int cnt = 0; + task automatic myTask; + fork + begin + bit x; + if (!x) begin + cnt++; + end + if (!$onehot(x)) begin + cnt++; + end + end + join_none + endtask + + initial begin + myTask(); + #1; + if (cnt != 2) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_cover_fsm_if_unknown_enum_multi_bad.out b/test_regress/t/t_cover_fsm_if_unknown_enum_multi_bad.out index 7416b7aa4..8cf3712f6 100644 --- a/test_regress/t/t_cover_fsm_if_unknown_enum_multi_bad.out +++ b/test_regress/t/t_cover_fsm_if_unknown_enum_multi_bad.out @@ -1,33 +1,33 @@ -%Warning-COVERIGN: t/t_cover_fsm_if_unknown_enum_multi_bad.v:26:19: Ignoring unsupported: FSM coverage on enum state variable 't.unknown_then_u.state_q': assigned value 3 is not present in the declared enum - 26 | S0: state_d = sel ? 2'd3 : S1; +%Warning-COVERIGN: t/t_cover_fsm_if_unknown_enum_multi_bad.v:274:19: Ignoring unsupported: FSM coverage on enum state variable 't.unknown_wide_direct_u.state_q': assigned value 40'hffffffffff is not present in the declared enum + 274 | S0: state_d = 40'hffff_ffff_ff; | ^ ... For warning description see https://verilator.org/warn/COVERIGN?v=latest ... Use "/* verilator lint_off COVERIGN */" and lint_on around source to disable this message. -%Warning-COVERIGN: t/t_cover_fsm_if_unknown_enum_multi_bad.v:53:19: Ignoring unsupported: FSM coverage on enum state variable 't.unknown_else_u.state_q': assigned value 3 is not present in the declared enum - 53 | S0: state_d = sel ? S1 : 2'd3; - | ^ -%Warning-COVERIGN: t/t_cover_fsm_if_unknown_enum_multi_bad.v:79:19: Ignoring unsupported: FSM coverage on enum state variable 't.unknown_direct_u.state_q': assigned value 3 is not present in the declared enum - 79 | S0: state_d = 2'd3; - | ^ -%Warning-COVERIGN: t/t_cover_fsm_if_unknown_enum_multi_bad.v:126:15: Ignoring unsupported: FSM coverage on enum state variable 't.unknown_reset_u.state_q': assigned value 3 is not present in the declared enum - 126 | state_q <= 2'd3; - | ^~ -%Warning-COVERIGN: t/t_cover_fsm_if_unknown_enum_multi_bad.v:150:7: Ignoring unsupported: FSM coverage on enum state variable 't.unknown_source_u.state_q': case item value 3 is not present in the declared enum - 150 | 2'd3: state_d = S0; - | ^~~~ -%Warning-COVERIGN: t/t_cover_fsm_if_unknown_enum_multi_bad.v:175:5: Ignoring unsupported: FSM coverage on enum state variable 't.unknown_if_source_u.state_q': case item value 3 is not present in the declared enum - 175 | if (state_q == 2'd3) state_d = S0; - | ^~ -%Warning-COVERIGN: t/t_cover_fsm_if_unknown_enum_multi_bad.v:199:32: Ignoring unsupported: FSM coverage on enum state variable 't.unknown_if_direct_target_u.state_q': assigned value 3 is not present in the declared enum - 199 | if (state_q == S0) state_d = 2'd3; +%Warning-COVERIGN: t/t_cover_fsm_if_unknown_enum_multi_bad.v:249:32: Ignoring unsupported: FSM coverage on enum state variable 't.unknown_if_else_target_u.state_q': assigned value 3 is not present in the declared enum + 249 | if (state_q == S0) state_d = sel ? S1 : 2'd3; | ^ %Warning-COVERIGN: t/t_cover_fsm_if_unknown_enum_multi_bad.v:224:32: Ignoring unsupported: FSM coverage on enum state variable 't.unknown_if_then_target_u.state_q': assigned value 3 is not present in the declared enum 224 | if (state_q == S0) state_d = sel ? 2'd3 : S1; | ^ -%Warning-COVERIGN: t/t_cover_fsm_if_unknown_enum_multi_bad.v:249:32: Ignoring unsupported: FSM coverage on enum state variable 't.unknown_if_else_target_u.state_q': assigned value 3 is not present in the declared enum - 249 | if (state_q == S0) state_d = sel ? S1 : 2'd3; +%Warning-COVERIGN: t/t_cover_fsm_if_unknown_enum_multi_bad.v:199:32: Ignoring unsupported: FSM coverage on enum state variable 't.unknown_if_direct_target_u.state_q': assigned value 3 is not present in the declared enum + 199 | if (state_q == S0) state_d = 2'd3; | ^ -%Warning-COVERIGN: t/t_cover_fsm_if_unknown_enum_multi_bad.v:274:19: Ignoring unsupported: FSM coverage on enum state variable 't.unknown_wide_direct_u.state_q': assigned value 40'hffffffffff is not present in the declared enum - 274 | S0: state_d = 40'hffff_ffff_ff; +%Warning-COVERIGN: t/t_cover_fsm_if_unknown_enum_multi_bad.v:175:5: Ignoring unsupported: FSM coverage on enum state variable 't.unknown_if_source_u.state_q': case item value 3 is not present in the declared enum + 175 | if (state_q == 2'd3) state_d = S0; + | ^~ +%Warning-COVERIGN: t/t_cover_fsm_if_unknown_enum_multi_bad.v:150:7: Ignoring unsupported: FSM coverage on enum state variable 't.unknown_source_u.state_q': case item value 3 is not present in the declared enum + 150 | 2'd3: state_d = S0; + | ^~~~ +%Warning-COVERIGN: t/t_cover_fsm_if_unknown_enum_multi_bad.v:126:15: Ignoring unsupported: FSM coverage on enum state variable 't.unknown_reset_u.state_q': assigned value 3 is not present in the declared enum + 126 | state_q <= 2'd3; + | ^~ +%Warning-COVERIGN: t/t_cover_fsm_if_unknown_enum_multi_bad.v:79:19: Ignoring unsupported: FSM coverage on enum state variable 't.unknown_direct_u.state_q': assigned value 3 is not present in the declared enum + 79 | S0: state_d = 2'd3; + | ^ +%Warning-COVERIGN: t/t_cover_fsm_if_unknown_enum_multi_bad.v:53:19: Ignoring unsupported: FSM coverage on enum state variable 't.unknown_else_u.state_q': assigned value 3 is not present in the declared enum + 53 | S0: state_d = sel ? S1 : 2'd3; + | ^ +%Warning-COVERIGN: t/t_cover_fsm_if_unknown_enum_multi_bad.v:26:19: Ignoring unsupported: FSM coverage on enum state variable 't.unknown_then_u.state_q': assigned value 3 is not present in the declared enum + 26 | S0: state_d = sel ? 2'd3 : S1; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_cover_fsm_plain_always_warn_multi_bad.out b/test_regress/t/t_cover_fsm_plain_always_warn_multi_bad.out index 064ef2ff1..976c00e07 100644 --- a/test_regress/t/t_cover_fsm_plain_always_warn_multi_bad.out +++ b/test_regress/t/t_cover_fsm_plain_always_warn_multi_bad.out @@ -1,12 +1,12 @@ -%Warning-COVERIGN: t/t_cover_fsm_plain_always_warn_multi_bad.v:25:5: Ignoring unsupported: FSM coverage on non-clocked always blocks requires a combinational sensitivity list or always_comb - 25 | case (state_q) +%Warning-COVERIGN: t/t_cover_fsm_plain_always_warn_multi_bad.v:86:5: Ignoring unsupported: FSM coverage on non-clocked always blocks requires a combinational sensitivity list or always_comb + 86 | case (state_q) | ^~~~ ... For warning description see https://verilator.org/warn/COVERIGN?v=latest ... Use "/* verilator lint_off COVERIGN */" and lint_on around source to disable this message. %Warning-COVERIGN: t/t_cover_fsm_plain_always_warn_multi_bad.v:55:5: Ignoring unsupported: FSM coverage on non-clocked always blocks requires a combinational sensitivity list or always_comb 55 | case (state_d) | ^~~~ -%Warning-COVERIGN: t/t_cover_fsm_plain_always_warn_multi_bad.v:86:5: Ignoring unsupported: FSM coverage on non-clocked always blocks requires a combinational sensitivity list or always_comb - 86 | case (state_q) +%Warning-COVERIGN: t/t_cover_fsm_plain_always_warn_multi_bad.v:25:5: Ignoring unsupported: FSM coverage on non-clocked always blocks requires a combinational sensitivity list or always_comb + 25 | case (state_q) | ^~~~ %Error: Exiting due to diff --git a/test_regress/t/t_cover_line_cc.info.out b/test_regress/t/t_cover_line_cc.info.out index 6a04c28bf..fbba38865 100644 --- a/test_regress/t/t_cover_line_cc.info.out +++ b/test_regress/t/t_cover_line_cc.info.out @@ -4,32 +4,32 @@ DA:15,1 DA:18,1 DA:55,10 DA:56,10 -BRDA:56,0,0,10 -BRDA:56,0,1,0 +BRDA:56,0,if,10 +BRDA:56,0,else,0 DA:57,10 DA:58,10 DA:60,9 -BRDA:60,0,0,1 -BRDA:60,0,1,9 +BRDA:60,0,if,1 +BRDA:60,0,else,9 DA:61,9 -BRDA:61,0,0,1 -BRDA:61,0,1,9 +BRDA:61,0,if,1 +BRDA:61,0,else,9 DA:62,1 DA:63,1 DA:66,9 -BRDA:66,0,0,1 -BRDA:66,0,1,9 +BRDA:66,0,if,1 +BRDA:66,0,else,9 DA:67,9 -BRDA:67,0,0,1 -BRDA:67,0,1,9 +BRDA:67,0,if,1 +BRDA:67,0,else,9 DA:69,9 DA:70,9 DA:73,9 -BRDA:73,0,0,1 -BRDA:73,0,1,9 +BRDA:73,0,if,1 +BRDA:73,0,else,9 DA:74,9 -BRDA:74,0,0,1 -BRDA:74,0,1,9 +BRDA:74,0,if,1 +BRDA:74,0,else,9 DA:75,1 DA:76,1 DA:79,9 @@ -41,8 +41,8 @@ DA:87,1 DA:88,1 DA:89,1 DA:91,7 -BRDA:91,0,0,1 -BRDA:91,0,1,7 +BRDA:91,0,if,1 +BRDA:91,0,else,7 DA:92,1 DA:93,1 DA:96,7 @@ -52,67 +52,67 @@ DA:101,0 DA:102,0 DA:104,0 DA:105,10 -BRDA:105,0,0,0 -BRDA:105,0,1,10 +BRDA:105,0,block,0 +BRDA:105,0,block,10 DA:106,10 DA:107,10 -BRDA:107,0,0,0 -BRDA:107,0,1,10 +BRDA:107,0,block,0 +BRDA:107,0,block,10 DA:110,1 DA:111,1 DA:113,1 DA:115,1 DA:120,7 -BRDA:120,0,0,1 -BRDA:120,0,1,7 +BRDA:120,0,if,1 +BRDA:120,0,else,7 DA:121,1 DA:122,1 DA:127,1 DA:129,1 DA:140,20 DA:141,18 -BRDA:141,0,0,2 -BRDA:141,0,1,18 +BRDA:141,0,if,2 +BRDA:141,0,else,18 DA:142,2 DA:145,18 DA:164,20 DA:165,20 DA:166,20 -BRDA:166,0,0,0 -BRDA:166,0,1,20 +BRDA:166,0,if,0 +BRDA:166,0,else,20 DA:168,0 DA:170,18 -BRDA:170,0,0,2 -BRDA:170,0,1,18 +BRDA:170,0,if,2 +BRDA:170,0,else,18 DA:172,2 DA:174,18 DA:188,11 DA:189,11 DA:190,11 -BRDA:190,0,0,11 -BRDA:190,0,1,0 +BRDA:190,0,if,11 +BRDA:190,0,else,0 DA:191,11 DA:194,11 DA:195,11 -BRDA:195,0,0,11 -BRDA:195,0,1,0 +BRDA:195,0,if,11 +BRDA:195,0,else,0 DA:196,11 DA:199,11 DA:200,11 -BRDA:200,0,0,11 -BRDA:200,0,1,0 +BRDA:200,0,if,11 +BRDA:200,0,else,0 DA:201,11 DA:215,10 DA:216,10 DA:219,11 DA:221,11 DA:222,10 -BRDA:222,0,0,1 -BRDA:222,0,1,10 +BRDA:222,0,if,1 +BRDA:222,0,else,10 DA:223,1 DA:225,10 -BRDA:225,0,0,1 -BRDA:225,0,1,10 +BRDA:225,0,if,1 +BRDA:225,0,else,10 DA:226,1 DA:229,11 DA:230,11 @@ -121,12 +121,12 @@ DA:232,11 DA:233,11 DA:253,10 DA:254,9 -BRDA:254,0,0,1 -BRDA:254,0,1,9 +BRDA:254,0,if,1 +BRDA:254,0,else,9 DA:256,1 DA:257,1 -BRDA:257,0,0,0 -BRDA:257,0,1,1 +BRDA:257,0,if,0 +BRDA:257,0,else,1 DA:266,10 DA:267,10 DA:268,1 @@ -139,8 +139,8 @@ DA:277,10 DA:278,10 DA:288,0 DA:289,0 -BRDA:289,0,0,0 -BRDA:289,0,1,0 +BRDA:289,0,if,0 +BRDA:289,0,else,0 DA:290,0 DA:292,0 DA:293,0 @@ -157,66 +157,66 @@ DA:328,10 DA:329,10 DA:330,10 DA:333,31 -BRDA:333,0,0,0 -BRDA:333,0,1,31 +BRDA:333,0,cond_then,0 +BRDA:333,0,cond_else,31 DA:334,28 -BRDA:334,0,0,3 -BRDA:334,0,1,28 +BRDA:334,0,cond_then,3 +BRDA:334,0,cond_else,28 DA:335,1 -BRDA:335,0,0,1 -BRDA:335,0,1,0 +BRDA:335,0,cond_then,1 +BRDA:335,0,cond_else,0 DA:336,10 DA:337,10 -BRDA:337,0,0,10 -BRDA:337,0,1,3 -BRDA:337,0,2,7 +BRDA:337,0,block,10 +BRDA:337,0,cond_then,3 +BRDA:337,0,cond_else,7 DA:338,10 -BRDA:338,0,0,10 -BRDA:338,0,1,0 -BRDA:338,0,2,10 +BRDA:338,0,block,10 +BRDA:338,0,cond_then,0 +BRDA:338,0,cond_else,10 DA:340,19 -BRDA:340,0,0,12 -BRDA:340,0,1,19 -BRDA:340,0,2,7 -BRDA:340,0,3,5 +BRDA:340,0,cond_then,12 +BRDA:340,0,cond_else,19 +BRDA:340,0,cond_then,7 +BRDA:340,0,cond_else,5 DA:343,11 -BRDA:343,0,0,11 -BRDA:343,0,1,0 +BRDA:343,0,cond_then,11 +BRDA:343,0,cond_else,0 DA:349,22 -BRDA:349,0,0,20 -BRDA:349,0,1,22 +BRDA:349,0,cond_then,20 +BRDA:349,0,cond_else,22 DA:352,11 DA:353,10 -BRDA:353,0,0,0 -BRDA:353,0,1,1 -BRDA:353,0,2,1 -BRDA:353,0,3,10 +BRDA:353,0,cond_then,0 +BRDA:353,0,cond_else,1 +BRDA:353,0,if,1 +BRDA:353,0,else,10 DA:354,10 DA:356,11 -BRDA:356,0,0,11 -BRDA:356,0,1,1 -BRDA:356,0,2,10 +BRDA:356,0,block,11 +BRDA:356,0,cond_then,1 +BRDA:356,0,cond_else,10 DA:359,55 -BRDA:359,0,0,11 -BRDA:359,0,1,55 +BRDA:359,0,block,11 +BRDA:359,0,block,55 DA:360,55 DA:362,44 -BRDA:362,0,0,11 -BRDA:362,0,1,11 -BRDA:362,0,2,33 -BRDA:362,0,3,44 +BRDA:362,0,block,11 +BRDA:362,0,cond_then,11 +BRDA:362,0,cond_else,33 +BRDA:362,0,block,44 DA:363,44 DA:366,11 -BRDA:366,0,0,0 -BRDA:366,0,1,11 +BRDA:366,0,if,0 +BRDA:366,0,else,11 DA:367,11 DA:370,10 -BRDA:370,0,0,1 -BRDA:370,0,1,10 +BRDA:370,0,cond_then,1 +BRDA:370,0,cond_else,10 DA:373,10 DA:374,9 -BRDA:374,0,0,1 -BRDA:374,0,1,9 +BRDA:374,0,if,1 +BRDA:374,0,else,9 BRF:83 BRH:32 end_of_record diff --git a/test_regress/t/t_cover_property.v b/test_regress/t/t_cover_property.v index 40089451c..d68118d96 100644 --- a/test_regress/t/t_cover_property.v +++ b/test_regress/t/t_cover_property.v @@ -60,18 +60,17 @@ module t ( // A cover of an implication counts only non-vacuous matches (IEEE // 1800-2023 16.15.2): the antecedent must match. So it is identical to the // corresponding sequence cover, not the vacuous implication value. - `checkd(n_imp_no, n_seq) - `checkd(n_imp_ov, n_seq0) + `checkd(n_imp_no, n_seq); // Other sims: pass, 73 + `checkd(n_imp_ov, n_seq0); // Other sims: pass, 45 // A named-property cover lowers the same implication, so it also counts // non-vacuously (regression guard for the property-inlining path). - `checkd(n_named, n_imp_no) - // Pinned Verilator counts; Questa golden cross-checked. - `checkd(n_imp_no, 28) // Questa: 28 - `checkd(n_imp_ov, 27) // Questa: 27 - `checkd(n_seq, 28) // Questa: 28 - `checkd(n_seq0, 27) // Questa: 27 - `checkd(n_bool, 55) // Questa: 54 - `checkd(n_named, 28) // Questa: 28 + `checkd(n_named, n_imp_no); + `checkd(n_imp_no, 28); + `checkd(n_imp_ov, 27); // Other sims: pass, 73 + `checkd(n_seq, 28); // Other sims: 45, 27 + `checkd(n_seq0, 27); + `checkd(n_bool, 55); // Other sims: pass, 25 + `checkd(n_named, 28); // Other sims: 73, 54, 54 end endmodule diff --git a/test_regress/t/t_cover_sequence.v b/test_regress/t/t_cover_sequence.v index 719a3c1ba..79516a81c 100644 --- a/test_regress/t/t_cover_sequence.v +++ b/test_regress/t/t_cover_sequence.v @@ -69,22 +69,21 @@ module t ( // Read the counters in 'final', not the clocked block: a same-cycle read of a // cover counter races the cover's increment under --threads (vltmt). Verilator - // counts one more end-of-match than Questa 2022.3 on some forms at the - // simulation boundary; the Questa value is noted per check. + // counts one more end-of-match than others on some forms. final begin `ifdef TEST_VERBOSE $write("simple=%0d clocked=%0d clk_dis=%0d def_dis=%0d range=%0d 2=%0d 3=%0d\n", hit_simple, hit_clocked, hit_clocked_disable, hit_default_disable, hit_consrep_range, hit_consrep_2, hit_consrep_3); `endif - `checkd(hit_simple, 96); // Questa: 95 - `checkd(hit_clocked, 149); // Questa: 149 - `checkd(hit_clocked_disable, 28); // Questa: 27 - `checkd(hit_default_disable, 30); // Questa: 30 - `checkd(hit_consrep_2, 30); // Questa: 29 - `checkd(hit_consrep_3, 14); // Questa: 13 + `checkd(hit_simple, 96); // Other sims: 5, 95 + `checkd(hit_clocked, 149); + `checkd(hit_clocked_disable, 27); + `checkd(hit_default_disable, 30); + `checkd(hit_consrep_2, 30); // Other sims: 29 + `checkd(hit_consrep_3, 14); // Other sims: 13 // a[*2:3] == a[*2] or a[*3] (IEEE 1800-2023 16.9.2) - `checkd(hit_consrep_range, hit_consrep_2 + hit_consrep_3); // 44; Questa: 42 + `checkd(hit_consrep_range, hit_consrep_2 + hit_consrep_3); $write("*-* All Finished *-*\n"); end endmodule diff --git a/test_regress/t/t_cover_toggle_min.info.out b/test_regress/t/t_cover_toggle_min.info.out index 975b502e0..6cdc747be 100644 --- a/test_regress/t/t_cover_toggle_min.info.out +++ b/test_regress/t/t_cover_toggle_min.info.out @@ -1,20 +1,20 @@ TN:verilator_coverage SF:t/t_cover_toggle_min.v DA:10,1 -BRDA:10,0,0,1 -BRDA:10,0,1,0 -BRDA:10,0,2,0 -BRDA:10,0,3,0 +BRDA:10,0,a[0]:0->1,1 +BRDA:10,0,a[0]:1->0,0 +BRDA:10,0,a[1]:0->1,0 +BRDA:10,0,a[1]:1->0,0 DA:11,1 -BRDA:11,0,0,0 -BRDA:11,0,1,0 -BRDA:11,0,2,1 -BRDA:11,0,3,0 +BRDA:11,0,b[0]:0->1,0 +BRDA:11,0,b[0]:1->0,0 +BRDA:11,0,b[1]:0->1,1 +BRDA:11,0,b[1]:1->0,0 DA:12,1 -BRDA:12,0,0,1 -BRDA:12,0,1,1 -BRDA:12,0,2,1 -BRDA:12,0,3,0 +BRDA:12,0,c[0]:0->1,1 +BRDA:12,0,c[0]:1->0,1 +BRDA:12,0,c[1]:0->1,1 +BRDA:12,0,c[1]:1->0,0 BRF:12 BRH:0 end_of_record diff --git a/test_regress/t/t_covergroup_cross.out b/test_regress/t/t_covergroup_cross.out index a7311da80..abb035e5e 100644 --- a/test_regress/t/t_covergroup_cross.out +++ b/test_regress/t/t_covergroup_cross.out @@ -109,10 +109,10 @@ cg_range.cp_addr.hi_range: 2 cg_range.cp_addr.lo_range: 2 cg_range.cp_cmd.read: 2 cg_range.cp_cmd.write: 2 -cg_unnamed_cross.__cross7.a0_x_read [cross]: 1 -cg_unnamed_cross.__cross7.a0_x_write [cross]: 0 -cg_unnamed_cross.__cross7.a1_x_read [cross]: 0 -cg_unnamed_cross.__cross7.a1_x_write [cross]: 1 +cg_unnamed_cross.__cross8.a0_x_read [cross]: 1 +cg_unnamed_cross.__cross8.a0_x_write [cross]: 0 +cg_unnamed_cross.__cross8.a1_x_read [cross]: 0 +cg_unnamed_cross.__cross8.a1_x_write [cross]: 1 cg_unnamed_cross.cp_a.a0: 1 cg_unnamed_cross.cp_a.a1: 1 cg_unnamed_cross.cp_c.read: 1 diff --git a/test_regress/t/t_covergroup_cross.v b/test_regress/t/t_covergroup_cross.v index e86f179a4..f0857bc01 100644 --- a/test_regress/t/t_covergroup_cross.v +++ b/test_regress/t/t_covergroup_cross.v @@ -17,6 +17,9 @@ module t; logic mode; logic parity; + typedef struct packed {logic m_p; logic h_mode;} cfg_t; + cfg_t s_cfg = '0; + // 2-way cross covergroup cg2; cp_addr: coverpoint addr {bins addr0 = {0}; bins addr1 = {1};} @@ -90,6 +93,12 @@ module t; addr_cmd_unsup: cross cp_addr, cp_cmd{ option.per_instance = 1; // unsupported for cross - expect COVERIGN warning } + // Non-standard hierarchical reference as a cross item (an implicit coverpoint): + // accepted with NONSTD, but implicit coverpoints are unsupported so the whole + // cross is dropped (COVERIGN, suppressed here) - it contributes no bins. + /* verilator lint_off NONSTD */ + cross_hier: cross cp_addr, s_cfg.m_p; + /* verilator lint_on NONSTD */ endgroup // Covergroup with an unnamed cross - the cross is reported under the default name "cross" diff --git a/test_regress/t/t_sequence_intersect_len_warn.py b/test_regress/t/t_covergroup_cross_no_coverage.py similarity index 75% rename from test_regress/t/t_sequence_intersect_len_warn.py rename to test_regress/t/t_covergroup_cross_no_coverage.py index 58fc7aeba..699c061b8 100755 --- a/test_regress/t/t_sequence_intersect_len_warn.py +++ b/test_regress/t/t_covergroup_cross_no_coverage.py @@ -10,9 +10,11 @@ import vltest_bootstrap test.scenarios('vlt_all') +test.top_filename = 't/t_covergroup_cross.v' -test.compile(verilator_flags2=['--assert', '--timing', '--lint-only'], - fails=True, - expect_filename=test.golden_filename) +# runs without --coverage +test.compile(verilator_flags2=['--Wno-COVERIGN']) + +test.execute() test.passes() diff --git a/test_regress/t/t_covergroup_cross_opt_unsup.out b/test_regress/t/t_covergroup_cross_opt_unsup.out index d07db1513..e1e2c5621 100644 --- a/test_regress/t/t_covergroup_cross_opt_unsup.out +++ b/test_regress/t/t_covergroup_cross_opt_unsup.out @@ -1,3 +1,8 @@ +%Warning-NONSTD: t/t_covergroup_cross_opt_unsup.v:19:34: Non-standard hierarchical reference as a coverage cross item (an implicit coverpoint) + 19 | cross_hier: cross cp_a, s_cfg.m_p; + | ^ + ... For warning description see https://verilator.org/warn/NONSTD?v=latest + ... Use "/* verilator lint_off NONSTD */" and lint_on around source to disable this message. %Warning-COVERIGN: t/t_covergroup_cross_opt_unsup.v:13:7: Ignoring unsupported coverage cross option: 'per_instance' 13 | option.per_instance = 1; | ^~~~~~ @@ -7,4 +12,8 @@ : ... note: In instance 't' 15 | cross_implicit: cross cp_a, var_x; | ^~~~~ +%Warning-COVERIGN: t/t_covergroup_cross_opt_unsup.v:19:34: Unsupported: cross of hierarchical reference (implicit coverpoint) + : ... note: In instance 't' + 19 | cross_hier: cross cp_a, s_cfg.m_p; + | ^ %Error: Exiting due to diff --git a/test_regress/t/t_covergroup_cross_opt_unsup.v b/test_regress/t/t_covergroup_cross_opt_unsup.v index bb63a86be..720fbad6c 100644 --- a/test_regress/t/t_covergroup_cross_opt_unsup.v +++ b/test_regress/t/t_covergroup_cross_opt_unsup.v @@ -13,7 +13,13 @@ module t; option.per_instance = 1; // unsupported for cross; triggers COVERIGN } cross_implicit: cross cp_a, var_x; + // Non-standard hierarchical/dotted cross item: can only be a data reference + // (implicit coverpoint), never a coverpoint. Accepted with a NONSTD warning; + // implicit coverpoints are unsupported so the cross is dropped (COVERIGN). + cross_hier: cross cp_a, s_cfg.m_p; endgroup + typedef struct packed {logic m_p; logic h_mode;} cfg_t; + cfg_t s_cfg = '0; logic var_x = 1'b0; cg cg_i = new; initial begin diff --git a/test_regress/t/t_covergroup_option_no_coverage.py b/test_regress/t/t_covergroup_option_no_coverage.py new file mode 100755 index 000000000..5f3bb6c6d --- /dev/null +++ b/test_regress/t/t_covergroup_option_no_coverage.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('vlt') +test.top_filename = 't/t_covergroup_option.v' + +# runs without --coverage +test.compile(verilator_flags2=['--Wno-COVERIGN']) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_cuse_struct_pkg.py b/test_regress/t/t_cuse_struct_pkg.py new file mode 100755 index 000000000..8a938befd --- /dev/null +++ b/test_regress/t/t_cuse_struct_pkg.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile() + +test.execute() + +test.passes() diff --git a/test_regress/t/t_cuse_struct_pkg.v b/test_regress/t/t_cuse_struct_pkg.v new file mode 100644 index 000000000..2ff97c8b2 --- /dev/null +++ b/test_regress/t/t_cuse_struct_pkg.v @@ -0,0 +1,72 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Wilson Snyder +// SPDX-License-Identifier: CC0-1.0 + +package pkg; + typedef struct {logic [7:0] value;} field_t; + typedef struct { + field_t f0; + field_t f1; + } reg_t; + typedef struct { + reg_t R0; + reg_t R1; + reg_t R2; + } hwif_t; +endpackage + +module t ( + input clk +); + + import pkg::*; + + hwif_t hwif_in; + hwif_t hwif_out; + hwif_t storage; + + integer cyc = 0; + + always_ff @(posedge clk) begin + storage.R0.f0.value <= hwif_in.R0.f0.value; + storage.R0.f1.value <= hwif_in.R0.f1.value; + storage.R1.f0.value <= hwif_in.R1.f0.value; + storage.R1.f1.value <= hwif_in.R1.f1.value; + storage.R2.f0.value <= hwif_in.R2.f0.value; + storage.R2.f1.value <= hwif_in.R2.f1.value; + end + + always_comb begin + hwif_out.R0.f0.value = storage.R0.f0.value; + hwif_out.R0.f1.value = storage.R0.f1.value; + hwif_out.R1.f0.value = storage.R1.f0.value; + hwif_out.R1.f1.value = storage.R1.f1.value; + hwif_out.R2.f0.value = storage.R2.f0.value; + hwif_out.R2.f1.value = storage.R2.f1.value; + end + + always @(posedge clk) begin + cyc <= cyc + 1; + if (cyc == 0) begin + hwif_in.R0.f0.value <= 8'h11; + hwif_in.R0.f1.value <= 8'h22; + hwif_in.R1.f0.value <= 8'h33; + hwif_in.R1.f1.value <= 8'h44; + hwif_in.R2.f0.value <= 8'h55; + hwif_in.R2.f1.value <= 8'h66; + end + else if (cyc == 3) begin + if (hwif_out.R0.f0.value !== 8'h11) $stop; + if (hwif_out.R0.f1.value !== 8'h22) $stop; + if (hwif_out.R1.f0.value !== 8'h33) $stop; + if (hwif_out.R1.f1.value !== 8'h44) $stop; + if (hwif_out.R2.f0.value !== 8'h55) $stop; + if (hwif_out.R2.f1.value !== 8'h66) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule diff --git a/test_regress/t/t_dfg_oob_array_access.py b/test_regress/t/t_dfg_oob_array_access.py new file mode 100755 index 000000000..b7bc5e342 --- /dev/null +++ b/test_regress/t/t_dfg_oob_array_access.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile(verilator_flags2=["-runtime-debug"]) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_dfg_oob_array_access.v b/test_regress/t/t_dfg_oob_array_access.v new file mode 100644 index 000000000..39b3f4d17 --- /dev/null +++ b/test_regress/t/t_dfg_oob_array_access.v @@ -0,0 +1,27 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Antmicro +// SPDX-License-Identifier: CC0-1.0 + + +module t ( + input clk +); + wire mem_wire; + bit [15:0] idx = 65535; + bit mem_reg[0:34000]; + assign mem_wire = mem_reg[idx]; + + always @(posedge clk) begin + if (idx < 65533) begin + $display("oob_val %d", mem_wire); + $write("*-* All Finished *-*\n"); + $finish; + end + else begin + idx <= idx - 1; + mem_reg[idx] <= 0; + end + end +endmodule diff --git a/test_regress/t/t_dpi_2exparg_bad.out b/test_regress/t/t_dpi_2exparg_bad.out index e908a6f57..812511578 100644 --- a/test_regress/t/t_dpi_2exparg_bad.out +++ b/test_regress/t/t_dpi_2exparg_bad.out @@ -10,12 +10,12 @@ | ^ ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. -%Error: t/t_dpi_2exparg_bad.v:21:8: Duplicate declaration of DPI function with different signature: 'dpix_twice' - 21 | task dpix_twice(input int i, output [63:0] o); - | ^~~~~~~~~~ - : ... New signature: void dpix_twice (int, svLogicVecVal* /* logic[63:0] */ ) - t/t_dpi_2exparg_bad.v:12:8: ... Original signature: void dpix_twice (int, svLogicVecVal* /* logic[2:0] */ ) +%Error: t/t_dpi_2exparg_bad.v:12:8: Duplicate declaration of DPI function with different signature: 'dpix_twice' 12 | task dpix_twice(input int i, output [2:0] o); + | ^~~~~~~~~~ + : ... New signature: void dpix_twice (int, svLogicVecVal* /* logic[2:0] */ ) + t/t_dpi_2exparg_bad.v:21:8: ... Original signature: void dpix_twice (int, svLogicVecVal* /* logic[63:0] */ ) + 21 | task dpix_twice(input int i, output [63:0] o); | ^~~~~~~~~~ ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. %Error: Exiting due to diff --git a/test_regress/t/t_flag_main_vpi.cpp b/test_regress/t/t_flag_main_vpi.cpp new file mode 100644 index 000000000..1be31452a --- /dev/null +++ b/test_regress/t/t_flag_main_vpi.cpp @@ -0,0 +1,94 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: VPI test library for t_flag_main_vpi +// +// Loaded at runtime via +verilator+vpi+ to verify that --binary --vpi +// correctly loads shared libraries and invokes vlog_startup_routines[] (or a +// named bootstrap). The design drives its own clock; this library only +// observes 'count' via a cbValueChange callback and calls $finish after +// MAX_TICKS edges -- so a successful $finish proves the library was loaded +// and is able to register callbacks and reach signals by name. +// +// 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-FileCopyrightText: 2025 Wilson Snyder +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* + +#include "vpi_user.h" + +#include +#include + +// Number of count increments to observe before calling $finish +static const int MAX_TICKS = 10; +static vpiHandle s_count_handle = nullptr; + +static PLI_INT32 count_change_cb(p_cb_data /*cb_data*/) { + if (!s_count_handle) return 0; + s_vpi_value val; + val.format = vpiIntVal; + vpi_get_value(s_count_handle, &val); + if (val.value.integer >= MAX_TICKS) { + vpi_printf(const_cast("*-* All Finished *-*\n")); + vpi_control(vpiFinish, 0); + } + return 0; +} + +static PLI_INT32 start_of_sim_cb(p_cb_data /*cb_data*/) { + s_count_handle = vpi_handle_by_name(const_cast("t.count"), nullptr); + if (!s_count_handle) { + vpi_printf(const_cast("ERROR: cannot find t.count\n")); + vpi_control(vpiFinish, 1); + return 0; + } + // Observe count: fire a callback whenever it changes + t_cb_data cb_data; + s_vpi_time t; + s_vpi_value val; + t.type = vpiSuppressTime; + val.format = vpiSuppressVal; + cb_data.reason = cbValueChange; + cb_data.cb_rtn = count_change_cb; + cb_data.obj = s_count_handle; + cb_data.time = &t; + cb_data.value = &val; + cb_data.user_data = nullptr; + vpi_register_cb(&cb_data); + return 0; +} + +static PLI_INT32 end_of_sim_cb(p_cb_data /*cb_data*/) { + vpi_printf(const_cast("VPI end of simulation\n")); + return 0; +} + +static void register_callbacks() { + // cbStartOfSimulation + t_cb_data cb_data; + s_vpi_time t; + t.type = vpiSuppressTime; + cb_data.reason = cbStartOfSimulation; + cb_data.cb_rtn = start_of_sim_cb; + cb_data.obj = nullptr; + cb_data.time = &t; + cb_data.value = nullptr; + cb_data.user_data = nullptr; + vpi_register_cb(&cb_data); + + // cbEndOfSimulation + cb_data.reason = cbEndOfSimulation; + cb_data.cb_rtn = end_of_sim_cb; + vpi_register_cb(&cb_data); +} + +// IEEE 1800 section 37: vlog_startup_routines[] -- null-terminated array of startup functions +extern "C" { +void (*vlog_startup_routines[])() = {register_callbacks, nullptr}; + +// Named bootstrap entrypoint -- used when library is loaded as :my_vpi_bootstrap +void my_vpi_bootstrap() { register_callbacks(); } +} diff --git a/test_regress/t/t_flag_main_vpi.out b/test_regress/t/t_flag_main_vpi.out new file mode 100644 index 000000000..6a9a7f37b --- /dev/null +++ b/test_regress/t/t_flag_main_vpi.out @@ -0,0 +1,2 @@ +*-* All Finished *-* +VPI end of simulation diff --git a/test_regress/t/t_flag_main_vpi.py b/test_regress/t/t_flag_main_vpi.py new file mode 100755 index 000000000..695b70e76 --- /dev/null +++ b/test_regress/t/t_flag_main_vpi.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2025 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('vlt') + +# Compile with --binary --vpi to exercise the VPI-aware generated main. +# Also compile a VPI shared library to be loaded at runtime via +verilator+vpi+. +test.compile(make_pli=True, verilator_flags2=["--binary --vpi --public-flat-rw"]) + +# Run the generated binary; load the VPI library via the +verilator+vpi+ plusarg. +# The VPI library's output (observed 'count' reaching MAX_TICKS, then end-of-sim) is +# checked against the golden .out file. +# Also pass a non-VPI plusarg (skipped by the loader's prefix check) and a bare +# +verilator+vpi+ with an empty payload (skipped by the empty-arg check), so both +# loader-skip branches are exercised alongside the real library load. +test.execute(all_run_flags=[ + "+othertest", "+verilator+vpi+", "+verilator+vpi+" + test.obj_dir + "/libvpi.so" +], + check_finished=True, + expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_flag_main_vpi.v b/test_regress/t/t_flag_main_vpi.v new file mode 100644 index 000000000..6ac03e26e --- /dev/null +++ b/test_regress/t/t_flag_main_vpi.v @@ -0,0 +1,28 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain +// SPDX-FileCopyrightText: 2025 Wilson Snyder +// SPDX-License-Identifier: CC0-1.0 + +// Test for --binary --vpi runtime library loading. The design provides its +// own clock (so the simulation has Verilog event activity); the VPI library +// (t_flag_main_vpi.cpp), loaded at runtime via +verilator+vpi+, observes +// 'count' via a cbValueChange callback and calls $finish after MAX_TICKS +// edges. Signals are public so the library can reach them by name +// (requires --public-flat-rw). +module t; + + reg clk /*verilator public_flat_rw*/; + reg [31:0] count /*verilator public_flat_rw*/; + + initial begin + clk = 0; + count = 0; + end + + // Self-driving clock: the design itself keeps the simulation alive + always #5 clk = ~clk; + + always @(posedge clk) count <= count + 1; + +endmodule diff --git a/test_regress/t/t_flag_main_vpi_badentry.out b/test_regress/t/t_flag_main_vpi_badentry.out new file mode 100644 index 000000000..6283fa03f --- /dev/null +++ b/test_regress/t/t_flag_main_vpi_badentry.out @@ -0,0 +1,2 @@ +%Error: Cannot find VPI bootstrap 'no_such_fn' in: obj_vlt/t_flag_main_vpi_badentry/libvpi.so +Aborting... diff --git a/test_regress/t/t_flag_main_vpi_badentry.py b/test_regress/t/t_flag_main_vpi_badentry.py new file mode 100755 index 000000000..15398a3e5 --- /dev/null +++ b/test_regress/t/t_flag_main_vpi_badentry.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2025 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('vlt') + +# A valid library loaded with a : entry that does not exist must +# fail with a clear error (the missing-named-bootstrap branch of the loader). +test.top_filename = 't/t_flag_main_vpi.v' +test.pli_filename = 't/t_flag_main_vpi.cpp' + +test.compile(make_pli=True, verilator_flags2=["--binary --vpi --public-flat-rw"]) + +test.execute(fails=True, + all_run_flags=["+verilator+vpi+" + test.obj_dir + "/libvpi.so:no_such_fn"], + expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_flag_main_vpi_badlib.out b/test_regress/t/t_flag_main_vpi_badlib.out new file mode 100644 index 000000000..752708e9e --- /dev/null +++ b/test_regress/t/t_flag_main_vpi_badlib.out @@ -0,0 +1,2 @@ +%Error: Cannot load VPI library: obj_vlt/t_flag_main_vpi_badlib/nonexistent.so +Aborting... diff --git a/test_regress/t/t_flag_main_vpi_badlib.py b/test_regress/t/t_flag_main_vpi_badlib.py new file mode 100755 index 000000000..2ac211d49 --- /dev/null +++ b/test_regress/t/t_flag_main_vpi_badlib.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2025 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('vlt') + +# +verilator+vpi+ pointing at a non-existent library must fail with a clear +# error (the dlopen-failure branch of the runtime loader). +test.top_filename = 't/t_flag_main_vpi.v' + +test.compile(verilator_flags2=["--binary --vpi --public-flat-rw"]) + +# The fatal names the (stable, relative) library path; the platform-specific dlerror() +# detail is emitted on a "- " line, which golden comparison strips, so the .out is portable. +test.execute(fails=True, + all_run_flags=["+verilator+vpi+" + test.obj_dir + "/nonexistent.so"], + expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_flag_main_vpi_bootstrap.out b/test_regress/t/t_flag_main_vpi_bootstrap.out new file mode 100644 index 000000000..6a9a7f37b --- /dev/null +++ b/test_regress/t/t_flag_main_vpi_bootstrap.out @@ -0,0 +1,2 @@ +*-* All Finished *-* +VPI end of simulation diff --git a/test_regress/t/t_flag_main_vpi_bootstrap.py b/test_regress/t/t_flag_main_vpi_bootstrap.py new file mode 100755 index 000000000..4c5c21e70 --- /dev/null +++ b/test_regress/t/t_flag_main_vpi_bootstrap.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2025 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('vlt') + +# Same design and VPI library as t_flag_main_vpi, but loaded via the +# +verilator+vpi+: named-bootstrap syntax instead of vlog_startup_routines[]. +test.top_filename = 't/t_flag_main_vpi.v' +test.pli_filename = 't/t_flag_main_vpi.cpp' + +test.compile(make_pli=True, verilator_flags2=["--binary --vpi --public-flat-rw"]) + +test.execute(all_run_flags=["+verilator+vpi+" + test.obj_dir + "/libvpi.so:my_vpi_bootstrap"], + check_finished=True, + expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_flag_main_vpi_lib2.cpp b/test_regress/t/t_flag_main_vpi_lib2.cpp new file mode 100644 index 000000000..8f5bba74b --- /dev/null +++ b/test_regress/t/t_flag_main_vpi_lib2.cpp @@ -0,0 +1,25 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Second VPI test library for t_flag_main_vpi_multi +// +// A second, independent VPI library loaded alongside t_flag_main_vpi.cpp via a +// repeated +verilator+vpi+ argument, to verify multiple libraries are loaded. +// Its startup routine prints a marker proving it was loaded; it does not drive +// or finish the simulation (the first library does that). +// +// 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-FileCopyrightText: 2025 Wilson Snyder +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* + +#include "vpi_user.h" + +static void lib2_startup() { vpi_printf(const_cast("second VPI library loaded\n")); } + +// IEEE 1800 section 37: vlog_startup_routines[] -- null-terminated array of startup functions +extern "C" { +void (*vlog_startup_routines[])() = {lib2_startup, nullptr}; +} diff --git a/test_regress/t/t_flag_main_vpi_multi.out b/test_regress/t/t_flag_main_vpi_multi.out new file mode 100644 index 000000000..04f3f5e6d --- /dev/null +++ b/test_regress/t/t_flag_main_vpi_multi.out @@ -0,0 +1,3 @@ +second VPI library loaded +*-* All Finished *-* +VPI end of simulation diff --git a/test_regress/t/t_flag_main_vpi_multi.py b/test_regress/t/t_flag_main_vpi_multi.py new file mode 100755 index 000000000..af3e301ee --- /dev/null +++ b/test_regress/t/t_flag_main_vpi_multi.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2025 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import os +import platform +import vltest_bootstrap + +test.scenarios('vlt') + +# Two +verilator+vpi+ arguments load two independent libraries: the first +# (t_flag_main_vpi.cpp) observes the design and calls $finish; the second +# (t_flag_main_vpi_lib2.cpp) prints a marker proving it too was loaded. +test.top_filename = 't/t_flag_main_vpi.v' +test.pli_filename = 't/t_flag_main_vpi.cpp' + +test.compile(make_pli=True, verilator_flags2=["--binary --vpi --public-flat-rw"]) + +# Build the second VPI library (make_pli only builds libvpi.so), mirroring the +# driver's own pli flags. +root = os.environ['VERILATOR_ROOT'] +pli2_cmd = [ + os.environ['CXX'], "-I" + root + "/include/vltstd", "-I" + root + "/include", "-fPIC", + "-shared" +] +pli2_cmd += (["-Wl,-undefined,dynamic_lookup"] if platform.system() == 'Darwin' else ["-rdynamic"]) +pli2_cmd += ["-o", test.obj_dir + "/libvpi2.so", "t/t_flag_main_vpi_lib2.cpp"] +test.run(logfile=test.obj_dir + "/pli2_compile.log", cmd=pli2_cmd) + +test.execute(all_run_flags=[ + "+verilator+vpi+" + test.obj_dir + "/libvpi.so", + "+verilator+vpi+" + test.obj_dir + "/libvpi2.so" +], + check_finished=True, + expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_flag_main_vpi_noarray.cpp b/test_regress/t/t_flag_main_vpi_noarray.cpp new file mode 100644 index 000000000..02568d282 --- /dev/null +++ b/test_regress/t/t_flag_main_vpi_noarray.cpp @@ -0,0 +1,21 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: VPI test library lacking vlog_startup_routines +// +// Loaded via +verilator+vpi+ with no : entry, to exercise +// the loader's error path when a library defines neither a named bootstrap +// nor the vlog_startup_routines[] array. +// +// 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-FileCopyrightText: 2025 Wilson Snyder +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* + +#include "vpi_user.h" + +// Intentionally no vlog_startup_routines and no bootstrap; just some symbol so +// the shared object is non-empty and loads successfully. +extern "C" void t_flag_main_vpi_noarray_present() {} diff --git a/test_regress/t/t_flag_main_vpi_noarray.out b/test_regress/t/t_flag_main_vpi_noarray.out new file mode 100644 index 000000000..a7f54a6af --- /dev/null +++ b/test_regress/t/t_flag_main_vpi_noarray.out @@ -0,0 +1,2 @@ +%Error: Cannot find 'vlog_startup_routines' in: obj_vlt/t_flag_main_vpi_noarray/libvpi.so +Aborting... diff --git a/test_regress/t/t_flag_main_vpi_noarray.py b/test_regress/t/t_flag_main_vpi_noarray.py new file mode 100755 index 000000000..9dd2ac853 --- /dev/null +++ b/test_regress/t/t_flag_main_vpi_noarray.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2025 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('vlt') + +# A library loaded with no : entry that lacks vlog_startup_routines +# must fail with a clear error (the missing-array branch of the loader). +test.top_filename = 't/t_flag_main_vpi.v' +test.pli_filename = 't/t_flag_main_vpi_noarray.cpp' + +test.compile(make_pli=True, verilator_flags2=["--binary --vpi --public-flat-rw"]) + +test.execute(fails=True, + all_run_flags=["+verilator+vpi+" + test.obj_dir + "/libvpi.so"], + expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_flag_main_vpi_noexe.py b/test_regress/t/t_flag_main_vpi_noexe.py new file mode 100755 index 000000000..1f347105b --- /dev/null +++ b/test_regress/t/t_flag_main_vpi_noexe.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2025 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('vlt') + +# --vpi without --exe (no generated main, library-only output): the Makefile +# must still report VM_VPI = 1, but must NOT add the runtime-VPI link flags since +# there is no executable to export VPI symbols from. Exercises the exe()==false +# branch of the VPI link-flag gate in V3EmitMk. +test.top_filename = 't/t_flag_main_vpi.v' + +test.compile(make_main=False, verilator_make_gmake=False, verilator_flags2=["--vpi --timing"]) + +test.file_grep(test.obj_dir + "/V" + test.name + "_classes.mk", r'VM_VPI = 1') +# Without --exe there is no executable to export symbols from or to dlopen into, +# so the runtime-VPI link flags (CFG_LDFLAGS_DYNAMIC/CFG_LDLIBS_DYNAMIC, probed at +# configure time) must not be referenced in the generated Makefile. +mk = test.obj_dir + "/V" + test.name + ".mk" +test.file_grep_not(mk, r'CFG_LDFLAGS_DYNAMIC') +test.file_grep_not(mk, r'CFG_LDLIBS_DYNAMIC') + +test.passes() diff --git a/test_regress/t/t_flag_main_vpi_nowarn.out b/test_regress/t/t_flag_main_vpi_nowarn.out new file mode 100644 index 000000000..e51042279 --- /dev/null +++ b/test_regress/t/t_flag_main_vpi_nowarn.out @@ -0,0 +1,3 @@ +%Warning: COMMAND_LINE:0: +verilator+vpi+ ignored: simulation was not compiled with --vpi '+verilator+vpi+/nonexistent.so' +[0] Hello +*-* All Finished *-* diff --git a/test_regress/t/t_flag_main_vpi_nowarn.py b/test_regress/t/t_flag_main_vpi_nowarn.py new file mode 100755 index 000000000..ab077f4f5 --- /dev/null +++ b/test_regress/t/t_flag_main_vpi_nowarn.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2025 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('vlt') + +# Compile with --binary but WITHOUT --vpi. +# Passing +verilator+vpi+ at runtime should emit a warning, not load anything. +test.compile(top_filename='t/t_flag_main.v', verilator_flags2=["--binary"]) + +# Without --vpi there is no loader, so the plusarg is ignored with a warning (checked via +# the golden .out). The plusarg value is fixed, so the warning text is portable. +test.execute(all_run_flags=["+verilator+vpi+/nonexistent.so"], + check_finished=True, + expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_forceable_unpacked.v b/test_regress/t/t_forceable_unpacked.v index 5e0048563..3b3cd23a0 100644 --- a/test_regress/t/t_forceable_unpacked.v +++ b/test_regress/t/t_forceable_unpacked.v @@ -5,7 +5,8 @@ // SPDX-License-Identifier: CC0-1.0 // verilog_format: off -`define checkh(g,e) do if ((g) !==(e)) begin $write("%%Error: %s:%0d: got=%x exp=%x\n", `__FILE__,`__LINE__, (g),(e)); $stop; end while(0) +`define stop $stop +`define checkh(g,e) do if ((g) !==(e)) begin $write("%%Error: %s:%0d: got=%x exp=%x\n", `__FILE__,`__LINE__, (g),(e)); `stop; end while(0) `ifdef CMT `define FORCEABLE /*verilator forceable*/ diff --git a/test_regress/t/t_fsmmulti_combo_multi_warn_bad.out b/test_regress/t/t_fsmmulti_combo_multi_warn_bad.out index 8985f2c91..367f70f55 100644 --- a/test_regress/t/t_fsmmulti_combo_multi_warn_bad.out +++ b/test_regress/t/t_fsmmulti_combo_multi_warn_bad.out @@ -1,29 +1,3 @@ -%Warning-FSMMULTI: t/t_fsmmulti_combo_multi_warn_bad.v:36:21: FSM coverage: multiple supported transition candidates found in the same combinational always block. Only the first candidate will be instrumented. - 36 | B0: state_b_d = B1; - | ^ - t/t_fsmmulti_combo_multi_warn_bad.v:32:21: ... Location of first supported candidate for 't.same_u.state_a_q' - 32 | A0: state_a_d = A1; - | ^ - ... For warning description see https://verilator.org/warn/FSMMULTI?v=latest - ... Use "/* verilator lint_off FSMMULTI */" and lint_on around source to disable this message. -%Warning-FSMMULTI: t/t_fsmmulti_combo_multi_warn_bad.v:73:19: FSM coverage: multiple supported transition candidates found for the same FSM in combinational always blocks. Only the first candidate will be instrumented. - 73 | S0: state_d = S1; - | ^ - t/t_fsmmulti_combo_multi_warn_bad.v:65:19: ... Location of first supported candidate for 't.split_u.state_q' - 65 | S0: state_d = S1; - | ^ -%Warning-FSMMULTI: t/t_fsmmulti_combo_multi_warn_bad.v:107:5: FSM coverage: multiple supported transition candidates found in the same combinational always block. Only the first candidate will be instrumented. - 107 | if (state_b_q == B0) state_b_d = B1; - | ^~ - t/t_fsmmulti_combo_multi_warn_bad.v:105:5: ... Location of first supported candidate for 't.same_if_u.state_a_q' - 105 | if (state_a_q == A0) state_a_d = A1; - | ^~ -%Warning-FSMMULTI: t/t_fsmmulti_combo_multi_warn_bad.v:140:5: FSM coverage: multiple supported transition candidates found for the same FSM in combinational always blocks. Only the first candidate will be instrumented. - 140 | if (state_q == S0) state_d = S1; - | ^~ - t/t_fsmmulti_combo_multi_warn_bad.v:134:5: ... Location of first supported candidate for 't.split_if_u.state_q' - 134 | if (state_q == S0) state_d = S1; - | ^~ %Warning-COVERIGN: t/t_fsmmulti_combo_multi_warn_bad.v:165:5: Ignoring unsupported: FSM coverage on multiple supported if-chain statements found in the same combinational always block. Only the first candidate will be instrumented. 165 | if (state_q == S1) state_d = S0; | ^~ @@ -32,4 +6,30 @@ | ^~ ... For warning description see https://verilator.org/warn/COVERIGN?v=latest ... Use "/* verilator lint_off COVERIGN */" and lint_on around source to disable this message. +%Warning-FSMMULTI: t/t_fsmmulti_combo_multi_warn_bad.v:140:5: FSM coverage: multiple supported transition candidates found for the same FSM in combinational always blocks. Only the first candidate will be instrumented. + 140 | if (state_q == S0) state_d = S1; + | ^~ + t/t_fsmmulti_combo_multi_warn_bad.v:134:5: ... Location of first supported candidate for 't.split_if_u.state_q' + 134 | if (state_q == S0) state_d = S1; + | ^~ + ... For warning description see https://verilator.org/warn/FSMMULTI?v=latest + ... Use "/* verilator lint_off FSMMULTI */" and lint_on around source to disable this message. +%Warning-FSMMULTI: t/t_fsmmulti_combo_multi_warn_bad.v:107:5: FSM coverage: multiple supported transition candidates found in the same combinational always block. Only the first candidate will be instrumented. + 107 | if (state_b_q == B0) state_b_d = B1; + | ^~ + t/t_fsmmulti_combo_multi_warn_bad.v:105:5: ... Location of first supported candidate for 't.same_if_u.state_a_q' + 105 | if (state_a_q == A0) state_a_d = A1; + | ^~ +%Warning-FSMMULTI: t/t_fsmmulti_combo_multi_warn_bad.v:73:19: FSM coverage: multiple supported transition candidates found for the same FSM in combinational always blocks. Only the first candidate will be instrumented. + 73 | S0: state_d = S1; + | ^ + t/t_fsmmulti_combo_multi_warn_bad.v:65:19: ... Location of first supported candidate for 't.split_u.state_q' + 65 | S0: state_d = S1; + | ^ +%Warning-FSMMULTI: t/t_fsmmulti_combo_multi_warn_bad.v:36:21: FSM coverage: multiple supported transition candidates found in the same combinational always block. Only the first candidate will be instrumented. + 36 | B0: state_b_d = B1; + | ^ + t/t_fsmmulti_combo_multi_warn_bad.v:32:21: ... Location of first supported candidate for 't.same_u.state_a_q' + 32 | A0: state_a_d = A1; + | ^ %Error: Exiting due to diff --git a/test_regress/t/t_gen_for.v b/test_regress/t/t_gen_for.v index 47d7ba1a7..006b9f83a 100644 --- a/test_regress/t/t_gen_for.v +++ b/test_regress/t/t_gen_for.v @@ -97,8 +97,6 @@ module paramed ( /*AUTOARG*/ // No else endgenerate -`ifndef NC // for(genvar) unsupported -`ifndef ATSIM // for(genvar) unsupported generate // Empty loop body, local genvar for (genvar j = 0; j < 3; j = j + 1) begin @@ -107,8 +105,6 @@ module paramed ( /*AUTOARG*/ for (genvar j = 0; j < 5; j = j + 1) begin end endgenerate -`endif -`endif generate endgenerate diff --git a/test_regress/t/t_gen_intdot.v b/test_regress/t/t_gen_intdot.v index d00c7028a..248616e8e 100644 --- a/test_regress/t/t_gen_intdot.v +++ b/test_regress/t/t_gen_intdot.v @@ -10,30 +10,34 @@ module t ( input clk ); - integer cyc = 0; + integer cyc = 0; - wire out; - reg in; + wire out; + reg in; - Genit g (.clk(clk), .value(in), .result(out)); + Genit g ( + .clk(clk), + .value(in), + .result(out) + ); - always @ (posedge clk) begin + always @(posedge clk) begin //$write("[%0t] cyc==%0d %x %x\n", $time, cyc, in, out); cyc <= cyc + 1; - if (cyc==0) begin + if (cyc == 0) begin // Setup in <= 1'b1; end - else if (cyc==1) begin + else if (cyc == 1) begin in <= 1'b0; end - else if (cyc==2) begin + else if (cyc == 2) begin if (out != 1'b1) $stop; end - else if (cyc==3) begin + else if (cyc == 3) begin if (out != 1'b0) $stop; end - else if (cyc==9) begin + else if (cyc == 9) begin $write("*-* All Finished *-*\n"); $finish; end @@ -41,7 +45,11 @@ module t ( endmodule -module Generate (clk, value, result); +module Generate ( + clk, + value, + result +); input clk; input value; output result; @@ -50,63 +58,73 @@ module Generate (clk, value, result); assign result = Internal; - always @(posedge clk) - Internal <= value; + always @(posedge clk) Internal <= value; endmodule -module Checker (clk, value); +module Checker ( + clk, + value +); input clk, value; always @(posedge clk) begin - $write ("[%0t] value=%h\n", $time, value); + $write("[%0t] value=%h\n", $time, value); end endmodule -module Test (clk, value, result); +module Test ( + clk, + value, + result +); input clk; input value; output result; - Generate gen (clk, value, result); - Checker chk (clk, gen.Internal); + Generate gen ( + clk, + value, + result + ); + Checker chk ( + clk, + gen.Internal + ); endmodule -module Genit (clk, value, result); +module Genit ( + clk, + value, + result +); input clk; input value; output result; -`ifndef ATSIM // else unsupported - `ifndef NC // else unsupported - `ifndef IVERILOG // else unsupported - `define WITH_FOR_GENVAR - `endif - `endif -`endif - -`define WITH_GENERATE + `define WITH_GENERATE `ifdef WITH_GENERATE - `ifndef WITH_FOR_GENVAR genvar i; - `endif generate - for ( - `ifdef WITH_FOR_GENVAR - genvar - `endif - i = 0; i < 1; i = i + 1) - begin : foo - Test tt (clk, value, result); - end + for (genvar i = 0; i < 1; i = i + 1) begin : foo + Test tt ( + clk, + value, + result + ); + end endgenerate `else - Test tt (clk, value, result); + Test tt ( + clk, + value, + result + ); `endif wire Result2 = t.g.foo[0].tt.gen.Internal; // Works - Do not change! - always @ (posedge clk) begin + always @(posedge clk) begin $write("[%0t] Result2 = %x\n", $time, Result2); end diff --git a/test_regress/t/t_gen_upscope.out b/test_regress/t/t_gen_upscope.out index 3765ed4ca..bb8b8e714 100644 --- a/test_regress/t/t_gen_upscope.out +++ b/test_regress/t/t_gen_upscope.out @@ -1,12 +1,12 @@ -created tag with scope = top.t.tag -created tag with scope = top.t.b.gen[0].tag created tag with scope = top.t.b.gen[1].tag +created tag with scope = top.t.b.gen[0].tag +created tag with scope = top.t.tag mod a has scope = top.t mod a has tag = top.t.tag mod b has scope = top.t.b mod b has tag = top.t.tag -mod c has scope = top.t.b.gen[0].c -mod c has tag = top.t.b.gen[0].tag mod c has scope = top.t.b.gen[1].c mod c has tag = top.t.b.gen[1].tag +mod c has scope = top.t.b.gen[0].c +mod c has tag = top.t.b.gen[0].tag *-* All Finished *-* diff --git a/test_regress/t/t_genfor_signed.out b/test_regress/t/t_genfor_signed.out index 7f921d5a9..b99a494fc 100644 --- a/test_regress/t/t_genfor_signed.out +++ b/test_regress/t/t_genfor_signed.out @@ -1,9 +1,9 @@ -top.t.u_sub1.unnamedblk1 1..1 i=1 +top.t.SUB_PIPE[0].u_sub.unnamedblk1 1..0 i=1 +top.t.SUB_PIPE[0].u_sub.unnamedblk1 1..0 i=0 top.t.u_sub0.unnamedblk1 1..0 i=1 top.t.u_sub0.unnamedblk1 1..0 i=0 top.t.SUB_PIPE[-1].u_sub.unnamedblk1 1..-1 i=1 top.t.SUB_PIPE[-1].u_sub.unnamedblk1 1..-1 i=0 top.t.SUB_PIPE[-1].u_sub.unnamedblk1 1..-1 i=-1 -top.t.SUB_PIPE[0].u_sub.unnamedblk1 1..0 i=1 -top.t.SUB_PIPE[0].u_sub.unnamedblk1 1..0 i=0 +top.t.u_sub1.unnamedblk1 1..1 i=1 *-* All Finished *-* diff --git a/test_regress/t/t_initial_dlyass2.py b/test_regress/t/t_initial_dlyass2.py new file mode 100755 index 000000000..46d1fe4c0 --- /dev/null +++ b/test_regress/t/t_initial_dlyass2.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile(verilator_flags2=['--binary']) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_initial_dlyass2.v b/test_regress/t/t_initial_dlyass2.v new file mode 100644 index 000000000..02e25a323 --- /dev/null +++ b/test_regress/t/t_initial_dlyass2.v @@ -0,0 +1,50 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Wilson Snyder +// SPDX-License-Identifier: CC0-1.0 + +// verilog_format: off +`define stop $stop +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +// verilog_format: on + +module t; + + reg clk = 1; + reg [7:0] d = 0; + reg [7:0] q = 0; + + // Clock generation + always #0.5 clk = ~clk; + + // Input signal generation + initial begin + // verilator lint_off INITIALDLY + d <= 0; + repeat (5) @(posedge clk); + d <= 1; + @(posedge clk); + d <= 2; + @(posedge clk); + d <= 3; + @(posedge clk); + d <= 4; + @(posedge clk); + d <= 0; + repeat (5) @(posedge clk); + $finish; + end + + // Unit under test (flip-flop) + always @(posedge clk) q <= d; + + always @(negedge clk) begin + $display("[%0t] d=%x q=%x", $time, d, q); + if (d == 1) `checkd(q, 0); + if (d == 2) `checkd(q, 1); + if (d == 3) `checkd(q, 2); + if (d == 4) `checkd(q, 3); + end + +endmodule diff --git a/test_regress/t/t_inst_signed.v b/test_regress/t/t_inst_signed.v index bd46592dd..bfb24f007 100644 --- a/test_regress/t/t_inst_signed.v +++ b/test_regress/t/t_inst_signed.v @@ -34,9 +34,9 @@ module t ( if (sgn_wide[2:0] != 3'sh7) $stop; if (unsgn_wide[2:0] != 3'h7) $stop; // Simulators differ here. - if (sgn_wide !== 8'sbzzzzz111 // z-extension - NC - && sgn_wide !== 8'sb11111111) - $stop; // sign extension - VCS + if (sgn_wide !== 8'sbzzzzz111 // z-extension - some others + && sgn_wide !== 8'sb11111111) // sign extension - some others + $stop; if (unsgn_wide !== 8'sbzzzzz111 && unsgn_wide !== 8'sb00000111) $stop; cyc <= cyc + 1; if (cyc == 3) begin diff --git a/test_regress/t/t_inst_tree_inl1_pub0.py b/test_regress/t/t_inst_tree_inl1_pub0.py index 443c7b9b1..036210aaa 100755 --- a/test_regress/t/t_inst_tree_inl1_pub0.py +++ b/test_regress/t/t_inst_tree_inl1_pub0.py @@ -20,11 +20,11 @@ test.compile( if test.vlt_all: test.file_grep( out_filename, - r'{"type":"VAR","name":"t.u.u0.u0.z1",.*"loc":"\w,70:[^"]*",.*"origName":"z1",.*"dtypeName":"logic"' + r'{"type":"VAR","name":"t.u.u1.u0.z1",.*"loc":"\w,70:[^"]*",.*"origName":"z1",.*"dtypeName":"logic"' ) test.file_grep( out_filename, - r'{"type":"VAR","name":"t.u.u0.u1.z1",.*"loc":"\w,70:[^"]*",.*"origName":"z1",.*"dtypeName":"logic"' + r'{"type":"VAR","name":"t.u.u1.u1.z1",.*"loc":"\w,70:[^"]*",.*"origName":"z1",.*"dtypeName":"logic"' ) test.file_grep( out_filename, diff --git a/test_regress/t/t_interface2.v b/test_regress/t/t_interface2.v index e11f71b1f..52c3ac79e 100644 --- a/test_regress/t/t_interface2.v +++ b/test_regress/t/t_interface2.v @@ -12,7 +12,7 @@ module t ( counter_io c1_data(); counter_io c2_data(); - //counter_io c3_data; // IEEE illegal, and VCS doesn't allow non-() as it does with cells + // counter_io c3_data; // IEEE illegal counter_io c3_data(); counter_ansi c1 (.clkm(clk), diff --git a/test_regress/t/t_interface_array_nocolon.v b/test_regress/t/t_interface_array_nocolon.v index a5af54af4..c8015b005 100644 --- a/test_regress/t/t_interface_array_nocolon.v +++ b/test_regress/t/t_interface_array_nocolon.v @@ -37,7 +37,6 @@ module t; initial begin // Check numbering with 0 first - // NC has a bug here if (foos[0].x !== 1'b1) $stop; if (foos[1].x !== 1'b1) $stop; if (foos[2].x !== 1'b0) $stop; diff --git a/test_regress/t/t_interface_virtual_sub_iface_method.v b/test_regress/t/t_interface_virtual_sub_iface_method.v index 6cf486f5b..d5d9a59fe 100644 --- a/test_regress/t/t_interface_virtual_sub_iface_method.v +++ b/test_regress/t/t_interface_virtual_sub_iface_method.v @@ -4,7 +4,8 @@ // SPDX-FileCopyrightText: 2026 PlanV GmbH // SPDX-License-Identifier: CC0-1.0 // verilog_format: off -`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); +`define stop $stop +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); // verilog_format: on interface inner_if; diff --git a/test_regress/t/t_json_only_flat.out b/test_regress/t/t_json_only_flat.out index e90bba08b..6b3d6ca6c 100644 --- a/test_regress/t/t_json_only_flat.out +++ b/test_regress/t/t_json_only_flat.out @@ -24,20 +24,20 @@ "valuep": [ {"type":"CONST","name":"2'h2","addr":"(Z)","loc":"d,25:43,25:44","dtypep":"(T)"} ],"attrsp": []}, - {"type":"VAR","name":"t.cell1.WIDTH","addr":"(AB)","loc":"d,48:15,48:20","dtypep":"(BB)","origName":"WIDTH","verilogName":"WIDTH","direction":"NONE","isConst":true,"lifetime":"VSTATICI","varType":"GPARAM","dtypeName":"logic","isGParam":true,"isParam":true,"hasUserInit":true,"sensIfacep":"UNLINKED","childDTypep": [],"delayp": [], + {"type":"VAR","name":"t.cell2.clk","addr":"(AB)","loc":"d,62:11,62:14","dtypep":"(J)","origName":"clk","verilogName":"clk","direction":"NONE","lifetime":"VSTATICI","varType":"PORT","dtypeName":"logic","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}, + {"type":"VAR","name":"t.cell2.d","addr":"(BB)","loc":"d,63:17,63:18","dtypep":"(H)","origName":"d","verilogName":"d","direction":"NONE","lifetime":"VSTATICI","varType":"PORT","dtypeName":"logic","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}, + {"type":"VAR","name":"t.cell2.q","addr":"(CB)","loc":"d,64:23,64:24","dtypep":"(H)","origName":"q","verilogName":"q","direction":"NONE","icoMaybeWritten":true,"lifetime":"VSTATICI","varType":"WIRE","dtypeName":"logic","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}, + {"type":"VAR","name":"t.cell1.WIDTH","addr":"(DB)","loc":"d,48:15,48:20","dtypep":"(EB)","origName":"WIDTH","verilogName":"WIDTH","direction":"NONE","isConst":true,"lifetime":"VSTATICI","varType":"GPARAM","dtypeName":"logic","isGParam":true,"isParam":true,"hasUserInit":true,"sensIfacep":"UNLINKED","childDTypep": [],"delayp": [], "valuep": [ - {"type":"CONST","name":"32'sh4","addr":"(CB)","loc":"d,32:14,32:15","dtypep":"(DB)"} + {"type":"CONST","name":"32'sh4","addr":"(FB)","loc":"d,32:14,32:15","dtypep":"(GB)"} ],"attrsp": []}, - {"type":"VAR","name":"t.cell1.clk","addr":"(EB)","loc":"d,50:11,50:14","dtypep":"(J)","origName":"clk","verilogName":"clk","direction":"NONE","lifetime":"VSTATICI","varType":"PORT","dtypeName":"logic","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}, - {"type":"VAR","name":"t.cell1.d","addr":"(FB)","loc":"d,51:23,51:24","dtypep":"(H)","origName":"d","verilogName":"d","direction":"NONE","lifetime":"VSTATICI","varType":"PORT","dtypeName":"logic","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}, - {"type":"VAR","name":"t.cell1.q","addr":"(GB)","loc":"d,52:30,52:31","dtypep":"(H)","origName":"q","verilogName":"q","direction":"NONE","icoMaybeWritten":true,"lifetime":"VSTATICI","varType":"PORT","dtypeName":"logic","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}, - {"type":"VAR","name":"t.cell1.IGNORED","addr":"(HB)","loc":"d,55:14,55:21","dtypep":"(BB)","origName":"IGNORED","verilogName":"IGNORED","direction":"NONE","isConst":true,"lifetime":"VSTATICI","varType":"LPARAM","dtypeName":"logic","isParam":true,"hasUserInit":true,"sensIfacep":"UNLINKED","childDTypep": [],"delayp": [], + {"type":"VAR","name":"t.cell1.clk","addr":"(HB)","loc":"d,50:11,50:14","dtypep":"(J)","origName":"clk","verilogName":"clk","direction":"NONE","lifetime":"VSTATICI","varType":"PORT","dtypeName":"logic","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}, + {"type":"VAR","name":"t.cell1.d","addr":"(IB)","loc":"d,51:23,51:24","dtypep":"(H)","origName":"d","verilogName":"d","direction":"NONE","lifetime":"VSTATICI","varType":"PORT","dtypeName":"logic","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}, + {"type":"VAR","name":"t.cell1.q","addr":"(JB)","loc":"d,52:30,52:31","dtypep":"(H)","origName":"q","verilogName":"q","direction":"NONE","icoMaybeWritten":true,"lifetime":"VSTATICI","varType":"PORT","dtypeName":"logic","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}, + {"type":"VAR","name":"t.cell1.IGNORED","addr":"(KB)","loc":"d,55:14,55:21","dtypep":"(EB)","origName":"IGNORED","verilogName":"IGNORED","direction":"NONE","isConst":true,"lifetime":"VSTATICI","varType":"LPARAM","dtypeName":"logic","isParam":true,"hasUserInit":true,"sensIfacep":"UNLINKED","childDTypep": [],"delayp": [], "valuep": [ - {"type":"CONST","name":"32'sh1","addr":"(IB)","loc":"d,55:24,55:25","dtypep":"(DB)"} + {"type":"CONST","name":"32'sh1","addr":"(LB)","loc":"d,55:24,55:25","dtypep":"(GB)"} ],"attrsp": []}, - {"type":"VAR","name":"t.cell2.clk","addr":"(JB)","loc":"d,62:11,62:14","dtypep":"(J)","origName":"clk","verilogName":"clk","direction":"NONE","lifetime":"VSTATICI","varType":"PORT","dtypeName":"logic","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}, - {"type":"VAR","name":"t.cell2.d","addr":"(KB)","loc":"d,63:17,63:18","dtypep":"(H)","origName":"d","verilogName":"d","direction":"NONE","lifetime":"VSTATICI","varType":"PORT","dtypeName":"logic","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}, - {"type":"VAR","name":"t.cell2.q","addr":"(LB)","loc":"d,64:23,64:24","dtypep":"(H)","origName":"q","verilogName":"q","direction":"NONE","icoMaybeWritten":true,"lifetime":"VSTATICI","varType":"WIRE","dtypeName":"logic","sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}, {"type":"TOPSCOPE","name":"","addr":"(E)","loc":"d,7:8,7:9","senTreesp": [], "scopep": [ {"type":"SCOPE","name":"TOP","addr":"(MB)","loc":"d,7:8,7:9","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(F)", @@ -85,74 +85,74 @@ {"type":"VARSCOPE","name":"t.S_IDLE","addr":"(JC)","loc":"d,23:26,23:32","dtypep":"(T)","isTrace":true,"scopep":"(MB)","varp":"(S)"}, {"type":"VARSCOPE","name":"t.S_FETCH","addr":"(KC)","loc":"d,24:26,24:33","dtypep":"(T)","isTrace":true,"scopep":"(MB)","varp":"(W)"}, {"type":"VARSCOPE","name":"t.S_EXEC","addr":"(LC)","loc":"d,25:26,25:32","dtypep":"(T)","isTrace":true,"scopep":"(MB)","varp":"(Y)"}, - {"type":"VARSCOPE","name":"t.cell1.WIDTH","addr":"(MC)","loc":"d,48:15,48:20","dtypep":"(BB)","isTrace":true,"scopep":"(MB)","varp":"(AB)"}, - {"type":"VARSCOPE","name":"t.cell1.clk","addr":"(NC)","loc":"d,50:11,50:14","dtypep":"(J)","isTrace":true,"scopep":"(MB)","varp":"(EB)"}, - {"type":"ALWAYS","name":"","addr":"(OC)","loc":"d,50:11,50:14","keyword":"cont_assign","sentreep": [], + {"type":"VARSCOPE","name":"t.cell2.clk","addr":"(MC)","loc":"d,62:11,62:14","dtypep":"(J)","isTrace":true,"scopep":"(MB)","varp":"(AB)"}, + {"type":"ALWAYS","name":"","addr":"(NC)","loc":"d,62:11,62:14","keyword":"cont_assign","sentreep": [], "stmtsp": [ - {"type":"ASSIGNW","name":"","addr":"(PC)","loc":"d,50:11,50:14","dtypep":"(J)", + {"type":"ASSIGNW","name":"","addr":"(OC)","loc":"d,62:11,62:14","dtypep":"(J)", "rhsp": [ - {"type":"VARREF","name":"clk","addr":"(QC)","loc":"d,50:11,50:14","dtypep":"(J)","access":"RD","varp":"(I)","varScopep":"(OB)","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"clk","addr":"(PC)","loc":"d,62:11,62:14","dtypep":"(J)","access":"RD","varp":"(I)","varScopep":"(OB)","classOrPackagep":"UNLINKED"} ], "lhsp": [ - {"type":"VARREF","name":"t.cell1.clk","addr":"(RC)","loc":"d,50:11,50:14","dtypep":"(J)","access":"WR","varp":"(EB)","varScopep":"(NC)","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"t.cell2.clk","addr":"(QC)","loc":"d,62:11,62:14","dtypep":"(J)","access":"WR","varp":"(AB)","varScopep":"(MC)","classOrPackagep":"UNLINKED"} ],"timingControlp": [],"strengthSpecp": []} ]}, - {"type":"VARSCOPE","name":"t.cell1.d","addr":"(SC)","loc":"d,51:23,51:24","dtypep":"(H)","isTrace":true,"scopep":"(MB)","varp":"(FB)"}, - {"type":"ALWAYS","name":"","addr":"(TC)","loc":"d,51:23,51:24","keyword":"cont_assign","sentreep": [], + {"type":"VARSCOPE","name":"t.cell2.d","addr":"(RC)","loc":"d,63:17,63:18","dtypep":"(H)","isTrace":true,"scopep":"(MB)","varp":"(BB)"}, + {"type":"ALWAYS","name":"","addr":"(SC)","loc":"d,63:17,63:18","keyword":"cont_assign","sentreep": [], "stmtsp": [ - {"type":"ASSIGNW","name":"","addr":"(UC)","loc":"d,51:23,51:24","dtypep":"(H)", + {"type":"ASSIGNW","name":"","addr":"(TC)","loc":"d,63:17,63:18","dtypep":"(H)", "rhsp": [ - {"type":"VARREF","name":"d","addr":"(VC)","loc":"d,51:23,51:24","dtypep":"(H)","access":"RD","varp":"(K)","varScopep":"(PB)","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"t.between","addr":"(UC)","loc":"d,63:17,63:18","dtypep":"(H)","access":"RD","varp":"(O)","varScopep":"(FC)","classOrPackagep":"UNLINKED"} ], "lhsp": [ - {"type":"VARREF","name":"t.cell1.d","addr":"(WC)","loc":"d,51:23,51:24","dtypep":"(H)","access":"WR","varp":"(FB)","varScopep":"(SC)","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"t.cell2.d","addr":"(VC)","loc":"d,63:17,63:18","dtypep":"(H)","access":"WR","varp":"(BB)","varScopep":"(RC)","classOrPackagep":"UNLINKED"} ],"timingControlp": [],"strengthSpecp": []} ]}, - {"type":"VARSCOPE","name":"t.cell1.q","addr":"(XC)","loc":"d,52:30,52:31","dtypep":"(H)","isTrace":true,"scopep":"(MB)","varp":"(GB)"}, - {"type":"ALWAYS","name":"","addr":"(YC)","loc":"d,52:30,52:31","keyword":"cont_assign","sentreep": [], + {"type":"VARSCOPE","name":"t.cell2.q","addr":"(WC)","loc":"d,64:23,64:24","dtypep":"(H)","isTrace":true,"scopep":"(MB)","varp":"(CB)"}, + {"type":"ALWAYS","name":"","addr":"(XC)","loc":"d,64:23,64:24","keyword":"cont_assign","sentreep": [], "stmtsp": [ - {"type":"ASSIGNW","name":"","addr":"(ZC)","loc":"d,52:30,52:31","dtypep":"(H)", + {"type":"ASSIGNW","name":"","addr":"(YC)","loc":"d,64:23,64:24","dtypep":"(H)", "rhsp": [ - {"type":"VARREF","name":"t.between","addr":"(AD)","loc":"d,52:30,52:31","dtypep":"(H)","access":"RD","varp":"(O)","varScopep":"(FC)","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"q","addr":"(ZC)","loc":"d,64:23,64:24","dtypep":"(H)","access":"RD","varp":"(G)","varScopep":"(NB)","classOrPackagep":"UNLINKED"} ], "lhsp": [ - {"type":"VARREF","name":"t.cell1.q","addr":"(BD)","loc":"d,52:30,52:31","dtypep":"(H)","access":"WR","varp":"(GB)","varScopep":"(XC)","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"t.cell2.q","addr":"(AD)","loc":"d,64:23,64:24","dtypep":"(H)","access":"WR","varp":"(CB)","varScopep":"(WC)","classOrPackagep":"UNLINKED"} ],"timingControlp": [],"strengthSpecp": []} ]}, - {"type":"VARSCOPE","name":"t.cell1.IGNORED","addr":"(CD)","loc":"d,55:14,55:21","dtypep":"(BB)","isTrace":true,"scopep":"(MB)","varp":"(HB)"}, - {"type":"VARSCOPE","name":"t.cell2.clk","addr":"(DD)","loc":"d,62:11,62:14","dtypep":"(J)","isTrace":true,"scopep":"(MB)","varp":"(JB)"}, - {"type":"ALWAYS","name":"","addr":"(ED)","loc":"d,62:11,62:14","keyword":"cont_assign","sentreep": [], + {"type":"VARSCOPE","name":"t.cell1.WIDTH","addr":"(BD)","loc":"d,48:15,48:20","dtypep":"(EB)","isTrace":true,"scopep":"(MB)","varp":"(DB)"}, + {"type":"VARSCOPE","name":"t.cell1.clk","addr":"(CD)","loc":"d,50:11,50:14","dtypep":"(J)","isTrace":true,"scopep":"(MB)","varp":"(HB)"}, + {"type":"ALWAYS","name":"","addr":"(DD)","loc":"d,50:11,50:14","keyword":"cont_assign","sentreep": [], "stmtsp": [ - {"type":"ASSIGNW","name":"","addr":"(FD)","loc":"d,62:11,62:14","dtypep":"(J)", + {"type":"ASSIGNW","name":"","addr":"(ED)","loc":"d,50:11,50:14","dtypep":"(J)", "rhsp": [ - {"type":"VARREF","name":"clk","addr":"(GD)","loc":"d,62:11,62:14","dtypep":"(J)","access":"RD","varp":"(I)","varScopep":"(OB)","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"clk","addr":"(FD)","loc":"d,50:11,50:14","dtypep":"(J)","access":"RD","varp":"(I)","varScopep":"(OB)","classOrPackagep":"UNLINKED"} ], "lhsp": [ - {"type":"VARREF","name":"t.cell2.clk","addr":"(HD)","loc":"d,62:11,62:14","dtypep":"(J)","access":"WR","varp":"(JB)","varScopep":"(DD)","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"t.cell1.clk","addr":"(GD)","loc":"d,50:11,50:14","dtypep":"(J)","access":"WR","varp":"(HB)","varScopep":"(CD)","classOrPackagep":"UNLINKED"} ],"timingControlp": [],"strengthSpecp": []} ]}, - {"type":"VARSCOPE","name":"t.cell2.d","addr":"(ID)","loc":"d,63:17,63:18","dtypep":"(H)","isTrace":true,"scopep":"(MB)","varp":"(KB)"}, - {"type":"ALWAYS","name":"","addr":"(JD)","loc":"d,63:17,63:18","keyword":"cont_assign","sentreep": [], + {"type":"VARSCOPE","name":"t.cell1.d","addr":"(HD)","loc":"d,51:23,51:24","dtypep":"(H)","isTrace":true,"scopep":"(MB)","varp":"(IB)"}, + {"type":"ALWAYS","name":"","addr":"(ID)","loc":"d,51:23,51:24","keyword":"cont_assign","sentreep": [], "stmtsp": [ - {"type":"ASSIGNW","name":"","addr":"(KD)","loc":"d,63:17,63:18","dtypep":"(H)", + {"type":"ASSIGNW","name":"","addr":"(JD)","loc":"d,51:23,51:24","dtypep":"(H)", "rhsp": [ - {"type":"VARREF","name":"t.between","addr":"(LD)","loc":"d,63:17,63:18","dtypep":"(H)","access":"RD","varp":"(O)","varScopep":"(FC)","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"d","addr":"(KD)","loc":"d,51:23,51:24","dtypep":"(H)","access":"RD","varp":"(K)","varScopep":"(PB)","classOrPackagep":"UNLINKED"} ], "lhsp": [ - {"type":"VARREF","name":"t.cell2.d","addr":"(MD)","loc":"d,63:17,63:18","dtypep":"(H)","access":"WR","varp":"(KB)","varScopep":"(ID)","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"t.cell1.d","addr":"(LD)","loc":"d,51:23,51:24","dtypep":"(H)","access":"WR","varp":"(IB)","varScopep":"(HD)","classOrPackagep":"UNLINKED"} ],"timingControlp": [],"strengthSpecp": []} ]}, - {"type":"VARSCOPE","name":"t.cell2.q","addr":"(ND)","loc":"d,64:23,64:24","dtypep":"(H)","isTrace":true,"scopep":"(MB)","varp":"(LB)"}, - {"type":"ALWAYS","name":"","addr":"(OD)","loc":"d,64:23,64:24","keyword":"cont_assign","sentreep": [], + {"type":"VARSCOPE","name":"t.cell1.q","addr":"(MD)","loc":"d,52:30,52:31","dtypep":"(H)","isTrace":true,"scopep":"(MB)","varp":"(JB)"}, + {"type":"ALWAYS","name":"","addr":"(ND)","loc":"d,52:30,52:31","keyword":"cont_assign","sentreep": [], "stmtsp": [ - {"type":"ASSIGNW","name":"","addr":"(PD)","loc":"d,64:23,64:24","dtypep":"(H)", + {"type":"ASSIGNW","name":"","addr":"(OD)","loc":"d,52:30,52:31","dtypep":"(H)", "rhsp": [ - {"type":"VARREF","name":"q","addr":"(QD)","loc":"d,64:23,64:24","dtypep":"(H)","access":"RD","varp":"(G)","varScopep":"(NB)","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"t.between","addr":"(PD)","loc":"d,52:30,52:31","dtypep":"(H)","access":"RD","varp":"(O)","varScopep":"(FC)","classOrPackagep":"UNLINKED"} ], "lhsp": [ - {"type":"VARREF","name":"t.cell2.q","addr":"(RD)","loc":"d,64:23,64:24","dtypep":"(H)","access":"WR","varp":"(LB)","varScopep":"(ND)","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"t.cell1.q","addr":"(QD)","loc":"d,52:30,52:31","dtypep":"(H)","access":"WR","varp":"(JB)","varScopep":"(MD)","classOrPackagep":"UNLINKED"} ],"timingControlp": [],"strengthSpecp": []} - ]} + ]}, + {"type":"VARSCOPE","name":"t.cell1.IGNORED","addr":"(RD)","loc":"d,55:14,55:21","dtypep":"(EB)","isTrace":true,"scopep":"(MB)","varp":"(KB)"} ], "blocksp": [ {"type":"ALWAYS","name":"","addr":"(SD)","loc":"d,27:23,27:24","keyword":"cont_assign","sentreep": [], @@ -221,34 +221,34 @@ {"type":"VARREF","name":"t.anonymous_expr","addr":"(RE)","loc":"d,29:10,29:24","dtypep":"(J)","access":"WR","varp":"(R)","varScopep":"(IC)","classOrPackagep":"UNLINKED"} ],"timingControlp": [],"strengthSpecp": []} ]}, - {"type":"ALWAYS","name":"","addr":"(SE)","loc":"d,57:3,57:9","keyword":"always", + {"type":"ALWAYS","name":"","addr":"(SE)","loc":"d,67:12,67:13","keyword":"cont_assign","sentreep": [], + "stmtsp": [ + {"type":"ASSIGNW","name":"","addr":"(TE)","loc":"d,67:12,67:13","dtypep":"(H)", + "rhsp": [ + {"type":"VARREF","name":"t.between","addr":"(UE)","loc":"d,67:14,67:15","dtypep":"(H)","access":"RD","varp":"(O)","varScopep":"(FC)","classOrPackagep":"UNLINKED"} + ], + "lhsp": [ + {"type":"VARREF","name":"q","addr":"(VE)","loc":"d,67:10,67:11","dtypep":"(H)","access":"WR","varp":"(G)","varScopep":"(NB)","classOrPackagep":"UNLINKED"} + ],"timingControlp": [],"strengthSpecp": []} + ]}, + {"type":"ALWAYS","name":"","addr":"(WE)","loc":"d,57:3,57:9","keyword":"always", "sentreep": [ - {"type":"SENTREE","name":"","addr":"(TE)","loc":"d,57:10,57:11", + {"type":"SENTREE","name":"","addr":"(XE)","loc":"d,57:10,57:11", "sensesp": [ - {"type":"SENITEM","name":"","addr":"(UE)","loc":"d,57:12,57:19","edgeType":"POS", + {"type":"SENITEM","name":"","addr":"(YE)","loc":"d,57:12,57:19","edgeType":"POS", "sensp": [ - {"type":"VARREF","name":"clk","addr":"(VE)","loc":"d,57:20,57:23","dtypep":"(J)","access":"RD","varp":"(I)","varScopep":"(OB)","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"clk","addr":"(ZE)","loc":"d,57:20,57:23","dtypep":"(J)","access":"RD","varp":"(I)","varScopep":"(OB)","classOrPackagep":"UNLINKED"} ],"condp": []} ]} ], "stmtsp": [ - {"type":"ASSIGNDLY","name":"","addr":"(WE)","loc":"d,57:27,57:29","dtypep":"(H)", + {"type":"ASSIGNDLY","name":"","addr":"(AF)","loc":"d,57:27,57:29","dtypep":"(H)", "rhsp": [ - {"type":"VARREF","name":"d","addr":"(XE)","loc":"d,57:30,57:31","dtypep":"(H)","access":"RD","varp":"(K)","varScopep":"(PB)","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"d","addr":"(BF)","loc":"d,57:30,57:31","dtypep":"(H)","access":"RD","varp":"(K)","varScopep":"(PB)","classOrPackagep":"UNLINKED"} ], "lhsp": [ - {"type":"VARREF","name":"t.between","addr":"(YE)","loc":"d,57:25,57:26","dtypep":"(H)","access":"WR","varp":"(O)","varScopep":"(FC)","classOrPackagep":"UNLINKED"} + {"type":"VARREF","name":"t.between","addr":"(CF)","loc":"d,57:25,57:26","dtypep":"(H)","access":"WR","varp":"(O)","varScopep":"(FC)","classOrPackagep":"UNLINKED"} ],"timingControlp": []} - ]}, - {"type":"ALWAYS","name":"","addr":"(ZE)","loc":"d,67:12,67:13","keyword":"cont_assign","sentreep": [], - "stmtsp": [ - {"type":"ASSIGNW","name":"","addr":"(AF)","loc":"d,67:12,67:13","dtypep":"(H)", - "rhsp": [ - {"type":"VARREF","name":"t.between","addr":"(BF)","loc":"d,67:14,67:15","dtypep":"(H)","access":"RD","varp":"(O)","varScopep":"(FC)","classOrPackagep":"UNLINKED"} - ], - "lhsp": [ - {"type":"VARREF","name":"q","addr":"(CF)","loc":"d,67:10,67:11","dtypep":"(H)","access":"WR","varp":"(G)","varScopep":"(NB)","classOrPackagep":"UNLINKED"} - ],"timingControlp": [],"strengthSpecp": []} ]} ],"inlinesp": []} ]} @@ -260,11 +260,11 @@ {"type":"BASICDTYPE","name":"bit","addr":"(V)","loc":"d,23:35,23:40","dtypep":"(V)","keyword":"bit","range":"1:0","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"logic","addr":"(J)","loc":"d,27:32,27:34","dtypep":"(J)","keyword":"logic","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"logic","addr":"(T)","loc":"d,23:14,23:19","dtypep":"(T)","keyword":"logic","range":"1:0","generic":true,"rangep": []}, - {"type":"BASICDTYPE","name":"logic","addr":"(BB)","loc":"d,48:15,48:20","dtypep":"(BB)","keyword":"logic","range":"31:0","generic":true,"signed":true,"rangep": []}, + {"type":"BASICDTYPE","name":"logic","addr":"(EB)","loc":"d,48:15,48:20","dtypep":"(EB)","keyword":"logic","range":"31:0","generic":true,"signed":true,"rangep": []}, {"type":"BASICDTYPE","name":"logic","addr":"(H)","loc":"d,16:15,16:16","dtypep":"(H)","keyword":"logic","range":"3:0","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"logic","addr":"(AE)","loc":"d,27:26,27:27","dtypep":"(AE)","keyword":"logic","range":"1:0","generic":true,"signed":true,"rangep": []}, {"type":"BASICDTYPE","name":"bit","addr":"(VD)","loc":"d,27:32,27:34","dtypep":"(VD)","keyword":"bit","generic":true,"rangep": []}, - {"type":"BASICDTYPE","name":"bit","addr":"(DB)","loc":"d,29:48,29:49","dtypep":"(DB)","keyword":"bit","range":"31:0","generic":true,"signed":true,"rangep": []} + {"type":"BASICDTYPE","name":"bit","addr":"(GB)","loc":"d,29:48,29:49","dtypep":"(GB)","keyword":"bit","range":"31:0","generic":true,"signed":true,"rangep": []} ]}, {"type":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0", "modulep": [ diff --git a/test_regress/t/t_lint_unusedloop_removed_bad.out b/test_regress/t/t_lint_unusedloop_removed_bad.out index 792568e78..16b88ada9 100644 --- a/test_regress/t/t_lint_unusedloop_removed_bad.out +++ b/test_regress/t/t_lint_unusedloop_removed_bad.out @@ -21,12 +21,6 @@ %Warning-UNUSEDLOOP: t/t_lint_unusedloop_removed_bad.v:280:5: Loop is not used and will be optimized out 280 | while (m_2_ticked); | ^~~~~ -%Warning-UNUSEDLOOP: t/t_lint_unusedloop_removed_bad.v:114:5: Loop condition is always false - 114 | while(always_zero < 0) begin - | ^~~~~ -%Warning-UNUSEDLOOP: t/t_lint_unusedloop_removed_bad.v:171:5: Loop condition is always false - 171 | while(always_false) begin - | ^~~~~ %Warning-UNUSEDLOOP: t/t_lint_unusedloop_removed_bad.v:181:5: Loop condition is always false 181 | while(always_zero) begin | ^~~~~ @@ -36,4 +30,10 @@ %Warning-UNUSEDLOOP: t/t_lint_unusedloop_removed_bad.v:190:5: Loop condition is always false 190 | for (int i = 0; i < always_zero; i++) | ^~~ +%Warning-UNUSEDLOOP: t/t_lint_unusedloop_removed_bad.v:171:5: Loop condition is always false + 171 | while(always_false) begin + | ^~~~~ +%Warning-UNUSEDLOOP: t/t_lint_unusedloop_removed_bad.v:114:5: Loop condition is always false + 114 | while(always_zero < 0) begin + | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_math_pow.v b/test_regress/t/t_math_pow.v index 72a617697..35aab1cb3 100644 --- a/test_regress/t/t_math_pow.v +++ b/test_regress/t/t_math_pow.v @@ -244,9 +244,7 @@ module t ( `checkh(67'h0 ** 21'h0, 67'h1); `checkh(67'sh0 ** 21'sh0, 67'sh1); `checkh(67'h10 ** 21'h0, 67'h1); -`ifndef VCS `checkh(61'h7ab3811219 ** 21'ha6e30, 61'h01ea58c703687e81); -`endif if (cyc==0) begin end else if (cyc==1) begin a <= 67'h0; b <= 67'h0; end else if (cyc==2) begin a <= 67'h0; b <= 67'h3; end diff --git a/test_regress/t/t_math_pow3.v b/test_regress/t/t_math_pow3.v index b591618b3..f0c18f8b6 100644 --- a/test_regress/t/t_math_pow3.v +++ b/test_regress/t/t_math_pow3.v @@ -16,22 +16,21 @@ module t; // verilog_format: off initial begin - // NC=67b6cfc1b29a21 VCS=c1b29a20(wrong) IV=67b6cfc1b29a21 Verilator=67b6cfc1b29a21 $display("15 ** 14 = %0x expect 67b6cfc1b29a21", 64'b1111 ** 64'b1110); - // NC=1 VCS=0 IV=0 Verilator=1 (wrong,fixed) $display("15 **-4'sd2 = %0x expect 0 (per IEEE negative power)", ((-4'd1 ** -4'sd2))); - // NC=1 VCS=0 IV=67b6cfc1b29a21(wrong) Verilator=1 $display("15 ** 14 = %0x expect 1 (LSB 4-bits of 67b6cfc1b29a21)", ((-4'd1 ** -4'd2))); - // NC=1 VCS=0 IV=67b6cfc1b29a21(wrong) Verilator=1 $display("15 ** 14 = %0x expect 1 (LSB 4-bits of 67b6cfc1b29a21)", ((4'd15 ** 4'd14))); - // NC=8765432187654321 VCS=8765432187654000(wrong) IV=8765432187654321 Verilator=8765432187654321 $display("64'big ** 1 = %0x expect %0x", 64'h8765432187654321 ** 1, 64'h8765432187654321); $display("\n"); `checkh( (64'b1111 ** 64'b1110), 64'h67b6cfc1b29a21); +`ifndef NC `checkh( (-4'd1 ** -4'sd2), 4'h0); //bug730 +`endif +`ifndef VCS `checkh( (-4'd1 ** -4'd2), 4'h1); `checkh( (4'd15 ** 4'd14), 4'h1); +`endif `checkh( (64'h8765432187654321 ** 4'h1), 64'h8765432187654321); `checkh((-8'sh3 ** 8'h3) , 8'he5 ); // a**b (-27) @@ -70,13 +69,23 @@ module t; `checkh(( 8'h3 ** -8'sh0), 8'h1 ); // a**0 always 1 `checkh(( 8'sh3 ** -8'sh0), 8'h1 ); // a**0 always 1 - `checkh((-8'sh3 ** -8'sh3), 8'h0 ); // 0 (a<-1) // NCVERILOG bug +`ifndef NC + `checkh((-8'sh3 ** -8'sh3), 8'h0 ); // 0 (a<-1) +`endif +`ifndef IVERILOG +`ifndef QUESTA +`ifndef VCS `checkh((-8'sh1 ** -8'sh2), 8'h1 ); // -1^odd=-1, -1^even=1 `checkh((-8'sh1 ** -8'sh3), 8'hff); // -1^odd=-1, -1^even=1 -// `checkh(( 8'h0 ** -8'sh3), 8'hx ); // x // NCVERILOG bug +`endif +`endif +`endif +// `checkh(( 8'h0 ** -8'sh3), 8'hx ); // x `checkh(( 8'h1 ** -8'sh3), 8'h1 ); // 1**b always 1 - `checkh(( 8'h3 ** -8'sh3), 8'h0 ); // 0 // NCVERILOG bug - `checkh(( 8'sh3 ** -8'sh3), 8'h0 ); // 0 // NCVERILOG bug +`ifndef NC + `checkh(( 8'h3 ** -8'sh3), 8'h0 ); // 0 + `checkh(( 8'sh3 ** -8'sh3), 8'h0 ); // 0 +`endif if (fail) $stop; diff --git a/test_regress/t/t_math_signed4.v b/test_regress/t/t_math_signed4.v index bb5d83602..05b7e6f7c 100644 --- a/test_regress/t/t_math_signed4.v +++ b/test_regress/t/t_math_signed4.v @@ -97,11 +97,7 @@ module t; // bug754 w5_u = 4'sb0010 << -2'sd1; // << 3 -`ifdef VCS - `checkh(w5_u, 5'b00000); // VCS E-2014.03 bug -`else - `checkh(w5_u, 5'b10000); // VCS E-2014.03 bug -`endif + `checkh(w5_u, 5'b10000); w5_u = 4'sb1000 << 0; // Sign extends `checkh(w5_u, 5'b11000); diff --git a/test_regress/t/t_math_signed5.v b/test_regress/t/t_math_signed5.v index b87b854f2..aa9a68d79 100644 --- a/test_regress/t/t_math_signed5.v +++ b/test_regress/t/t_math_signed5.v @@ -47,11 +47,7 @@ module t ( /*AUTOARG*/ initial begin // verilator lint_off STMTDLY #1; -`ifdef VCS // I-2014.03 - `checkh({a, b, c, d, e, f, g}, 7'b1101111); -`else `checkh({a, b, c, d, e, f, g}, 7'b1101011); -`endif //====================================================================== @@ -76,20 +72,11 @@ module t ( /*AUTOARG*/ w4_u = ((5'b0 == (5'sb11111 >>> 3'd7))); // Exp 0 Vlt 0 `checkh(w4_u, 4'b0001); w4_u = ((5'b01111 == (5'sb11111 / 5'sd2))); // Strength-reduces to >>> -`ifdef VCS // I-2014.03 - `checkh(w4_u, 4'b0000); // Wrong, gets 5'b0==..., unsigned does not propagate -`else - `checkh(w4_u, 4'b0001); // NC-Verilog, Modelsim, XSim, ... -`endif + `checkh(w4_u, 4'b0001); - // Does == sign propagate from lhs to rhs? Yes, but not in VCS + // Does == sign propagate from lhs to rhs? w4_u = ((5'b01010 == (5'sb11111 / 5'sd3))); // Exp 0 Vlt 0 // Must be signed result (-1/3) to make this result zero -`ifdef VCS // I-2014.03 - `checkh(w4_u, 4'b0000); // Wrong, gets 5'b0==..., unsigned does not propagate - // Somewhat questionable, as spec says division signed depends on only LHS and RHS, however differs from others -`else - `checkh(w4_u, 4'b0001); // NC-Verilog, Modelsim, XSim, ... -`endif + `checkh(w4_u, 4'b0001); w4_u = (1'b0+(5'sb11111 >>> 3'd7)); // Exp 00000 Vlt 000000 Actually the signedness of result does NOT matter `checkh(w4_u, 4'b0000); diff --git a/test_regress/t/t_math_svl2.v b/test_regress/t/t_math_svl2.v index b6049d112..1d62f7006 100644 --- a/test_regress/t/t_math_svl2.v +++ b/test_regress/t/t_math_svl2.v @@ -19,15 +19,11 @@ module t ( if ('1 !== {66{1'b1}}) $stop; if ('x !== {66{1'bx}}) $stop; if ('z !== {66{1'bz}}) $stop; -`ifndef NC // NC-Verilog 5.50-s09 chokes on this test if ("\v" != 8'd11) $stop; if ("\f" != 8'd12) $stop; if ("\a" != 8'd7) $stop; if ("\x9a" != 8'h9a) $stop; if ("\xf1" != 8'hf1) $stop; -`endif - end - if (cyc == 8) begin end if (cyc == 9) begin $write("*-* All Finished *-*\n"); diff --git a/test_regress/t/t_modport_export_task.v b/test_regress/t/t_modport_export_task.v index 848c05ccf..0016f7a3d 100644 --- a/test_regress/t/t_modport_export_task.v +++ b/test_regress/t/t_modport_export_task.v @@ -5,7 +5,8 @@ // SPDX-License-Identifier: CC0-1.0 // verilog_format: off -`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 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) // verilog_format: on interface bus_if; diff --git a/test_regress/t/t_opt_constpool_recache.py b/test_regress/t/t_opt_constpool_recache.py new file mode 100755 index 000000000..ac30d3a16 --- /dev/null +++ b/test_regress/t/t_opt_constpool_recache.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('vlt') + +test.compile(verilator_flags2=['--binary', '--stats']) + +test.execute() + +test.file_grep(test.stats, r'Optimizations, Cases table normal\s+(\d+)', 1) +test.file_grep(test.stats, r'ConstPool, Constants emitted\s+(\d+)', 1) + +test.passes() diff --git a/test_regress/t/t_opt_constpool_recache.v b/test_regress/t/t_opt_constpool_recache.v new file mode 100644 index 000000000..af77d7409 --- /dev/null +++ b/test_regress/t/t_opt_constpool_recache.v @@ -0,0 +1,75 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Wilson Snyder +// SPDX-License-Identifier: CC0-1.0 + +// verilog_format: off +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0); +// verilog_format: on + +module t; + logic clk = 1'b0; + always #5 clk = ~clk; + + logic [31:0] cyc = 0; + logic [3:0] idx; + assign idx = cyc[3:0]; + + // V3Case lowers this to a 512-bit constant-pool lookup table before V3Dead + // calls AstConstPool::rebuildVarScopesAndCache(). + logic [31:0] case_word; + always_comb + case (idx) + 4'h0: case_word = 32'h00000000; + 4'h1: case_word = 32'h00000001; + 4'h2: case_word = 32'h00000002; + 4'h3: case_word = 32'h00000003; + 4'h4: case_word = 32'h00000004; + 4'h5: case_word = 32'h00000005; + 4'h6: case_word = 32'h00000006; + 4'h7: case_word = 32'h00000007; + 4'h8: case_word = 32'h00000008; + 4'h9: case_word = 32'h00000009; + 4'ha: case_word = 32'h0000000a; + 4'hb: case_word = 32'h0000000b; + 4'hc: case_word = 32'h0000000c; + 4'hd: case_word = 32'h0000000d; + 4'he: case_word = 32'h0000000e; + default: case_word = 32'h0000000f; + endcase + + localparam logic [511:0] TABLE = { + 32'h0000000f, + 32'h0000000e, + 32'h0000000d, + 32'h0000000c, + 32'h0000000b, + 32'h0000000a, + 32'h00000009, + 32'h00000008, + 32'h00000007, + 32'h00000006, + 32'h00000005, + 32'h00000004, + 32'h00000003, + 32'h00000002, + 32'h00000001, + 32'h00000000 + }; + + // V3Premit extracts this matching wide constant after V3Dead recached the + // const-pool contents created by V3Case. + logic [31:0] static_word; + assign static_word = TABLE[{idx, 5'b0}+:32]; + + always @(posedge clk) begin + `checkh(case_word, static_word); + cyc <= cyc + 32'd1; + if (cyc == 32'd32) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_opt_dedupe_clk_gate.py b/test_regress/t/t_opt_dedupe_clk_gate.py index 02778fcec..0fbd122ba 100755 --- a/test_regress/t/t_opt_dedupe_clk_gate.py +++ b/test_regress/t/t_opt_dedupe_clk_gate.py @@ -18,7 +18,7 @@ test.compile(verilator_flags2=["--no-json-edit-nums", "--stats"]) if test.vlt_all: test.file_grep( out_filename, - r'{"type":"VAR","name":"t.f0.clock_gate.clken_latched","addr":"[^"]*","loc":"\w,44:[^"]*","dtypep":"\(\w+\)",.*"origName":"clken_latched",.*"isLatched":true,.*"dtypeName":"logic"' + r'{"type":"VAR","name":"t.f1.clock_gate.clken_latched","addr":"[^"]*","loc":"\w,44:[^"]*","dtypep":"\(\w+\)",.*"origName":"clken_latched",.*"isLatched":true,.*"dtypeName":"logic"' ) test.file_grep(test.stats, r'Optimizations, Gate sigs deduped\s+(\d+)', 2) diff --git a/test_regress/t/t_opt_inline_cfuncs_args.v b/test_regress/t/t_opt_inline_cfuncs_args.v index d94ac40c4..74c049939 100644 --- a/test_regress/t/t_opt_inline_cfuncs_args.v +++ b/test_regress/t/t_opt_inline_cfuncs_args.v @@ -5,7 +5,7 @@ // SPDX-License-Identifier: CC0-1.0 module t ( - input wire clk + input wire clk ); integer cyc = 0; diff --git a/test_regress/t/t_opt_inline_cfuncs_dup.v b/test_regress/t/t_opt_inline_cfuncs_dup.v index 2a39fa47e..2d93e20fe 100644 --- a/test_regress/t/t_opt_inline_cfuncs_dup.v +++ b/test_regress/t/t_opt_inline_cfuncs_dup.v @@ -5,7 +5,7 @@ // SPDX-License-Identifier: CC0-1.0 module t ( - input wire clk + input wire clk ); integer cyc = 0; diff --git a/test_regress/t/t_param_first.v b/test_regress/t/t_param_first.v index eea84e2c3..6ded92a93 100644 --- a/test_regress/t/t_param_first.v +++ b/test_regress/t/t_param_first.v @@ -63,12 +63,11 @@ module t ( parameter THREE_2WIDE = 2'b11; parameter ALSO_THREE_WIDE = THREE_BITS_WIDE; parameter THREEPP_32_WIDE = 2 * 8 * 2 + 3; - parameter THREEPP_3_WIDE = 3'd4 * 3'd4 * 3'd2 + 3'd3; // Yes folks VCS says 3 bits wide + parameter THREEPP_3_WIDE = 3'd4 * 3'd4 * 3'd2 + 3'd3; // Width propagation doesn't care about LHS vs RHS // But the width of a RHS/LHS on a upper node does affect lower nodes; // Thus must double-descend in width analysis. - // VCS 7.0.1 is broken on this test! parameter T10 = (3'h7 + 3'h7) + 4'h0; //initial if (T10!==4'd14) $stop; parameter T11 = 4'h0 + (3'h7 + 3'h7); //initial if (T11!==4'd14) $stop; diff --git a/test_regress/t/t_prop_always.v b/test_regress/t/t_prop_always.v index 52cfea02c..f389a3a8c 100644 --- a/test_regress/t/t_prop_always.v +++ b/test_regress/t/t_prop_always.v @@ -43,11 +43,9 @@ module t ( // Constant-false: every attempt fails. assert property (@(posedge clk) always [0:3] a_low) - ; else low_bounded_fail_q.push_back(cyc); assert property (@(posedge clk) always [0:0] a_low) - ; else low_degenerate_fail_q.push_back(cyc); // CRC-driven random input: window [cyc..cyc+3] of a_rand. @@ -76,21 +74,21 @@ module t ( crc <= {crc[62:0], crc[63] ^ crc[2] ^ crc[0]}; if (cyc == 19) begin // Constant-true window [0:3]: K=0..16 succeed at cyc K+3 = 3..19. - `checkd(high_bounded_pass_q.size(), 17); - `checkd(high_bounded_pass_q[0], 3); + `checkd(high_bounded_pass_q.size(), 17); // Other sims: 16 + `checkd(high_bounded_pass_q[0], 3); // Other sims: 4 `checkd(high_bounded_pass_q[$], 19); // Degenerate [0:0]: K=0..19 succeed at cyc K = 0..19. - `checkd(high_degenerate_pass_q.size(), 20); - `checkd(high_degenerate_pass_q[0], 0); + `checkd(high_degenerate_pass_q.size(), 20); // Other sims: 19 + `checkd(high_degenerate_pass_q[0], 0); // Other sims: 0, 1 `checkd(high_degenerate_pass_q[$], 19); // Constant-false: every attempt fails immediately. - `checkd(low_bounded_fail_q.size(), 20); - `checkd(low_degenerate_fail_q.size(), 20); - // CRC + disable streams: counts pinned (cross-checked against Questa). + `checkd(low_bounded_fail_q.size(), 20); // Other sims: 19 + `checkd(low_degenerate_fail_q.size(), 20); // Other sims: 19 + // CRC + disable streams `checkd(rand_bounded_pass_q.size(), 0); - `checkd(rand_bounded_fail_q.size(), 20); + `checkd(rand_bounded_fail_q.size(), 20); // Other sims: 19, 11 `checkd(disable_bounded_pass_q.size(), 0); - `checkd(disable_bounded_fail_q.size(), 13); + `checkd(disable_bounded_fail_q.size(), 13); // Other sims: 5, 6 $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_prop_followed_by.v b/test_regress/t/t_prop_followed_by.v index c1e5778a6..6cc11045a 100644 --- a/test_regress/t/t_prop_followed_by.v +++ b/test_regress/t/t_prop_followed_by.v @@ -4,11 +4,10 @@ // SPDX-FileCopyrightText: 2026 PlanV GmbH // SPDX-License-Identifier: CC0-1.0 -`define checkd(gotv, expv) \ - do if ((gotv) !== (expv)) begin \ - $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__, `__LINE__, (gotv), (expv)); \ - $stop; \ - end while (0); +// verilog_format: off +`define stop $stop +`define checkd(gotv, expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +// verilog_format: on module t ( input clk @@ -54,13 +53,11 @@ module t ( cyc <= cyc + 1; crc <= {crc[62:0], crc[63] ^ crc[2] ^ crc[0]}; if (cyc == 32) begin - // Counts are deterministic for this CRC seed. Questa reference run - // (IEEE 1800-2023 16.12.9) reports ovl=28, novl=19, impl=9, nimp=0; the // ovl/novl deltas vs Verilator are 1-cycle preponed-sampling differences. $display("ovl=%0d novl=%0d impl=%0d nimp=%0d wide=%0d", ovl_f, novl_f, impl_f, nimp_f, wide_f); - `checkd(ovl_f, 29); - `checkd(novl_f, 20); + `checkd(ovl_f, 29); // Other sims: 28, one other sim: 5 + `checkd(novl_f, 20); // Other sims: 19 `checkd(impl_f, 9); `checkd(nimp_f, 0); `checkd(wide_f, 0); diff --git a/test_regress/t/t_property_accept_reject_on.v b/test_regress/t/t_property_accept_reject_on.v index 020e754f2..080af892c 100644 --- a/test_regress/t/t_property_accept_reject_on.v +++ b/test_regress/t/t_property_accept_reject_on.v @@ -94,16 +94,16 @@ module t ( end else if (cyc == 99) begin `checkh(crc, 64'hc77bb9b3784ea091); - `checkd(count_fail1, 29); // Questa: 14 - `checkd(count_fail2, 65); // Questa: 64 - `checkd(count_fail3, 29); // Questa: 14 - `checkd(count_fail4, 65); // Questa: 64 - `checkd(count_fail5, 46); // Questa: 31 - `checkd(count_fail6, 65); // Questa: 59 - `checkd(count_fail7, 29); // Questa: 14 - `checkd(count_fail8, 14); // Questa: 10 - `checkd(count_fail9, 29); // Questa: 14 - `checkd(count_fail10, 29); // Questa: 14 + `checkd(count_fail1, 28); // Other sims: 14, one other: 15 + `checkd(count_fail2, 64); // One other sim: 66 + `checkd(count_fail3, 28); // Other sims: 14 + `checkd(count_fail4, 64); + `checkd(count_fail5, 45); // Other sims: 31, one other: 32 + `checkd(count_fail6, 64); // Other sims: 59, one other: 60 + `checkd(count_fail7, 28); // Other sims: 14, one other: 15 + `checkd(count_fail8, 13); // Other sims: 10 + `checkd(count_fail9, 28); // Other sims: 14, one other: 15 + `checkd(count_fail10, 28); // Other sims: 14 $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_property_disable_iff_held.py b/test_regress/t/t_property_disable_iff_held.py new file mode 100755 index 000000000..8c5881f1b --- /dev/null +++ b/test_regress/t/t_property_disable_iff_held.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile(timing_loop=True, verilator_flags2=['--assert --timing --coverage']) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_property_disable_iff_held.v b/test_regress/t/t_property_disable_iff_held.v new file mode 100644 index 000000000..37fa06461 --- /dev/null +++ b/test_regress/t/t_property_disable_iff_held.v @@ -0,0 +1,57 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 PlanV GmbH +// SPDX-License-Identifier: CC0-1.0 + +// verilog_format: off +`define stop $stop +`define checkd(gotv, expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +// verilog_format: on + +// IEEE 1800-2023 16.12: a disable iff condition held continuously true must +// disable every attempt of a multi-cycle property (verilator/verilator#7792). +// en_held is a plain non-$sampled, non-constant signal held 1, so it exercises +// the NFA disable-counter path. The held assert/cover must never fire; the +// `disable iff (1'b0)` controls prove the same assert/cover do fire when enabled. + +module t ( + input clk +); + int cyc = 0; + reg [63:0] crc = 64'h5aef0c8d_d70a4497; + wire a = crc[0]; + wire b = crc[4]; + + bit en_held = 1'b1; + + int n_held_assert = 0; + int n_held_cover = 0; + int n_ctrl_assert = 0; + int n_ctrl_cover = 0; + + // Held-true disable: assert + cover must be fully suppressed. + assert property (@(posedge clk) disable iff (en_held) (a ##1 b)) + else n_held_assert <= n_held_assert + 1; + cover property (@(posedge clk) disable iff (en_held) (a ##1 b)) + n_held_cover <= n_held_cover + 1; + + // Enabled control (disable iff 1'b0): same assert + cover must fire. + assert property (@(posedge clk) disable iff (1'b0) (a ##1 b)) + else n_ctrl_assert <= n_ctrl_assert + 1; + cover property (@(posedge clk) disable iff (1'b0) (a ##1 b)) + n_ctrl_cover <= n_ctrl_cover + 1; + + always @(posedge clk) begin + cyc <= cyc + 1; + crc <= {crc[62:0], crc[63] ^ crc[2] ^ crc[0]}; + if (cyc == 99) begin + `checkd(n_held_assert, 0); + `checkd(n_held_cover, 0); + `checkd(n_ctrl_assert, 58); + `checkd(n_ctrl_cover, 26); // Others: 26, One other: 0 + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_property_pexpr_unsup.out b/test_regress/t/t_property_pexpr_unsup.out deleted file mode 100644 index bae43d802..000000000 --- a/test_regress/t/t_property_pexpr_unsup.out +++ /dev/null @@ -1,26 +0,0 @@ -%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:115:21: Unsupported: Unclocked assertion - : ... note: In instance 't' - 115 | assert property ((s_eventually a) implies (s_eventually a)); - | ^~~~~~~~~~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:115:46: Unsupported: Unclocked assertion - : ... note: In instance 't' - 115 | assert property ((s_eventually a) implies (s_eventually a)); - | ^~~~~~~~~~~~ -%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:115:3: Unsupported: Unclocked assertion - : ... note: In instance 't' - 115 | assert property ((s_eventually a) implies (s_eventually a)); - | ^~~~~~ -%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:117:21: Unsupported: Unclocked assertion - : ... note: In instance 't' - 117 | assert property ((s_eventually a) iff (s_eventually a)); - | ^~~~~~~~~~~~ -%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:117:42: Unsupported: Unclocked assertion - : ... note: In instance 't' - 117 | assert property ((s_eventually a) iff (s_eventually a)); - | ^~~~~~~~~~~~ -%Error-UNSUPPORTED: t/t_property_pexpr_unsup.v:117:3: Unsupported: Unclocked assertion - : ... note: In instance 't' - 117 | assert property ((s_eventually a) iff (s_eventually a)); - | ^~~~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_property_s_eventually_unsup.out b/test_regress/t/t_property_s_eventually_unsup.out index 6a9be1c3a..e4355f13f 100644 --- a/test_regress/t/t_property_s_eventually_unsup.out +++ b/test_regress/t/t_property_s_eventually_unsup.out @@ -1,12 +1,8 @@ -%Error-UNSUPPORTED: t/t_property_s_eventually_unsup.v:14:20: Unsupported: Unclocked assertion +%Error-UNSUPPORTED: t/t_property_s_eventually_unsup.v:14:35: Unsupported: cycle delay in s_eventually : ... note: In instance 't' - 14 | assert property (s_eventually ##1 1); - | ^~~~~~~~~~~~ + 14 | assert property (@(posedge clk) s_eventually ##1 1); + | ^~~~~~~~~~~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_property_s_eventually_unsup.v:14:3: Unsupported: Unclocked assertion - : ... note: In instance 't' - 14 | assert property (s_eventually ##1 1); - | ^~~~~~ %Error-UNSUPPORTED: t/t_property_s_eventually_unsup.v:15:35: Unsupported: cycle delay in s_eventually : ... note: In instance 't' 15 | assert property (@(negedge clk) s_eventually ##1 1); diff --git a/test_regress/t/t_property_s_eventually_unsup.v b/test_regress/t/t_property_s_eventually_unsup.v index 9338a0f4d..02a22a127 100644 --- a/test_regress/t/t_property_s_eventually_unsup.v +++ b/test_regress/t/t_property_s_eventually_unsup.v @@ -11,7 +11,7 @@ module t; localparam MAX = 3; integer cyc = 1; - assert property (s_eventually ##1 1); + assert property (@(posedge clk) s_eventually ##1 1); assert property (@(negedge clk) s_eventually ##1 1); always @(posedge clk) begin diff --git a/test_regress/t/t_property_until_implication.v b/test_regress/t/t_property_until_implication.v index 6023ac501..2f345677f 100644 --- a/test_regress/t/t_property_until_implication.v +++ b/test_regress/t/t_property_until_implication.v @@ -50,12 +50,12 @@ module t ( crc <= 64'h5aef0c8d_d70a4497; end else if (cyc == 99) begin - // Counts reflect NFA per-cycle reject aggregation, not Questa's + // Counts reflect NFA per-cycle reject aggregation, not some other sim's // per-attempt action_block firing; the two differ by a small constant // (see PR description for the model gap). Test is a regression for // "no internal error on `until` as |=> consequent" (issue #7548). - `checkd(fail_nonoverlap, 7); - `checkd(fail_overlap, 22); + `checkd(fail_nonoverlap, 7); // Other sims: 8, one other: 7 + `checkd(fail_overlap, 22); // Other sims: 24, one other: 22 $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_queue_array.py b/test_regress/t/t_queue_array.py new file mode 100755 index 000000000..8a938befd --- /dev/null +++ b/test_regress/t/t_queue_array.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile() + +test.execute() + +test.passes() diff --git a/test_regress/t/t_queue_array.v b/test_regress/t/t_queue_array.v new file mode 100644 index 000000000..c729a4654 --- /dev/null +++ b/test_regress/t/t_queue_array.v @@ -0,0 +1,87 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Wilson Snyder +// SPDX-License-Identifier: CC0-1.0 + +// verilog_format: off +`define stop $stop +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0); +// verilog_format: on + +module t; + + int normal_queue[$]; + int array_of_queues[3][$]; + int aa_of_queues[int][$]; + + function void test_normal_queue(); + $display("[%0t] %m: Testing single queue (int normal_queue [$])", $realtime); + `checkd(normal_queue.size(), 0); + repeat (4) normal_queue.push_back($urandom); + `checkd(normal_queue.size(), 4); + repeat (4) void'(normal_queue.pop_front()); + `checkd(normal_queue.size(), 0); + endfunction + + function void test_array_of_queues(); + $display("[%0t] %m: Testing array of queues (int array_of_queues [3][$])", $realtime); + array_of_queues[0] = {}; + array_of_queues[1] = {}; + array_of_queues[2] = {}; + + for (int i = 0; i < 3; i++) begin + `checkd(array_of_queues[i].size(), 0); + end + + for (int i = 0; i < 3; i++) begin + for (int j = 0; j < 4; j++) begin : push_4_items + array_of_queues[i].push_back($urandom); + $display("[%0t] %m: array_of_queues, pushed item to queue %0d: [0]=%p [1]=%p [2]=%p", + $realtime, i, array_of_queues[0], array_of_queues[1], array_of_queues[2]); + `checkd(array_of_queues[i].size(), j + 1); + end + end + + for (int i = 0; i < 3; i++) begin : pop_4_items_from_each + repeat (4) void'(array_of_queues[i].pop_front()); + `checkd(array_of_queues[i].size(), 0); + end + endfunction + + function void test_aa_of_queues(); + $display("[%0t] %m: Testing associative-array of queues (int aa_of_queues [int][$])", + $realtime); + + aa_of_queues[0] = {}; + aa_of_queues[1] = {}; + aa_of_queues[2] = {}; + + for (int i = 0; i < 3; i++) begin + `checkd(aa_of_queues[i].size(), 0); + end + + for (int i = 0; i < 3; i++) begin + for (int j = 0; j < 4; j++) begin : push_4_items + aa_of_queues[i].push_back($urandom); + $display("[%0t] %m: aa_of_queues, pushed item to queue %0d: [0]=%p [1]=%p [2]=%p", + $realtime, i, aa_of_queues[0], aa_of_queues[1], aa_of_queues[2]); + `checkd(aa_of_queues[i].size(), j + 1); + end + end + + for (int i = 0; i < 3; i++) begin + repeat (4) void'(aa_of_queues[i].pop_front()); + `checkd(aa_of_queues[i].size(), 0); + end + endfunction + + + initial begin + test_normal_queue(); + test_aa_of_queues(); + test_array_of_queues(); + $finish; + end + +endmodule diff --git a/test_regress/t/t_randsequence.v b/test_regress/t/t_randsequence.v index 739178d02..7d00d9e15 100644 --- a/test_regress/t/t_randsequence.v +++ b/test_regress/t/t_randsequence.v @@ -7,8 +7,9 @@ // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 // verilog_format: off -`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); -`define check_range(gotv,minv,maxv) do if ((gotv) < (minv) || (gotv) > (maxv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d-%0d\n", `__FILE__,`__LINE__, (gotv), (minv), (maxv)); $stop; end while(0); +`define stop $stop +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +`define check_range(gotv,minv,maxv) do if ((gotv) < (minv) || (gotv) > (maxv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d-%0d\n", `__FILE__,`__LINE__, (gotv), (minv), (maxv)); `stop; end while(0); `define check_within_30_percent(gotv,val) `check_range((gotv), (val) * 70 / 100, (val) * 130 / 100) // verilog_format: on diff --git a/test_regress/t/t_randsequence_func.v b/test_regress/t/t_randsequence_func.v index ac06220bc..2374251af 100644 --- a/test_regress/t/t_randsequence_func.v +++ b/test_regress/t/t_randsequence_func.v @@ -7,7 +7,8 @@ // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 // verilog_format: off -`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); +`define stop $stop +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); // verilog_format: on module t; diff --git a/test_regress/t/t_randsequence_randjoin.v b/test_regress/t/t_randsequence_randjoin.v index 47bd297c2..d0d2febcd 100644 --- a/test_regress/t/t_randsequence_randjoin.v +++ b/test_regress/t/t_randsequence_randjoin.v @@ -7,8 +7,9 @@ // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 // verilog_format: off -`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); -`define check_range(gotv,minv,maxv) do if ((gotv) < (minv) || (gotv) > (maxv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d-%0d\n", `__FILE__,`__LINE__, (gotv), (minv), (maxv)); $stop; end while(0); +`define stop $stop +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +`define check_range(gotv,minv,maxv) do if ((gotv) < (minv) || (gotv) > (maxv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d-%0d\n", `__FILE__,`__LINE__, (gotv), (minv), (maxv)); `stop; end while(0); `define check_within_30_percent(gotv,val) `check_range((gotv), (val) * 70 / 100, (val) * 130 / 100) // verilog_format: on diff --git a/test_regress/t/t_randsequence_svtests.v b/test_regress/t/t_randsequence_svtests.v index dd087d63b..b4c549148 100644 --- a/test_regress/t/t_randsequence_svtests.v +++ b/test_regress/t/t_randsequence_svtests.v @@ -4,7 +4,8 @@ // SPDX-License-Identifier: ISC // verilog_format: off -`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); +`define stop $stop +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); // verilog_format: on module t; diff --git a/test_regress/t/t_sequence_first_match_unsup.out b/test_regress/t/t_sequence_first_match_unsup.out deleted file mode 100644 index e4e3a5d37..000000000 --- a/test_regress/t/t_sequence_first_match_unsup.out +++ /dev/null @@ -1,47 +0,0 @@ -%Error: t/t_sequence_first_match_unsup.v:51:34: Usage of cycle delays requires default clocking (IEEE 1800-2023 14.11) - : ... note: In instance 'main' - 51 | initial p0 : assert property ((##1 1) or(##2 1) |-> x == 1); - | ^~ - ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. -%Error: t/t_sequence_first_match_unsup.v:51:44: Usage of cycle delays requires default clocking (IEEE 1800-2023 14.11) - : ... note: In instance 'main' - 51 | initial p0 : assert property ((##1 1) or(##2 1) |-> x == 1); - | ^~ -%Error-UNSUPPORTED: t/t_sequence_first_match_unsup.v:51:16: Unsupported: Unclocked assertion - : ... note: In instance 'main' - 51 | initial p0 : assert property ((##1 1) or(##2 1) |-> x == 1); - | ^~~~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error: t/t_sequence_first_match_unsup.v:54:47: Usage of cycle delays requires default clocking (IEEE 1800-2023 14.11) - : ... note: In instance 'main' - 54 | initial p1 : assert property (first_match ((##1 1) or(##2 1)) |-> x == 1); - | ^~ -%Error: t/t_sequence_first_match_unsup.v:54:57: Usage of cycle delays requires default clocking (IEEE 1800-2023 14.11) - : ... note: In instance 'main' - 54 | initial p1 : assert property (first_match ((##1 1) or(##2 1)) |-> x == 1); - | ^~ -%Error-UNSUPPORTED: t/t_sequence_first_match_unsup.v:54:16: Unsupported: Unclocked assertion - : ... note: In instance 'main' - 54 | initial p1 : assert property (first_match ((##1 1) or(##2 1)) |-> x == 1); - | ^~~~~~ -%Error: t/t_sequence_first_match_unsup.v:57:38: Usage of cycle delays requires default clocking (IEEE 1800-2023 14.11) - : ... note: In instance 'main' - 57 | initial p2 : assert property (1 or ##1 1 |-> x == 0); - | ^~ -%Error-UNSUPPORTED: t/t_sequence_first_match_unsup.v:57:16: Unsupported: Unclocked assertion - : ... note: In instance 'main' - 57 | initial p2 : assert property (1 or ##1 1 |-> x == 0); - | ^~~~~~ -%Error: t/t_sequence_first_match_unsup.v:60:51: Usage of cycle delays requires default clocking (IEEE 1800-2023 14.11) - : ... note: In instance 'main' - 60 | initial p3 : assert property (first_match (1 or ##1 1) |-> x == 0); - | ^~ -%Error-UNSUPPORTED: t/t_sequence_first_match_unsup.v:60:16: Unsupported: Unclocked assertion - : ... note: In instance 'main' - 60 | initial p3 : assert property (first_match (1 or ##1 1) |-> x == 0); - | ^~~~~~ -%Error: Internal Error: t/t_sequence_first_match_unsup.v:51:34: ../V3Ast.cpp:#: AstSExpr must have non-nullptr delayp() - : ... note: In instance 'main' - 51 | initial p0 : assert property ((##1 1) or(##2 1) |-> x == 1); - | ^~ - ... This fatal error may be caused by the earlier error(s); resolve those first. diff --git a/test_regress/t/t_sequence_first_match_unsup.v b/test_regress/t/t_sequence_first_match_unsup.v deleted file mode 100644 index 5f4d08838..000000000 --- a/test_regress/t/t_sequence_first_match_unsup.v +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-FileCopyrightText: 2001-2020 Daniel Kroening, Edmund Clarke -// SPDX-License-Identifier: BSD-3-Clause -// -// (C) 2001-2020, Daniel Kroening, Edmund Clarke, -// Computer Science Department, University of Oxford -// Computer Science Department, Carnegie Mellon University -// -// All rights reserved. Redistribution and use in source and binary forms, with -// or without modification, are permitted provided that the following -// conditions are met: -// -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the University nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// You can contact the author at: -// - homepage : https://www.cprover.org/ebmc/ -// - source repository : https://github.com/diffblue/hw-cbmc - -module main ( - input clk -); - - reg [31:0] x = 0; - - always @(posedge clk) x <= x + 1; - - // Starting from a particular state, - // first_match yields the sequence that _ends_ first. - - // fails - initial p0 : assert property ((##1 1) or(##2 1) |-> x == 1); - - // passes - initial p1 : assert property (first_match ((##1 1) or(##2 1)) |-> x == 1); - - // fails - initial p2 : assert property (1 or ##1 1 |-> x == 0); - - // passes - initial p3 : assert property (first_match (1 or ##1 1) |-> x == 0); - -endmodule diff --git a/test_regress/t/t_sequence_intersect.v b/test_regress/t/t_sequence_intersect.v index 1e1b754b5..4e278a177 100644 --- a/test_regress/t/t_sequence_intersect.v +++ b/test_regress/t/t_sequence_intersect.v @@ -79,6 +79,10 @@ module t ( assert property (@(posedge clk) (1'b1 ##1 1'b1) intersect (1'b1 ##1 1'b1)); + // Leading-delay operands (no offset-0 check): conjoin first offset > 0. + assert property (@(posedge clk) + (##2 1'b1) intersect (##2 1'b1)); + // Intersect with `throughout` on one side: exercises fixedLength's // SThroughout branch (recurses into rhs to compute the length). cover property (@(posedge clk) diff --git a/test_regress/t/t_sequence_intersect_len_warn.out b/test_regress/t/t_sequence_intersect_len_warn.out deleted file mode 100644 index f8239fae1..000000000 --- a/test_regress/t/t_sequence_intersect_len_warn.out +++ /dev/null @@ -1,10 +0,0 @@ -%Error: t/t_sequence_intersect_len_warn.v:16:17: Intersect sequence length mismatch: left 1 cycles, right 3 cycles (IEEE 1800-2023 16.9.6) - : ... note: In instance 't' - 16 | (a ##1 b) intersect (c ##3 d)); - | ^~~~~~~~~ - ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. -%Error: t/t_sequence_intersect_len_warn.v:20:17: Intersect sequence length mismatch: left 3 cycles, right 1 cycles (IEEE 1800-2023 16.9.6) - : ... note: In instance 't' - 20 | (a ##3 b) intersect (c ##1 d)); - | ^~~~~~~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_sequence_intersect_len_warn.v b/test_regress/t/t_sequence_intersect_len_warn.v deleted file mode 100644 index e544c8926..000000000 --- a/test_regress/t/t_sequence_intersect_len_warn.v +++ /dev/null @@ -1,22 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed under the Creative Commons Public Domain. -// SPDX-FileCopyrightText: 2026 PlanV GmbH -// SPDX-License-Identifier: CC0-1.0 - -// verilog_format: off -// verilog_lint: off -// verilog_format: on - -module t (input clk); - logic a, b, c, d; - - // LHS length 2, RHS length 4 -- WIDTHTRUNC (left < right) - assert property (@(posedge clk) - (a ##1 b) intersect (c ##3 d)); - - // LHS length 4, RHS length 2 -- WIDTHEXPAND (left > right) - assert property (@(posedge clk) - (a ##3 b) intersect (c ##1 d)); - -endmodule diff --git a/test_regress/t/t_sequence_intersect_nevermatch.py b/test_regress/t/t_sequence_intersect_nevermatch.py new file mode 100755 index 000000000..ddef50cab --- /dev/null +++ b/test_regress/t/t_sequence_intersect_nevermatch.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile(verilator_flags2=['--assert --timing']) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_sequence_intersect_nevermatch.v b/test_regress/t/t_sequence_intersect_nevermatch.v new file mode 100644 index 000000000..38abde53a --- /dev/null +++ b/test_regress/t/t_sequence_intersect_nevermatch.v @@ -0,0 +1,59 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 PlanV GmbH +// SPDX-License-Identifier: CC0-1.0 + +// verilog_format: off +`define stop $stop +`define checkd(gotv, expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +// verilog_format: on + +module t ( + input clk +); + integer cyc = 0; + reg [63:0] crc = 64'h5aef0c8d_d70a4497; + + wire a = crc[0]; + wire b = crc[1]; + wire c = crc[2]; + wire d = crc[3]; + + int f_fix = 0; + int f_dis = 0; + + always_ff @(posedge clk) begin + cyc <= cyc + 1; + crc <= {crc[62:0], crc[63] ^ crc[2] ^ crc[0]}; + if (cyc == 99) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + + default clocking @(posedge clk); + endclocking + + // An intersect whose operands share no common length compiles and never + // matches (IEEE 1800-2023 16.9.6 requires a window of equal length). Each + // form is the antecedent of `|-> 1'b0`: it stays vacuous while it never + // matches, so the else fires once per match -- pinned to 0. A spurious match + // would both fail the assertion and bump the counter. + + // Unequal fixed lengths: {2} vs {3}. + ap_fix : + assert property (disable iff (cyc < 2) ((a ##2 b) intersect (c ##3 d)) |-> 1'b0) + else f_fix <= f_fix + 1; + + // Disjoint ranges: {1,2} vs {4,5}. + ap_dis : + assert property (disable iff (cyc < 2) ((a ##[1:2] b) intersect (c ##[4:5] d)) |-> 1'b0) + else f_dis <= f_dis + 1; + + final begin + // TODO need better non-zero test + `checkd(f_fix, 0); + `checkd(f_dis, 0); + end +endmodule diff --git a/test_regress/t/t_sequence_intersect_range_unsup.out b/test_regress/t/t_sequence_intersect_range_unsup.out index 3d71a9f29..8788a6735 100644 --- a/test_regress/t/t_sequence_intersect_range_unsup.out +++ b/test_regress/t/t_sequence_intersect_range_unsup.out @@ -1,14 +1,18 @@ -%Error: t/t_sequence_intersect_range_unsup.v:12:10: Usage of cycle delays requires default clocking (IEEE 1800-2023 14.11) - : ... note: In instance 't' - 12 | (a ##[1:5] b) intersect (c ##2 d)); - | ^~ - ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. -%Error: t/t_sequence_intersect_range_unsup.v:12:34: Usage of cycle delays requires default clocking (IEEE 1800-2023 14.11) - : ... note: In instance 't' - 12 | (a ##[1:5] b) intersect (c ##2 d)); - | ^~ -%Error: Internal Error: t/t_sequence_intersect_range_unsup.v:12:10: ../V3Ast.cpp:#: AstSExpr must have non-nullptr delayp() - : ... note: In instance 't' - 12 | (a ##[1:5] b) intersect (c ##2 d)); - | ^~ - ... This fatal error may be caused by the earlier error(s); resolve those first. +%Error-UNSUPPORTED: t/t_sequence_intersect_range_unsup.v:16:44: Unsupported: intersect with this variable-length operand + : ... note: In instance 't' + 16 | assert property ((a ##[1:3] b ##[1:2] c) intersect (d ##2 e)); + | ^~~~~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_sequence_intersect_range_unsup.v:19:45: Unsupported: intersect operand is not a plain boolean sequence + : ... note: In instance 't' + 19 | assert property ((a throughout (b ##1 c)) intersect (d ##[0:2] e)); + | ^~~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_intersect_range_unsup.v:22:42: Unsupported: intersect of two sequences that each vary in length over a range with internal structure + : ... note: In instance 't' + 22 | assert property ((a ##[1:3] (b ##1 c)) intersect (d ##[2:4] e)); + | ^~~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_intersect_range_unsup.v:25:42: Unsupported: intersect of two sequences that each vary in length over a range with internal structure + : ... note: In instance 't' + 25 | assert property ((a ##2 (b ##[1:3] c)) intersect (d ##[3:5] e)); + | ^~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_sequence_intersect_range_unsup.v b/test_regress/t/t_sequence_intersect_range_unsup.v index 837f9b146..567496a47 100644 --- a/test_regress/t/t_sequence_intersect_range_unsup.v +++ b/test_regress/t/t_sequence_intersect_range_unsup.v @@ -4,11 +4,24 @@ // SPDX-FileCopyrightText: 2026 PlanV GmbH // SPDX-License-Identifier: CC0-1.0 -module t (input clk); - logic a, b, c, d; +module t ( + input clk +); + logic a, b, c, d, e; - // Range delay in intersect operand is unsupported - assert property (@(posedge clk) - (a ##[1:5] b) intersect (c ##2 d)); + default clocking @(posedge clk); + endclocking + + // Two ranged cycle delays in one intersect operand is unsupported + assert property ((a ##[1:3] b ##[1:2] c) intersect (d ##2 e)); + + // Single common length, but an operand is not a plain boolean sequence + assert property ((a throughout (b ##1 c)) intersect (d ##[0:2] e)); + + // Both operands vary over a range and carry internal structure + assert property ((a ##[1:3] (b ##1 c)) intersect (d ##[2:4] e)); + + // Operand top-level delay fixed but length varies via a nested range + assert property ((a ##2 (b ##[1:3] c)) intersect (d ##[3:5] e)); endmodule diff --git a/test_regress/t/t_sequence_intersect_varlen.py b/test_regress/t/t_sequence_intersect_varlen.py new file mode 100755 index 000000000..ddef50cab --- /dev/null +++ b/test_regress/t/t_sequence_intersect_varlen.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile(verilator_flags2=['--assert --timing']) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_sequence_intersect_varlen.v b/test_regress/t/t_sequence_intersect_varlen.v new file mode 100644 index 000000000..72eaa8601 --- /dev/null +++ b/test_regress/t/t_sequence_intersect_varlen.v @@ -0,0 +1,72 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 PlanV GmbH +// SPDX-License-Identifier: CC0-1.0 + +// verilog_format: off +`define stop $stop +`define checkd(gotv, expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +// verilog_format: on + +module t ( + input clk +); + integer cyc = 0; + reg [63:0] crc = 64'h5aef0c8d_d70a4497; + + wire a = crc[0]; + wire b = crc[1]; + wire c = crc[2]; + wire d = crc[3]; + wire e = crc[4]; + + int f_var = 0; + int f_ieee = 0; + int f_collapse = 0; + int f_over = 0; + + always @(posedge clk) begin + cyc <= cyc + 1; + crc <= {crc[62:0], crc[63] ^ crc[2] ^ crc[0]}; + if (cyc == 99) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + + default clocking @(posedge clk); + endclocking + + // Both operands vary in length: lhs in [1,3], rhs in [2,5], common [2,3]. + // Variable-length intersect (IEEE 1800-2023 16.9.6): both match the same + // window with equal start and end, length chosen from each operand's range. + ap_var : + assert property (disable iff (cyc < 2) (a & c) |-> ((a ##[1:3] b) intersect (c ##[2:5] d))) + else f_var <= f_var + 1; + + // IEEE 16.9.6 canonical: one variable + one fixed operand, common length {4}. + ap_ieee : + assert property (disable iff (cyc < 2) a |-> ((a ##[1:5] b) intersect (c ##2 d ##2 e))) + else f_ieee <= f_ieee + 1; + + // Common length collapses to {0}: (a ##[0:3] b) intersect c == a & b & c, + // so this implication never fails (exercises the bare-boolean lowering path). + ap_collapse : + assert property (disable iff (cyc < 2) (a & b & c) |-> ((a ##[0:3] b) intersect c)) + else f_collapse <= f_collapse + 1; + + // Equal fixed length, one operand carrying an internal check: lowered through + // the per-cycle conjoin, not the done-latch combiner (which conflates + // concurrent attempts and over-accepts). + ap_over : + assert property (disable iff (cyc < 2) (a ##4 b) intersect (c ##2 d ##2 e)) + else f_over <= f_over + 1; + + final begin + `checkd(f_var, 7); + `checkd(f_ieee, 41); + `checkd(f_collapse, 0); + `checkd(f_over, 84); + end +endmodule diff --git a/test_regress/t/t_sequence_sexpr_throughout.v b/test_regress/t/t_sequence_sexpr_throughout.v index a2b17ef46..8b9fe3cfa 100644 --- a/test_regress/t/t_sequence_sexpr_throughout.v +++ b/test_regress/t/t_sequence_sexpr_throughout.v @@ -74,7 +74,7 @@ module t ( // by the throughout-drop check. cover property (@(posedge clk) a throughout (b ##1 c)); - always_ff @(posedge clk) begin + always @(posedge clk) begin `ifdef TEST_VERBOSE $write("[%0t] cyc==%0d crc=%x cond=%b a=%b b=%b c=%b\n", $time, cyc, crc, cond, a, b, c); @@ -85,15 +85,15 @@ module t ( crc <= 64'h5aef0c8d_d70a4497; end else if (cyc == 99) begin `checkh(crc, 64'hc77bb9b3784ea091); - `checkd(count_fail1, 28); // Questa: 28 - `checkd(count_fail2, 33); // Questa: 33 - `checkd(count_fail3, 31); // Questa: 31 - `checkd(count_fail4, 35); // Questa: 35 + `checkd(count_fail1, 28); + `checkd(count_fail2, 33); + `checkd(count_fail3, 31); + `checkd(count_fail4, 35); // count_fail5: NFA undercounts by 12; throughout+temporal-and first-step // rejection is a known limitation of the SAnd combiner architecture // (propagating isTopLevelStep causes double-counting; fix is future work). - `checkd(count_fail5, 25); // Questa: 36 - `checkd(count_fail6, 33); // Questa: 33 + `checkd(count_fail5, 25); // All other sims: 36 + `checkd(count_fail6, 33); $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_sequence_within.v b/test_regress/t/t_sequence_within.v index 093b7afcb..e8d73ad61 100644 --- a/test_regress/t/t_sequence_within.v +++ b/test_regress/t/t_sequence_within.v @@ -11,9 +11,6 @@ // verilog_format: on // IEEE 1800-2023 16.9.10: seq1 within seq2 -// CRC-driven random stimulus. Each property has a counter; at cyc==99 we -// `checkd` against Verilator's actual count and record the Questa golden -// value in a trailing comment for cross-simulator reference. module t ( input clk @@ -93,7 +90,7 @@ module t ( initial $assertvacuousoff; - always_ff @(posedge clk) begin + always @(posedge clk) begin cyc <= cyc + 1; crc <= {crc[62:0], crc[63] ^ crc[2] ^ crc[0]}; @@ -103,30 +100,20 @@ module t ( else if (cyc == 99) begin `checkh(crc, 64'hc77bb9b3784ea091); // p1/p2/p5 use |->; the NFA currently fires the pass action on - // vacuous passes too, so counts are inflated vs. Questa. Pre-existing + // vacuous passes too, so counts are inflated vs. others. Pre-existing // engine-wide behavior, not within-specific. - `checkd(count_p1, 23); // Questa: 23 - `checkd(count_p2, 44); // Questa: 44 - `checkd(count_p3, 26); // Questa: 20 - `checkd(count_p4, 24); // Questa: 22 - `checkd(count_p5, 26); // Questa: 26 - `checkd(count_p6, 21); // Questa: 16 - `checkd(count_p7, 15); // Questa: 9 - `checkd(count_p8, 15); // Questa: 4 - `checkd(count_p9, 17); // Questa: 10 - `checkd(count_p10, 24); // Questa: 15 + `checkd(count_p1, 23); // Other sims: 23, or 16 + `checkd(count_p2, 44); // Other sims: 44, or 21 + `checkd(count_p3, 25); // Other sims: 20 + `checkd(count_p4, 23); // Other sims: 22 + `checkd(count_p5, 26); + `checkd(count_p6, 21); // Other sims: 16 + `checkd(count_p7, 15); // Other sims: 9 + `checkd(count_p8, 15); // Other sims: 4 + `checkd(count_p9, 15); // Other sims: 10 + `checkd(count_p10, 23); // Other sims: 15 $write("*-* All Finished *-*\n"); $finish; end end endmodule - -// Harness for stand-alone simulators (e.g. QuestaSim). Verilator uses -// test_regress's built-in clock shell and ignores this module. -`ifndef VERILATOR -module wrap; - logic clk = 0; - always #5 clk = ~clk; - t inst (.clk(clk)); -endmodule -`endif diff --git a/test_regress/t/t_sv_cpu.py b/test_regress/t/t_sv_cpu.py index dcc41dab2..0eb062f2a 100755 --- a/test_regress/t/t_sv_cpu.py +++ b/test_regress/t/t_sv_cpu.py @@ -14,23 +14,22 @@ test.scenarios('simulator') # 22-Mar-2012: Modifications for this test contributed by Jeremy Bennett, # Embecosm. -test.compile( - # Taken from the original VCS command line. - v_flags2=[ - "t/t_sv_cpu_code/timescale.sv", "t/t_sv_cpu_code/program_h.sv", - "t/t_sv_cpu_code/pads_h.sv", "t/t_sv_cpu_code/ports_h.sv", "t/t_sv_cpu_code/pinout_h.sv", - "t/t_sv_cpu_code/genbus_if.sv", "t/t_sv_cpu_code/pads_if.sv", "t/t_sv_cpu_code/adrdec.sv", - "t/t_sv_cpu_code/pad_gpio.sv", "t/t_sv_cpu_code/pad_vdd.sv", "t/t_sv_cpu_code/pad_gnd.sv", - "t/t_sv_cpu_code/pads.sv", "t/t_sv_cpu_code/ports.sv", "t/t_sv_cpu_code/ac_dig.sv", - "t/t_sv_cpu_code/ac_ana.sv", "t/t_sv_cpu_code/ac.sv", "t/t_sv_cpu_code/cpu.sv", - "t/t_sv_cpu_code/chip.sv" - ], - vcs_flags2=["-R -sverilog +memcbk -y t/t_sv_cpu_code +libext+.sv+ +incdir+t/t_sv_cpu_code"], - verilator_flags2=[ - "-y t/t_sv_cpu_code +libext+.sv+ +incdir+t/t_sv_cpu_code --top-module t", - "--timescale-override 1ns/1ps" - ], - iv_flags2=["-yt/t_sv_cpu_code -It/t_sv_cpu_code -Y.sv"]) +test.compile(v_flags2=[ + "t/t_sv_cpu_code/timescale.sv", "t/t_sv_cpu_code/program_h.sv", "t/t_sv_cpu_code/pads_h.sv", + "t/t_sv_cpu_code/ports_h.sv", "t/t_sv_cpu_code/pinout_h.sv", "t/t_sv_cpu_code/genbus_if.sv", + "t/t_sv_cpu_code/pads_if.sv", "t/t_sv_cpu_code/adrdec.sv", "t/t_sv_cpu_code/pad_gpio.sv", + "t/t_sv_cpu_code/pad_vdd.sv", "t/t_sv_cpu_code/pad_gnd.sv", "t/t_sv_cpu_code/pads.sv", + "t/t_sv_cpu_code/ports.sv", "t/t_sv_cpu_code/ac_dig.sv", "t/t_sv_cpu_code/ac_ana.sv", + "t/t_sv_cpu_code/ac.sv", "t/t_sv_cpu_code/cpu.sv", "t/t_sv_cpu_code/chip.sv" +], + vcs_flags2=[ + "-R -sverilog +memcbk -y t/t_sv_cpu_code +libext+.sv+ +incdir+t/t_sv_cpu_code" + ], + verilator_flags2=[ + "-y t/t_sv_cpu_code +libext+.sv+ +incdir+t/t_sv_cpu_code --top-module t", + "--timescale-override 1ns/1ps" + ], + iv_flags2=["-yt/t_sv_cpu_code -It/t_sv_cpu_code -Y.sv"]) test.execute() diff --git a/test_regress/t/t_sys_file_scan_delay.v b/test_regress/t/t_sys_file_scan_delay.v index f1db0a34e..efb4e4659 100644 --- a/test_regress/t/t_sys_file_scan_delay.v +++ b/test_regress/t/t_sys_file_scan_delay.v @@ -6,7 +6,7 @@ // verilog_format: off `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 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); // verilog_format: on module t; diff --git a/test_regress/t/t_tagged_case.out b/test_regress/t/t_tagged_case.out index e7965a85d..edec504d1 100644 --- a/test_regress/t/t_tagged_case.out +++ b/test_regress/t/t_tagged_case.out @@ -11,142 +11,142 @@ %Error-UNSUPPORTED: t/t_tagged_case.v:65:5: Unsupported: void (for tagged unions) 65 | void Invalid; | ^~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:71:5: Unsupported: void (for tagged unions) - 71 | void Invalid; +%Error-UNSUPPORTED: t/t_tagged_case.v:73:5: Unsupported: void (for tagged unions) + 73 | void Invalid; | ^~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:80:5: Unsupported: void (for tagged unions) - 80 | void Invalid; +%Error-UNSUPPORTED: t/t_tagged_case.v:82:5: Unsupported: void (for tagged unions) + 82 | void Invalid; | ^~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:87:5: Unsupported: void (for tagged unions) - 87 | void Invalid; +%Error-UNSUPPORTED: t/t_tagged_case.v:89:5: Unsupported: void (for tagged unions) + 89 | void Invalid; | ^~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:93:5: Unsupported: void (for tagged unions) - 93 | void Invalid; +%Error-UNSUPPORTED: t/t_tagged_case.v:95:5: Unsupported: void (for tagged unions) + 95 | void Invalid; | ^~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:102:5: Unsupported: void (for tagged unions) - 102 | void Invalid; +%Error-UNSUPPORTED: t/t_tagged_case.v:104:5: Unsupported: void (for tagged unions) + 104 | void Invalid; | ^~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:126:9: Unsupported: tagged union - 126 | v = tagged Invalid; +%Error-UNSUPPORTED: t/t_tagged_case.v:128:9: Unsupported: tagged union + 128 | v = tagged Invalid; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:128:5: Unsupported: case matches (for tagged union) - 128 | case (v) matches +%Error-UNSUPPORTED: t/t_tagged_case.v:130:5: Unsupported: case matches (for tagged union) + 130 | case (v) matches | ^~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:129:7: Unsupported: tagged union - 129 | tagged Invalid : result = 1; +%Error-UNSUPPORTED: t/t_tagged_case.v:131:7: Unsupported: tagged union + 131 | tagged Invalid : result = 1; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:130:7: Unsupported: tagged pattern - 130 | tagged Valid .n : result = n; +%Error-UNSUPPORTED: t/t_tagged_case.v:132:7: Unsupported: tagged pattern + 132 | tagged Valid .n : result = n; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:130:20: Unsupported: pattern variable - 130 | tagged Valid .n : result = n; +%Error-UNSUPPORTED: t/t_tagged_case.v:132:20: Unsupported: pattern variable + 132 | tagged Valid .n : result = n; | ^ -%Error-UNSUPPORTED: t/t_tagged_case.v:135:9: Unsupported: tagged union - 135 | v = tagged Valid (123); +%Error-UNSUPPORTED: t/t_tagged_case.v:137:9: Unsupported: tagged union + 137 | v = tagged Valid (123); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:137:5: Unsupported: case matches (for tagged union) - 137 | case (v) matches +%Error-UNSUPPORTED: t/t_tagged_case.v:139:5: Unsupported: case matches (for tagged union) + 139 | case (v) matches | ^~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:138:7: Unsupported: tagged union - 138 | tagged Invalid : result = -1; +%Error-UNSUPPORTED: t/t_tagged_case.v:140:7: Unsupported: tagged union + 140 | tagged Invalid : result = -1; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:139:7: Unsupported: tagged pattern - 139 | tagged Valid .n : result = n; +%Error-UNSUPPORTED: t/t_tagged_case.v:141:7: Unsupported: tagged pattern + 141 | tagged Valid .n : result = n; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:139:20: Unsupported: pattern variable - 139 | tagged Valid .n : result = n; +%Error-UNSUPPORTED: t/t_tagged_case.v:141:20: Unsupported: pattern variable + 141 | tagged Valid .n : result = n; | ^ -%Error-UNSUPPORTED: t/t_tagged_case.v:144:10: Unsupported: tagged union - 144 | wt = tagged Wide60 (60'hFEDCBA987654321); +%Error-UNSUPPORTED: t/t_tagged_case.v:146:10: Unsupported: tagged union + 146 | wt = tagged Wide60 (60'hFEDCBA987654321); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:146:5: Unsupported: case matches (for tagged union) - 146 | case (wt) matches +%Error-UNSUPPORTED: t/t_tagged_case.v:148:5: Unsupported: case matches (for tagged union) + 148 | case (wt) matches | ^~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:147:7: Unsupported: tagged union - 147 | tagged Invalid : wide60_result = 0; +%Error-UNSUPPORTED: t/t_tagged_case.v:149:7: Unsupported: tagged union + 149 | tagged Invalid : wide60_result = 0; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:148:7: Unsupported: tagged pattern - 148 | tagged Wide60 .w : wide60_result = w; +%Error-UNSUPPORTED: t/t_tagged_case.v:150:7: Unsupported: tagged pattern + 150 | tagged Wide60 .w : wide60_result = w; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:148:21: Unsupported: pattern variable - 148 | tagged Wide60 .w : wide60_result = w; +%Error-UNSUPPORTED: t/t_tagged_case.v:150:21: Unsupported: pattern variable + 150 | tagged Wide60 .w : wide60_result = w; | ^ -%Error-UNSUPPORTED: t/t_tagged_case.v:154:10: Unsupported: tagged union - 154 | wt = tagged Wide90 (90'hDE_ADBEEFCA_FEBABE12_3456); +%Error-UNSUPPORTED: t/t_tagged_case.v:158:10: Unsupported: tagged union + 158 | wt = tagged Wide90 (90'hDE_ADBEEFCA_FEBABE12_3456); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:156:5: Unsupported: case matches (for tagged union) - 156 | case (wt) matches +%Error-UNSUPPORTED: t/t_tagged_case.v:160:5: Unsupported: case matches (for tagged union) + 160 | case (wt) matches | ^~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:157:7: Unsupported: tagged union - 157 | tagged Invalid : wide90_result = 0; +%Error-UNSUPPORTED: t/t_tagged_case.v:161:7: Unsupported: tagged union + 161 | tagged Invalid : wide90_result = 0; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:158:7: Unsupported: tagged pattern - 158 | tagged Wide90 .w : wide90_result = w; +%Error-UNSUPPORTED: t/t_tagged_case.v:162:7: Unsupported: tagged pattern + 162 | tagged Wide90 .w : wide90_result = w; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:158:21: Unsupported: pattern variable - 158 | tagged Wide90 .w : wide90_result = w; +%Error-UNSUPPORTED: t/t_tagged_case.v:162:21: Unsupported: pattern variable + 162 | tagged Wide90 .w : wide90_result = w; | ^ -%Error-UNSUPPORTED: t/t_tagged_case.v:164:10: Unsupported: tagged union - 164 | wt = tagged Byte8NonZeroLSB (8'hA5); +%Error-UNSUPPORTED: t/t_tagged_case.v:170:10: Unsupported: tagged union + 170 | wt = tagged Byte8NonZeroLSB (8'hA5); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:166:5: Unsupported: case matches (for tagged union) - 166 | case (wt) matches +%Error-UNSUPPORTED: t/t_tagged_case.v:172:5: Unsupported: case matches (for tagged union) + 172 | case (wt) matches | ^~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:167:7: Unsupported: tagged pattern - 167 | tagged Byte8NonZeroLSB .b : result = b; +%Error-UNSUPPORTED: t/t_tagged_case.v:173:7: Unsupported: tagged pattern + 173 | tagged Byte8NonZeroLSB .b : result = b; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:167:30: Unsupported: pattern variable - 167 | tagged Byte8NonZeroLSB .b : result = b; +%Error-UNSUPPORTED: t/t_tagged_case.v:173:30: Unsupported: pattern variable + 173 | tagged Byte8NonZeroLSB .b : result = b; | ^ -%Error-UNSUPPORTED: t/t_tagged_case.v:173:10: Unsupported: tagged union - 173 | wt = tagged Word32LittleEndian (32'hDEADBEEF); +%Error-UNSUPPORTED: t/t_tagged_case.v:179:10: Unsupported: tagged union + 179 | wt = tagged Word32LittleEndian (32'hDEADBEEF); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:175:5: Unsupported: case matches (for tagged union) - 175 | case (wt) matches +%Error-UNSUPPORTED: t/t_tagged_case.v:181:5: Unsupported: case matches (for tagged union) + 181 | case (wt) matches | ^~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:176:7: Unsupported: tagged pattern - 176 | tagged Word32LittleEndian .w : result = w; +%Error-UNSUPPORTED: t/t_tagged_case.v:182:7: Unsupported: tagged pattern + 182 | tagged Word32LittleEndian .w : result = w; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:176:33: Unsupported: pattern variable - 176 | tagged Word32LittleEndian .w : result = w; +%Error-UNSUPPORTED: t/t_tagged_case.v:182:33: Unsupported: pattern variable + 182 | tagged Word32LittleEndian .w : result = w; | ^ -%Error-UNSUPPORTED: t/t_tagged_case.v:182:10: Unsupported: tagged union - 182 | at = tagged Arr '{10, 20, 30, 40}; +%Error-UNSUPPORTED: t/t_tagged_case.v:188:10: Unsupported: tagged union + 188 | at = tagged Arr '{10, 20, 30, 40}; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:184:5: Unsupported: case matches (for tagged union) - 184 | case (at) matches +%Error-UNSUPPORTED: t/t_tagged_case.v:190:5: Unsupported: case matches (for tagged union) + 190 | case (at) matches | ^~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:185:7: Unsupported: tagged union - 185 | tagged Invalid : result = -1; +%Error-UNSUPPORTED: t/t_tagged_case.v:191:7: Unsupported: tagged union + 191 | tagged Invalid : result = -1; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:186:7: Unsupported: tagged pattern - 186 | tagged Scalar .s : result = s; +%Error-UNSUPPORTED: t/t_tagged_case.v:192:7: Unsupported: tagged pattern + 192 | tagged Scalar .s : result = s; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:186:21: Unsupported: pattern variable - 186 | tagged Scalar .s : result = s; +%Error-UNSUPPORTED: t/t_tagged_case.v:192:21: Unsupported: pattern variable + 192 | tagged Scalar .s : result = s; | ^ -%Error-UNSUPPORTED: t/t_tagged_case.v:187:7: Unsupported: tagged pattern - 187 | tagged Arr .a : result = a[0] + a[1] + a[2] + a[3]; +%Error-UNSUPPORTED: t/t_tagged_case.v:193:7: Unsupported: tagged pattern + 193 | tagged Arr .a : result = a[0] + a[1] + a[2] + a[3]; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:187:18: Unsupported: pattern variable - 187 | tagged Arr .a : result = a[0] + a[1] + a[2] + a[3]; +%Error-UNSUPPORTED: t/t_tagged_case.v:193:18: Unsupported: pattern variable + 193 | tagged Arr .a : result = a[0] + a[1] + a[2] + a[3]; | ^ -%Error-UNSUPPORTED: t/t_tagged_case.v:192:13: Unsupported: tagged union - 192 | instr = tagged Jmp (tagged JmpC '{2'd1, 10'd256}); +%Error-UNSUPPORTED: t/t_tagged_case.v:198:13: Unsupported: tagged union + 198 | instr = tagged Jmp (tagged JmpC '{2'd1, 10'd256}); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:192:25: Unsupported: tagged union - 192 | instr = tagged Jmp (tagged JmpC '{2'd1, 10'd256}); +%Error-UNSUPPORTED: t/t_tagged_case.v:198:25: Unsupported: tagged union + 198 | instr = tagged Jmp (tagged JmpC '{2'd1, 10'd256}); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:194:5: Unsupported: case matches (for tagged union) - 194 | case (instr) matches +%Error-UNSUPPORTED: t/t_tagged_case.v:200:5: Unsupported: case matches (for tagged union) + 200 | case (instr) matches | ^~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:195:7: Unsupported: tagged pattern - 195 | tagged Add .* : result = -1; +%Error-UNSUPPORTED: t/t_tagged_case.v:201:7: Unsupported: tagged pattern + 201 | tagged Add .* : result = -1; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_case.v:195:18: Unsupported: pattern wildcard - 195 | tagged Add .* : result = -1; +%Error-UNSUPPORTED: t/t_tagged_case.v:201:18: Unsupported: pattern wildcard + 201 | tagged Add .* : result = -1; | ^~ -%Error-UNSUPPORTED: t/t_tagged_case.v:196:7: Unsupported: tagged union - 196 | tagged Jmp (tagged JmpU .a) : result = a; +%Error-UNSUPPORTED: t/t_tagged_case.v:202:7: Unsupported: tagged union + 202 | tagged Jmp (tagged JmpU .a) : result = a; | ^~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_tagged_case.v b/test_regress/t/t_tagged_case.v index a2ebf02fc..ebf466c59 100644 --- a/test_regress/t/t_tagged_case.v +++ b/test_regress/t/t_tagged_case.v @@ -63,7 +63,9 @@ module t; // Tagged union with chandle member typedef union tagged { void Invalid; +`ifndef QUESTA chandle Handle; +`endif } ChandleType; // Tagged union with class reference member @@ -148,7 +150,9 @@ module t; tagged Wide60 .w : wide60_result = w; default : wide60_result = 0; endcase +`ifndef QUESTA `checkh(wide60_result, 60'hFEDCBA987654321); +`endif // Test 4: Wide type case matching - 90-bit wt = tagged Wide90 (90'hDE_ADBEEFCA_FEBABE12_3456); @@ -158,7 +162,9 @@ module t; tagged Wide90 .w : wide90_result = w; default : wide90_result = 0; endcase +`ifndef QUESTA `checkh(wide90_result, 90'hDE_ADBEEFCA_FEBABE12_3456); +`endif // Test 5: Non-zero LSB case match wt = tagged Byte8NonZeroLSB (8'hA5); @@ -203,7 +209,9 @@ module t; result = 0; case (cht) matches tagged Invalid : result = 1; +`ifndef QUESTA tagged Handle .* : result = 2; // Wildcard - can't bind chandle +`endif endcase `checkh(result, 1); @@ -213,9 +221,9 @@ module t; result = 0; case (clt) matches tagged Invalid : result = -1; - tagged Obj .o : result = o.value; + tagged Obj : result = 2; endcase - `checkh(result, 42); + `checkh(result, 2); // Test 11: Real member case matching rt = tagged Invalid; diff --git a/test_regress/t/t_tagged_if.out b/test_regress/t/t_tagged_if.out index 31b7cc0bb..db7e619f6 100644 --- a/test_regress/t/t_tagged_if.out +++ b/test_regress/t/t_tagged_if.out @@ -1,14 +1,14 @@ -%Error-UNSUPPORTED: t/t_tagged_if.v:218:37: Unsupported: &&& expression - 218 | if (instr matches tagged Jmp .j &&& +%Error-UNSUPPORTED: t/t_tagged_if.v:226:37: Unsupported: &&& expression + 226 | if (instr matches tagged Jmp .j &&& | ^~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_tagged_if.v:228:35: Unsupported: &&& expression - 228 | if (v matches tagged Valid .n &&& (n > 50)) +%Error-UNSUPPORTED: t/t_tagged_if.v:236:35: Unsupported: &&& expression + 236 | if (v matches tagged Valid .n &&& (n > 50)) | ^~~ -%Error-UNSUPPORTED: t/t_tagged_if.v:237:35: Unsupported: &&& expression - 237 | if (v matches tagged Valid .n &&& (n > 50)) +%Error-UNSUPPORTED: t/t_tagged_if.v:245:35: Unsupported: &&& expression + 245 | if (v matches tagged Valid .n &&& (n > 50)) | ^~~ -%Error-UNSUPPORTED: t/t_tagged_if.v:266:37: Unsupported: &&& expression - 266 | if (instr matches tagged Jmp .j &&& +%Error-UNSUPPORTED: t/t_tagged_if.v:274:37: Unsupported: &&& expression + 274 | if (instr matches tagged Jmp .j &&& | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_tagged_if.v b/test_regress/t/t_tagged_if.v index 46be66135..269219f9d 100644 --- a/test_regress/t/t_tagged_if.v +++ b/test_regress/t/t_tagged_if.v @@ -61,10 +61,12 @@ module t; } Instr; // Tagged union with chandle member +`ifndef QUESTA typedef union tagged { void Invalid; chandle Handle; } ChandleType; +`endif // Tagged union with class reference member typedef union tagged { @@ -108,7 +110,9 @@ module t; WideType wt; ArrayType at; Instr instr; +`ifndef QUESTA ChandleType cht; +`endif ClassType clt; TestClass obj; RealType rt; @@ -156,7 +160,9 @@ module t; wide60_result = w; else wide60_result = 0; +`ifndef QUESTA `checkh(wide60_result, 60'hFEDCBA987654321); +`endif // Test 5: Wide type if matching - 90-bit wt = tagged Wide90 (90'hDE_ADBEEFCA_FEBABE12_3456); @@ -165,7 +171,9 @@ module t; wide90_result = w; else wide90_result = 0; +`ifndef QUESTA `checkh(wide90_result, 90'hDE_ADBEEFCA_FEBABE12_3456); +`endif // Test 6: Non-zero LSB if match wt = tagged Byte8NonZeroLSB (8'hA5); @@ -291,6 +299,7 @@ module t; result = 2; `checkh(result, 1); +`ifndef QUESTA // Test 19: Chandle member if matching cht = tagged Invalid; result = 0; @@ -307,6 +316,7 @@ module t; else result = 2; `checkh(result, 1); +`endif // Test 20: Class reference member if matching obj = new(42); @@ -320,8 +330,8 @@ module t; clt = tagged Obj (obj); result = 0; - if (clt matches tagged Obj .o) - result = o.value; + if (clt matches tagged Obj) + result = 42; else result = -1; `checkh(result, 42); diff --git a/test_regress/t/t_tagged_union.out b/test_regress/t/t_tagged_union.out index ab08889dc..d31a3fdfa 100644 --- a/test_regress/t/t_tagged_union.out +++ b/test_regress/t/t_tagged_union.out @@ -8,145 +8,145 @@ %Error-UNSUPPORTED: t/t_tagged_union.v:57:5: Unsupported: void (for tagged unions) 57 | void Invalid; | ^~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:79:5: Unsupported: void (for tagged unions) - 79 | void Invalid; +%Error-UNSUPPORTED: t/t_tagged_union.v:80:5: Unsupported: void (for tagged unions) + 80 | void Invalid; | ^~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:85:5: Unsupported: void (for tagged unions) - 85 | void Invalid; +%Error-UNSUPPORTED: t/t_tagged_union.v:87:5: Unsupported: void (for tagged unions) + 87 | void Invalid; | ^~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:94:5: Unsupported: void (for tagged unions) - 94 | void Invalid; +%Error-UNSUPPORTED: t/t_tagged_union.v:96:5: Unsupported: void (for tagged unions) + 96 | void Invalid; | ^~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:101:5: Unsupported: void (for tagged unions) - 101 | void Invalid; +%Error-UNSUPPORTED: t/t_tagged_union.v:103:5: Unsupported: void (for tagged unions) + 103 | void Invalid; | ^~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:107:5: Unsupported: void (for tagged unions) - 107 | void Invalid; +%Error-UNSUPPORTED: t/t_tagged_union.v:109:5: Unsupported: void (for tagged unions) + 109 | void Invalid; | ^~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:116:5: Unsupported: void (for tagged unions) - 116 | void Invalid; +%Error-UNSUPPORTED: t/t_tagged_union.v:118:5: Unsupported: void (for tagged unions) + 118 | void Invalid; | ^~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:137:11: Unsupported: tagged union - 137 | vi1 = tagged Invalid; - | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:138:11: Unsupported: tagged union - 138 | vi2 = tagged Invalid; - | ^~~~~~ %Error-UNSUPPORTED: t/t_tagged_union.v:141:11: Unsupported: tagged union - 141 | vi1 = tagged Valid (42); + 141 | vi1 = tagged Invalid; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:144:11: Unsupported: tagged union - 144 | vi2 = tagged Valid (23 + 34); +%Error-UNSUPPORTED: t/t_tagged_union.v:142:11: Unsupported: tagged union + 142 | vi2 = tagged Invalid; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:148:10: Unsupported: tagged union - 148 | mt = tagged Invalid; +%Error-UNSUPPORTED: t/t_tagged_union.v:145:11: Unsupported: tagged union + 145 | vi1 = tagged Valid (42); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:148:11: Unsupported: tagged union + 148 | vi2 = tagged Valid (23 + 34); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:152:10: Unsupported: tagged union + 152 | mt = tagged Invalid; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:150:10: Unsupported: tagged union - 150 | mt = tagged IntVal (32'h12345678); +%Error-UNSUPPORTED: t/t_tagged_union.v:154:10: Unsupported: tagged union + 154 | mt = tagged IntVal (32'h12345678); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:153:10: Unsupported: tagged union - 153 | mt = tagged ShortVal (16'hABCD); +%Error-UNSUPPORTED: t/t_tagged_union.v:157:10: Unsupported: tagged union + 157 | mt = tagged ShortVal (16'hABCD); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:156:10: Unsupported: tagged union - 156 | mt = tagged ByteVal (8'h5A); - | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:159:10: Unsupported: tagged union - 159 | mt = tagged BitVal (1'b1); +%Error-UNSUPPORTED: t/t_tagged_union.v:160:10: Unsupported: tagged union + 160 | mt = tagged ByteVal (8'h5A); | ^~~~~~ %Error-UNSUPPORTED: t/t_tagged_union.v:163:10: Unsupported: tagged union - 163 | mt = tagged Byte8NonZeroLSB (8'hA5); + 163 | mt = tagged BitVal (1'b1); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:166:10: Unsupported: tagged union - 166 | mt = tagged Word16NonZeroLSB (16'h1234); +%Error-UNSUPPORTED: t/t_tagged_union.v:167:10: Unsupported: tagged union + 167 | mt = tagged Byte8NonZeroLSB (8'hA5); | ^~~~~~ %Error-UNSUPPORTED: t/t_tagged_union.v:170:10: Unsupported: tagged union - 170 | mt = tagged Word32LittleEndian (32'hDEADBEEF); + 170 | mt = tagged Word16NonZeroLSB (16'h1234); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:173:10: Unsupported: tagged union - 173 | mt = tagged Word16LittleEndian (16'hCAFE); +%Error-UNSUPPORTED: t/t_tagged_union.v:174:10: Unsupported: tagged union + 174 | mt = tagged Word32LittleEndian (32'hDEADBEEF); | ^~~~~~ %Error-UNSUPPORTED: t/t_tagged_union.v:177:10: Unsupported: tagged union - 177 | mt = tagged Wide60 (60'hFEDCBA987654321); + 177 | mt = tagged Word16LittleEndian (16'hCAFE); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:180:10: Unsupported: tagged union - 180 | mt = tagged Wide60NonZeroLSB (60'h123456789ABCDEF); +%Error-UNSUPPORTED: t/t_tagged_union.v:181:10: Unsupported: tagged union + 181 | mt = tagged Wide60 (60'hFEDCBA987654321); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:183:10: Unsupported: tagged union - 183 | mt = tagged Wide60LittleEndian (60'hABCDEF012345678); +%Error-UNSUPPORTED: t/t_tagged_union.v:184:10: Unsupported: tagged union + 184 | mt = tagged Wide60NonZeroLSB (60'h123456789ABCDEF); | ^~~~~~ %Error-UNSUPPORTED: t/t_tagged_union.v:187:10: Unsupported: tagged union - 187 | mt = tagged Wide90 (90'hFF_FFFFFFFF_FFFFFFFF_FFFF); + 187 | mt = tagged Wide60LittleEndian (60'hABCDEF012345678); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:190:10: Unsupported: tagged union - 190 | mt = tagged Wide90NonZeroLSB (90'hDE_ADBEEFCA_FEBABE12_3456); +%Error-UNSUPPORTED: t/t_tagged_union.v:191:10: Unsupported: tagged union + 191 | mt = tagged Wide90 (90'hFF_FFFFFFFF_FFFFFFFF_FFFF); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:193:10: Unsupported: tagged union - 193 | mt = tagged Wide90LittleEndian (90'h11_11111122_22222233_3333); +%Error-UNSUPPORTED: t/t_tagged_union.v:194:10: Unsupported: tagged union + 194 | mt = tagged Wide90NonZeroLSB (90'hDE_ADBEEFCA_FEBABE12_3456); | ^~~~~~ %Error-UNSUPPORTED: t/t_tagged_union.v:197:10: Unsupported: tagged union - 197 | at = tagged Invalid; + 197 | mt = tagged Wide90LittleEndian (90'h11_11111122_22222233_3333); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:199:10: Unsupported: tagged union - 199 | at = tagged Scalar (999); +%Error-UNSUPPORTED: t/t_tagged_union.v:201:10: Unsupported: tagged union + 201 | at = tagged Invalid; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:202:10: Unsupported: tagged union - 202 | at = tagged UnpackedArr '{100, 200, 300, 400}; +%Error-UNSUPPORTED: t/t_tagged_union.v:203:10: Unsupported: tagged union + 203 | at = tagged Scalar (999); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:208:10: Unsupported: tagged union - 208 | at = tagged UnpackedArr2D '{'{32'hA, 32'hB, 32'hC}, '{32'hD, 32'hE, 32'hF}}; +%Error-UNSUPPORTED: t/t_tagged_union.v:206:10: Unsupported: tagged union + 206 | at = tagged UnpackedArr '{100, 200, 300, 400}; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:217:13: Unsupported: tagged union - 217 | instr = tagged Add '{5'd1, 5'd2, 5'd3}; +%Error-UNSUPPORTED: t/t_tagged_union.v:212:10: Unsupported: tagged union + 212 | at = tagged UnpackedArr2D '{'{32'hA, 32'hB, 32'hC}, '{32'hD, 32'hE, 32'hF}}; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:221:13: Unsupported: tagged union + 221 | instr = tagged Add '{5'd1, 5'd2, 5'd3}; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:223:13: Unsupported: tagged union - 223 | instr = tagged Add '{reg2:5'd10, regd:5'd20, reg1:5'd5}; +%Error-UNSUPPORTED: t/t_tagged_union.v:227:13: Unsupported: tagged union + 227 | instr = tagged Add '{reg2:5'd10, regd:5'd20, reg1:5'd5}; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:229:13: Unsupported: tagged union - 229 | instr = tagged Jmp (tagged JmpU 10'd512); - | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:229:25: Unsupported: tagged union - 229 | instr = tagged Jmp (tagged JmpU 10'd512); - | ^~~~~~ %Error-UNSUPPORTED: t/t_tagged_union.v:233:13: Unsupported: tagged union - 233 | instr = tagged Jmp (tagged JmpC '{2'd1, 10'd256}); + 233 | instr = tagged Jmp (tagged JmpU 10'd512); | ^~~~~~ %Error-UNSUPPORTED: t/t_tagged_union.v:233:25: Unsupported: tagged union - 233 | instr = tagged Jmp (tagged JmpC '{2'd1, 10'd256}); + 233 | instr = tagged Jmp (tagged JmpU 10'd512); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:238:13: Unsupported: tagged union - 238 | instr = tagged Jmp (tagged JmpC '{cc:2'd3, addr:10'd100}); +%Error-UNSUPPORTED: t/t_tagged_union.v:237:13: Unsupported: tagged union + 237 | instr = tagged Jmp (tagged JmpC '{2'd1, 10'd256}); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:238:25: Unsupported: tagged union - 238 | instr = tagged Jmp (tagged JmpC '{cc:2'd3, addr:10'd100}); +%Error-UNSUPPORTED: t/t_tagged_union.v:237:25: Unsupported: tagged union + 237 | instr = tagged Jmp (tagged JmpC '{2'd1, 10'd256}); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:242:13: Unsupported: tagged union + 242 | instr = tagged Jmp (tagged JmpC '{cc:2'd3, addr:10'd100}); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:242:25: Unsupported: tagged union + 242 | instr = tagged Jmp (tagged JmpC '{cc:2'd3, addr:10'd100}); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:243:11: Unsupported: tagged union - 243 | cht = tagged Invalid; - | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:244:11: Unsupported: tagged union - 244 | cht = tagged Handle (null); - | ^~~~~~ %Error-UNSUPPORTED: t/t_tagged_union.v:248:11: Unsupported: tagged union - 248 | clt = tagged Invalid; + 248 | cht = tagged Invalid; | ^~~~~~ %Error-UNSUPPORTED: t/t_tagged_union.v:249:11: Unsupported: tagged union - 249 | clt = tagged Obj (obj); + 249 | cht = tagged Handle (null); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:253:10: Unsupported: tagged union - 253 | rt = tagged Invalid; +%Error-UNSUPPORTED: t/t_tagged_union.v:254:11: Unsupported: tagged union + 254 | clt = tagged Invalid; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:255:11: Unsupported: tagged union + 255 | clt = tagged Obj (obj); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged_union.v:259:10: Unsupported: tagged union + 259 | rt = tagged Invalid; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:254:10: Unsupported: tagged union - 254 | rt = tagged RealVal (3.14159); +%Error-UNSUPPORTED: t/t_tagged_union.v:260:10: Unsupported: tagged union + 260 | rt = tagged RealVal (3.14159); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:258:10: Unsupported: tagged union - 258 | rt = tagged ShortRealVal (2.5); +%Error-UNSUPPORTED: t/t_tagged_union.v:264:10: Unsupported: tagged union + 264 | rt = tagged ShortRealVal (2.5); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:262:10: Unsupported: tagged union - 262 | st = tagged Invalid; +%Error-UNSUPPORTED: t/t_tagged_union.v:268:10: Unsupported: tagged union + 268 | st = tagged Invalid; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:263:10: Unsupported: tagged union - 263 | st = tagged StrVal ("hello"); +%Error-UNSUPPORTED: t/t_tagged_union.v:269:10: Unsupported: tagged union + 269 | st = tagged StrVal ("hello"); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged_union.v:267:10: Unsupported: tagged union - 267 | et = tagged Invalid; +%Error-UNSUPPORTED: t/t_tagged_union.v:273:10: Unsupported: tagged union + 273 | et = tagged Invalid; | ^~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_tagged_union.v b/test_regress/t/t_tagged_union.v index 59642f503..4ce7fe866 100644 --- a/test_regress/t/t_tagged_union.v +++ b/test_regress/t/t_tagged_union.v @@ -75,10 +75,12 @@ module t; } Instr; // Tagged union with chandle member +`ifndef QUESTA typedef union tagged { void Invalid; chandle Handle; } ChandleType; +`endif // Tagged union with class reference member typedef union tagged { @@ -122,7 +124,9 @@ module t; MultiType mt; ArrayType at; Instr instr; +`ifndef QUESTA ChandleType cht; +`endif ClassType clt; TestClass obj; RealType rt; @@ -239,9 +243,11 @@ module t; `checkh(instr.Jmp.JmpC.cc, 2'd3); `checkh(instr.Jmp.JmpC.addr, 10'd100); +`ifndef QUESTA // Test 13: Chandle member cht = tagged Invalid; cht = tagged Handle (null); +`endif // Test 14: Class reference member obj = new(42); diff --git a/test_regress/t/t_unique0_case.py b/test_regress/t/t_unique0_case.py new file mode 100755 index 000000000..3626b338d --- /dev/null +++ b/test_regress/t/t_unique0_case.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios("simulator") + +test.compile(verilator_flags2=["--stats"]) + +test.execute() + +test.file_grep(test.stats, r"Assertions, lifted impure case expressions\s+(\d+)", 1) + +test.passes() diff --git a/test_regress/t/t_unique0_case.v b/test_regress/t/t_unique0_case.v new file mode 100644 index 000000000..ed3f92535 --- /dev/null +++ b/test_regress/t/t_unique0_case.v @@ -0,0 +1,38 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Antmicro +// SPDX-License-Identifier: CC0-1.0 + +// verilog_format: off +`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); +// verilog_format: on + +module t; + int x; + int y; + int z; + initial begin + y = 0; + x = 0; + z = 0; + unique0 case (increment_x()) + 1: begin + y = 1; + end + default: begin + z = 1; + end + endcase + `checkh(x, 32'h1); + `checkh(y, 32'h1); + `checkh(z, 32'h0); + $finish; + end + + function automatic integer increment_x(); + x = x + 1; + return x; + endfunction +endmodule diff --git a/test_regress/t/t_unoptflat_simple_3_bad.out b/test_regress/t/t_unoptflat_simple_3_bad.out index f5ef439ae..7e31eb84d 100644 --- a/test_regress/t/t_unoptflat_simple_3_bad.out +++ b/test_regress/t/t_unoptflat_simple_3_bad.out @@ -4,8 +4,8 @@ ... For warning description see https://verilator.org/warn/UNOPTFLAT?v=latest ... Use "/* verilator lint_off UNOPTFLAT */" and lint_on around source to disable this message. t/t_unoptflat_simple_3.v:16:14: Example path: t.x - t/t_unoptflat_simple_3.v:58:18: Example path: ASSIGNW - t/t_unoptflat_simple_3.v:56:21: Example path: t.__Vcellout__test1i__xvecout - t/t_unoptflat_simple_3.v:21:8: Example path: ASSIGNW + t/t_unoptflat_simple_3.v:76:18: Example path: ASSIGNW + t/t_unoptflat_simple_3.v:74:21: Example path: t.__Vcellout__test2i__xvecout + t/t_unoptflat_simple_3.v:27:8: Example path: ASSIGNW t/t_unoptflat_simple_3.v:16:14: Example path: t.x %Error: Exiting due to diff --git a/test_regress/t/t_virtual_interface_method_sched.py b/test_regress/t/t_virtual_interface_method_sched.py new file mode 100755 index 000000000..6ac2815da --- /dev/null +++ b/test_regress/t/t_virtual_interface_method_sched.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile(verilator_flags2=["--timing"]) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_virtual_interface_method_sched.v b/test_regress/t/t_virtual_interface_method_sched.v new file mode 100644 index 000000000..b6586f268 --- /dev/null +++ b/test_regress/t/t_virtual_interface_method_sched.v @@ -0,0 +1,85 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Antmicro +// SPDX-License-Identifier: CC0-1.0 + +class msg; + string context_name; + + function void set_context(string name); + context_name = name; + endfunction +endclass + +package helper_pkg; + int package_counter; + + function void bump(); + package_counter++; + endfunction +endpackage + +interface intf ( + output logic a, + output logic b +); + msg m; + event e; + + task go(); + helper_pkg::package_counter++; + go_helper(); + go_helper(); + endtask + + task go_helper(); + // verilator no_inline_task + m.set_context("go_helper"); + helper_pkg::bump(); + ->e; + a <= 1; + endtask +endinterface + +class driver; + virtual intf vif; + + function new(virtual intf vif); + this.vif = vif; + endfunction + + task go(); + vif.go(); + endtask +endclass + +module t; + wire a; + wire b; + virtual intf vif; + + intf i ( + a, + b + ); + + initial begin + driver d; + vif = t.i; + t.i.m = new; + d = new(t.i); + d.go(); + end + + always @(posedge a) begin + vif.b <= 1; + end + + always @(*) begin + if (a && b) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_vlcov_covergroup.annotate.out b/test_regress/t/t_vlcov_covergroup.annotate.out index b8616ad2d..16b86a66e 100644 --- a/test_regress/t/t_vlcov_covergroup.annotate.out +++ b/test_regress/t/t_vlcov_covergroup.annotate.out @@ -28,6 +28,14 @@ -000001 point: type=toggle comment=parity:0->1 hier=top.t -000000 point: type=toggle comment=parity:1->0 hier=top.t + typedef struct packed {logic m_p; logic h_mode;} cfg_t; +%000001 cfg_t s_cfg = '0; +-000001 point: type=line comment=block hier=top.t +-000000 point: type=toggle comment=s_cfg.h_mode:0->1 hier=top.t +-000000 point: type=toggle comment=s_cfg.h_mode:1->0 hier=top.t +-000000 point: type=toggle comment=s_cfg.m_p:0->1 hier=top.t +-000000 point: type=toggle comment=s_cfg.m_p:1->0 hier=top.t + // 2-way cross covergroup cg2; %000002 cp_addr: coverpoint addr {bins addr0 = {0}; bins addr1 = {1};} @@ -257,6 +265,12 @@ // cross: [addr1, write] option.per_instance = 1; // unsupported for cross - expect COVERIGN warning } + // Non-standard hierarchical reference as a cross item (an implicit coverpoint): + // accepted with NONSTD, but implicit coverpoints are unsupported so the whole + // cross is dropped (COVERIGN, suppressed here) - it contributes no bins. + /* verilator lint_off NONSTD */ + cross_hier: cross cp_addr, s_cfg.m_p; + /* verilator lint_on NONSTD */ endgroup // Covergroup with an unnamed cross - the cross is reported under the default name "cross" @@ -268,13 +282,13 @@ -000001 point: type=covergroup comment= hier=cg_unnamed_cross.cp_c.read -000001 point: type=covergroup comment= hier=cg_unnamed_cross.cp_c.write %000001 cross cp_a, cp_c; // no label: reported under the default cross name --000001 point: type=covergroup comment= hier=cg_unnamed_cross.__cross7.a0_x_read +-000001 point: type=covergroup comment= hier=cg_unnamed_cross.__cross8.a0_x_read // cross: [a0, read] --000000 point: type=covergroup comment= hier=cg_unnamed_cross.__cross7.a0_x_write +-000000 point: type=covergroup comment= hier=cg_unnamed_cross.__cross8.a0_x_write // cross: [a0, write] --000000 point: type=covergroup comment= hier=cg_unnamed_cross.__cross7.a1_x_read +-000000 point: type=covergroup comment= hier=cg_unnamed_cross.__cross8.a1_x_read // cross: [a1, read] --000001 point: type=covergroup comment= hier=cg_unnamed_cross.__cross7.a1_x_write +-000001 point: type=covergroup comment= hier=cg_unnamed_cross.__cross8.a1_x_write // cross: [a1, write] endgroup diff --git a/test_regress/t/t_vlcov_data_e.dat b/test_regress/t/t_vlcov_data_e.dat index 32c705c59..114d03f03 100644 --- a/test_regress/t/t_vlcov_data_e.dat +++ b/test_regress/t/t_vlcov_data_e.dat @@ -224,3 +224,4 @@ C 'ft/t_cover_line.vl83n10tlinepagev_line/toelsifS83-85htop.t' 1 C 'ft/t_cover_line.vl87n15tlinepagev_line/toelsifS87-89htop.t' 1 C 'ft/t_cover_line.vl91n15tlinepagev_line/toifS91-93htop.t' 1 C 'ft/t_cover_line.vl91n16tlinepagev_line/toelseS96-97htop.t' 7 +C 'ft/t_cover_line.vl91n16tlinepagev_line/totest,testS91-91htop.t' 5 diff --git a/test_regress/t/t_vlcov_hier_report.out b/test_regress/t/t_vlcov_hier_report.out index bc70aa8a1..1c37b8e6a 100644 --- a/test_regress/t/t_vlcov_hier_report.out +++ b/test_regress/t/t_vlcov_hier_report.out @@ -1,6 +1,6 @@ $ verilator_coverage --report summary t/t_vlcov_data_e.dat Coverage Summary: - line : 88.6% ( 39/ 44) + line : 88.9% ( 40/ 45) toggle : 33.3% ( 35/105) branch : 78.1% ( 50/ 64) expr : 66.7% ( 8/ 12) diff --git a/test_regress/t/t_vlcov_opt_branch.info.out b/test_regress/t/t_vlcov_opt_branch.info.out index 45d5b4627..f7850b8c9 100644 --- a/test_regress/t/t_vlcov_opt_branch.info.out +++ b/test_regress/t/t_vlcov_opt_branch.info.out @@ -1,32 +1,32 @@ TN:verilator_coverage SF:t/t_cover_line.v DA:56,10 -BRDA:56,0,0,10 -BRDA:56,0,1,0 +BRDA:56,0,if,10 +BRDA:56,0,else,0 DA:57,10 DA:58,10 DA:60,9 -BRDA:60,0,0,1 -BRDA:60,0,1,9 +BRDA:60,0,if,1 +BRDA:60,0,else,9 DA:61,9 -BRDA:61,0,0,1 -BRDA:61,0,1,9 +BRDA:61,0,if,1 +BRDA:61,0,else,9 DA:62,1 DA:63,1 DA:66,9 -BRDA:66,0,0,1 -BRDA:66,0,1,9 +BRDA:66,0,if,1 +BRDA:66,0,else,9 DA:67,9 -BRDA:67,0,0,1 -BRDA:67,0,1,9 +BRDA:67,0,if,1 +BRDA:67,0,else,9 DA:69,9 DA:70,9 DA:73,9 -BRDA:73,0,0,1 -BRDA:73,0,1,9 +BRDA:73,0,if,1 +BRDA:73,0,else,9 DA:74,9 -BRDA:74,0,0,1 -BRDA:74,0,1,9 +BRDA:74,0,if,1 +BRDA:74,0,else,9 DA:75,1 DA:76,1 DA:79,9 @@ -34,93 +34,93 @@ DA:80,9 DA:105,10 DA:106,10 DA:120,7 -BRDA:120,0,0,1 -BRDA:120,0,1,7 +BRDA:120,0,if,1 +BRDA:120,0,else,7 DA:121,1 DA:122,1 DA:141,18 -BRDA:141,0,0,2 -BRDA:141,0,1,18 +BRDA:141,0,if,2 +BRDA:141,0,else,18 DA:142,2 DA:166,20 -BRDA:166,0,0,0 -BRDA:166,0,1,20 +BRDA:166,0,if,0 +BRDA:166,0,else,20 DA:168,0 DA:170,18 -BRDA:170,0,0,2 -BRDA:170,0,1,18 +BRDA:170,0,if,2 +BRDA:170,0,else,18 DA:172,2 DA:190,1 -BRDA:190,0,0,1 -BRDA:190,0,1,0 +BRDA:190,0,if,1 +BRDA:190,0,else,0 DA:191,1 DA:195,11 -BRDA:195,0,0,11 -BRDA:195,0,1,0 +BRDA:195,0,if,11 +BRDA:195,0,else,0 DA:196,11 DA:200,11 -BRDA:200,0,0,11 -BRDA:200,0,1,0 +BRDA:200,0,if,11 +BRDA:200,0,else,0 DA:201,11 DA:222,10 -BRDA:222,0,0,1 -BRDA:222,0,1,10 +BRDA:222,0,if,1 +BRDA:222,0,else,10 DA:223,1 DA:225,10 -BRDA:225,0,0,1 -BRDA:225,0,1,10 +BRDA:225,0,if,1 +BRDA:225,0,else,10 DA:226,1 DA:253,9 -BRDA:253,0,0,1 -BRDA:253,0,1,9 +BRDA:253,0,if,1 +BRDA:253,0,else,9 DA:255,1 DA:256,1 -BRDA:256,0,0,0 -BRDA:256,0,1,1 +BRDA:256,0,if,0 +BRDA:256,0,else,1 DA:288,0 -BRDA:288,0,0,0 -BRDA:288,0,1,0 +BRDA:288,0,if,0 +BRDA:288,0,else,0 DA:289,0 DA:291,0 DA:292,0 DA:327,31 -BRDA:327,0,0,0 -BRDA:327,0,1,31 +BRDA:327,0,cond_then,0 +BRDA:327,0,cond_else,31 DA:328,28 -BRDA:328,0,0,3 -BRDA:328,0,1,28 +BRDA:328,0,cond_then,3 +BRDA:328,0,cond_else,28 DA:329,21 -BRDA:329,0,0,21 -BRDA:329,0,1,0 +BRDA:329,0,cond_then,21 +BRDA:329,0,cond_else,0 DA:331,7 -BRDA:331,0,0,3 -BRDA:331,0,1,7 +BRDA:331,0,cond_then,3 +BRDA:331,0,cond_else,7 DA:332,10 -BRDA:332,0,0,0 -BRDA:332,0,1,10 +BRDA:332,0,cond_then,0 +BRDA:332,0,cond_else,10 DA:334,19 -BRDA:334,0,0,12 -BRDA:334,0,1,19 -BRDA:334,0,2,7 -BRDA:334,0,3,5 +BRDA:334,0,cond_then,12 +BRDA:334,0,cond_else,19 +BRDA:334,0,cond_then,7 +BRDA:334,0,cond_else,5 DA:337,11 -BRDA:337,0,0,11 -BRDA:337,0,1,0 +BRDA:337,0,cond_then,11 +BRDA:337,0,cond_else,0 DA:343,11 -BRDA:343,0,0,10 -BRDA:343,0,1,11 +BRDA:343,0,cond_then,10 +BRDA:343,0,cond_else,11 DA:347,10 -BRDA:347,0,0,0 -BRDA:347,0,1,1 -BRDA:347,0,2,1 -BRDA:347,0,3,10 +BRDA:347,0,cond_then,0 +BRDA:347,0,cond_else,1 +BRDA:347,0,if,1 +BRDA:347,0,else,10 DA:348,10 DA:350,10 -BRDA:350,0,0,1 -BRDA:350,0,1,10 +BRDA:350,0,cond_then,1 +BRDA:350,0,cond_else,10 DA:360,11 -BRDA:360,0,0,0 -BRDA:360,0,1,11 +BRDA:360,0,if,0 +BRDA:360,0,else,11 DA:361,11 BRF:64 BRH:20 diff --git a/test_regress/t/t_vlcov_opt_expr.info.out b/test_regress/t/t_vlcov_opt_expr.info.out index 33c3c1c89..c83249652 100644 --- a/test_regress/t/t_vlcov_opt_expr.info.out +++ b/test_regress/t/t_vlcov_opt_expr.info.out @@ -1,23 +1,23 @@ TN:verilator_coverage SF:t/t_cover_line.v DA:331,7 -BRDA:331,0,0,7 -BRDA:331,0,1,3 +BRDA:331,0,(((cyc %25 32'sh3) == 32'sh0)==0) => 0,7 +BRDA:331,0,(((cyc %25 32'sh3) == 32'sh0)==1) => 1,3 DA:347,1 -BRDA:347,0,0,1 -BRDA:347,0,1,0 +BRDA:347,0,((cyc > 32'sh5)==0) => 0,1 +BRDA:347,0,((cyc > 32'sh5)==1) => 1,0 DA:350,10 -BRDA:350,0,0,10 -BRDA:350,0,1,1 +BRDA:350,0,((cyc == 32'sh2)==0) => 0,10 +BRDA:350,0,((cyc == 32'sh2)==1) => 1,1 DA:353,11 -BRDA:353,0,0,11 -BRDA:353,0,1,0 +BRDA:353,0,((i < 32'sh5)==0) => 0,11 +BRDA:353,0,((i < 32'sh5)==1) => 1,0 DA:356,11 -BRDA:356,0,0,0 -BRDA:356,0,1,11 +BRDA:356,0,((i > 32'sh4)==0) => 0,0 +BRDA:356,0,((i > 32'sh4)==1) => 1,11 DA:360,11 -BRDA:360,0,0,11 -BRDA:360,0,1,0 +BRDA:360,0,(k==0) => 0,11 +BRDA:360,0,(k==1) => 1,0 BRF:12 BRH:4 end_of_record diff --git a/test_regress/t/t_vlcov_opt_line.info.out b/test_regress/t/t_vlcov_opt_line.info.out index eaba1df5d..c744548c6 100644 --- a/test_regress/t/t_vlcov_opt_line.info.out +++ b/test_regress/t/t_vlcov_opt_line.info.out @@ -10,8 +10,9 @@ DA:87,1 DA:88,1 DA:89,1 DA:91,7 -BRDA:91,0,0,1 -BRDA:91,0,1,7 +BRDA:91,0,if,1 +BRDA:91,0,else,7 +BRDA:91,0,test_test,5 DA:92,1 DA:93,1 DA:96,7 @@ -75,13 +76,13 @@ DA:332,10 DA:346,11 DA:350,11 DA:353,55 -BRDA:353,0,0,11 -BRDA:353,0,1,55 +BRDA:353,0,block,11 +BRDA:353,0,block,55 DA:354,55 DA:356,44 -BRDA:356,0,0,11 -BRDA:356,0,1,44 +BRDA:356,0,block,11 +BRDA:356,0,block,44 DA:357,44 -BRF:6 +BRF:7 BRH:4 end_of_record diff --git a/test_regress/t/t_vlcov_opt_toggle.info.out b/test_regress/t/t_vlcov_opt_toggle.info.out index 7740e44dc..e44fbbbbe 100644 --- a/test_regress/t/t_vlcov_opt_toggle.info.out +++ b/test_regress/t/t_vlcov_opt_toggle.info.out @@ -3,14 +3,14 @@ SF:t/t_cover_line.v DA:12,19 DA:14,2 DA:20,11 -BRDA:20,0,0,11 -BRDA:20,0,1,5 -BRDA:20,0,2,2 -BRDA:20,0,3,1 -BRDA:20,0,4,0 -BRDA:20,0,5,0 -BRDA:20,0,6,0 -BRDA:20,0,7,0 +BRDA:20,0,cyc_copy[0],11 +BRDA:20,0,cyc_copy[1],5 +BRDA:20,0,cyc_copy[2],2 +BRDA:20,0,cyc_copy[3],1 +BRDA:20,0,cyc_copy[4],0 +BRDA:20,0,cyc_copy[5],0 +BRDA:20,0,cyc_copy[6],0 +BRDA:20,0,cyc_copy[7],0 DA:138,38 DA:139,4 DA:159,38 @@ -21,96 +21,96 @@ DA:241,19 DA:242,2 DA:261,19 DA:262,10 -BRDA:262,0,0,10 -BRDA:262,0,1,5 -BRDA:262,0,2,2 -BRDA:262,0,3,1 +BRDA:262,0,cyc4[0],10 +BRDA:262,0,cyc4[1],5 +BRDA:262,0,cyc4[2],2 +BRDA:262,0,cyc4[3],1 DA:309,19 -BRDA:309,0,0,19 -BRDA:309,0,1,11 -BRDA:309,0,2,0 -BRDA:309,0,3,0 -BRDA:309,0,4,0 -BRDA:309,0,5,0 -BRDA:309,0,6,0 -BRDA:309,0,7,0 -BRDA:309,0,8,0 -BRDA:309,0,9,0 -BRDA:309,0,10,0 -BRDA:309,0,11,0 -BRDA:309,0,12,5 -BRDA:309,0,13,0 -BRDA:309,0,14,0 -BRDA:309,0,15,0 -BRDA:309,0,16,0 -BRDA:309,0,17,0 -BRDA:309,0,18,0 -BRDA:309,0,19,0 -BRDA:309,0,20,0 -BRDA:309,0,21,0 -BRDA:309,0,22,0 -BRDA:309,0,23,2 -BRDA:309,0,24,0 -BRDA:309,0,25,0 -BRDA:309,0,26,1 -BRDA:309,0,27,0 -BRDA:309,0,28,0 -BRDA:309,0,29,0 -BRDA:309,0,30,0 -BRDA:309,0,31,0 -BRDA:309,0,32,0 +BRDA:309,0,clk,19 +BRDA:309,0,cyc[0],11 +BRDA:309,0,cyc[10],0 +BRDA:309,0,cyc[11],0 +BRDA:309,0,cyc[12],0 +BRDA:309,0,cyc[13],0 +BRDA:309,0,cyc[14],0 +BRDA:309,0,cyc[15],0 +BRDA:309,0,cyc[16],0 +BRDA:309,0,cyc[17],0 +BRDA:309,0,cyc[18],0 +BRDA:309,0,cyc[19],0 +BRDA:309,0,cyc[1],5 +BRDA:309,0,cyc[20],0 +BRDA:309,0,cyc[21],0 +BRDA:309,0,cyc[22],0 +BRDA:309,0,cyc[23],0 +BRDA:309,0,cyc[24],0 +BRDA:309,0,cyc[25],0 +BRDA:309,0,cyc[26],0 +BRDA:309,0,cyc[27],0 +BRDA:309,0,cyc[28],0 +BRDA:309,0,cyc[29],0 +BRDA:309,0,cyc[2],2 +BRDA:309,0,cyc[30],0 +BRDA:309,0,cyc[31],0 +BRDA:309,0,cyc[3],1 +BRDA:309,0,cyc[4],0 +BRDA:309,0,cyc[5],0 +BRDA:309,0,cyc[6],0 +BRDA:309,0,cyc[7],0 +BRDA:309,0,cyc[8],0 +BRDA:309,0,cyc[9],0 DA:310,19 -BRDA:310,0,0,0 -BRDA:310,0,1,2 -BRDA:310,0,2,19 -BRDA:310,0,3,6 -BRDA:310,0,4,7 -BRDA:310,0,5,1 -BRDA:310,0,6,19 -BRDA:310,0,7,3 -BRDA:310,0,8,0 -BRDA:310,0,9,0 -BRDA:310,0,10,0 +BRDA:310,0,a,0 +BRDA:310,0,b,2 +BRDA:310,0,c,19 +BRDA:310,0,d,6 +BRDA:310,0,e,7 +BRDA:310,0,f,1 +BRDA:310,0,g,19 +BRDA:310,0,h,3 +BRDA:310,0,k,0 +BRDA:310,0,l,0 +BRDA:310,0,m,0 DA:311,1 -BRDA:311,0,0,1 -BRDA:311,0,1,1 -BRDA:311,0,2,0 -BRDA:311,0,3,0 -BRDA:311,0,4,0 -BRDA:311,0,5,0 +BRDA:311,0,tab[0],1 +BRDA:311,0,tab[1],1 +BRDA:311,0,tab[2],0 +BRDA:311,0,tab[3],0 +BRDA:311,0,tab[4],0 +BRDA:311,0,tab[5],0 DA:313,2 -BRDA:313,0,0,0 -BRDA:313,0,1,2 -BRDA:313,0,2,0 -BRDA:313,0,3,0 -BRDA:313,0,4,0 -BRDA:313,0,5,0 -BRDA:313,0,6,0 -BRDA:313,0,7,0 -BRDA:313,0,8,2 -BRDA:313,0,9,0 -BRDA:313,0,10,0 -BRDA:313,0,11,0 -BRDA:313,0,12,0 -BRDA:313,0,13,0 -BRDA:313,0,14,0 -BRDA:313,0,15,0 -BRDA:313,0,16,0 -BRDA:313,0,17,0 -BRDA:313,0,18,0 -BRDA:313,0,19,0 -BRDA:313,0,20,0 -BRDA:313,0,21,0 -BRDA:313,0,22,0 -BRDA:313,0,23,0 -BRDA:313,0,24,0 -BRDA:313,0,25,0 -BRDA:313,0,26,0 -BRDA:313,0,27,0 -BRDA:313,0,28,0 -BRDA:313,0,29,0 -BRDA:313,0,30,0 -BRDA:313,0,31,0 +BRDA:313,0,data[0][0][0],0 +BRDA:313,0,data[0][0][1],2 +BRDA:313,0,data[0][0][2],0 +BRDA:313,0,data[0][0][3],0 +BRDA:313,0,data[0][0][4],0 +BRDA:313,0,data[0][0][5],0 +BRDA:313,0,data[0][0][6],0 +BRDA:313,0,data[0][0][7],0 +BRDA:313,0,data[0][1][0],2 +BRDA:313,0,data[0][1][1],0 +BRDA:313,0,data[0][1][2],0 +BRDA:313,0,data[0][1][3],0 +BRDA:313,0,data[0][1][4],0 +BRDA:313,0,data[0][1][5],0 +BRDA:313,0,data[0][1][6],0 +BRDA:313,0,data[0][1][7],0 +BRDA:313,0,data[1][0][0],0 +BRDA:313,0,data[1][0][1],0 +BRDA:313,0,data[1][0][2],0 +BRDA:313,0,data[1][0][3],0 +BRDA:313,0,data[1][0][4],0 +BRDA:313,0,data[1][0][5],0 +BRDA:313,0,data[1][0][6],0 +BRDA:313,0,data[1][0][7],0 +BRDA:313,0,data[1][1][0],0 +BRDA:313,0,data[1][1][1],0 +BRDA:313,0,data[1][1][2],0 +BRDA:313,0,data[1][1][3],0 +BRDA:313,0,data[1][1][4],0 +BRDA:313,0,data[1][1][5],0 +BRDA:313,0,data[1][1][6],0 +BRDA:313,0,data[1][1][7],0 BRF:94 BRH:6 end_of_record diff --git a/test_regress/t/t_vlcov_opt_user.info.out b/test_regress/t/t_vlcov_opt_user.info.out index e1b47061b..45fd8205a 100644 --- a/test_regress/t/t_vlcov_opt_user.info.out +++ b/test_regress/t/t_vlcov_opt_user.info.out @@ -1,180 +1,180 @@ TN:verilator_coverage SF:t/t_assert_ctl_arg.v DA:49,1 -BRDA:49,0,0,1 -BRDA:49,0,1,1 -BRDA:49,0,2,0 -BRDA:49,0,3,0 -BRDA:49,0,4,0 -BRDA:49,0,5,0 +BRDA:49,0,cover_simple_immediate_49,1 +BRDA:49,0,cover_simple_immediate_stmt_49,1 +BRDA:49,0,cover_final_deferred_immediate_49,0 +BRDA:49,0,cover_observed_deferred_immediate_49,0 +BRDA:49,0,cover_final_deferred_immediate_stmt_49,0 +BRDA:49,0,cover_observed_deferred_immediate_stmt_49,0 DA:51,0 -BRDA:51,0,0,0 -BRDA:51,0,1,0 -BRDA:51,0,2,0 -BRDA:51,0,3,0 -BRDA:51,0,4,0 -BRDA:51,0,5,0 +BRDA:51,0,cover_simple_immediate_51,0 +BRDA:51,0,cover_simple_immediate_stmt_51,0 +BRDA:51,0,cover_final_deferred_immediate_51,0 +BRDA:51,0,cover_observed_deferred_immediate_51,0 +BRDA:51,0,cover_final_deferred_immediate_stmt_51,0 +BRDA:51,0,cover_observed_deferred_immediate_stmt_51,0 DA:56,1 -BRDA:56,0,0,0 -BRDA:56,0,1,0 -BRDA:56,0,2,0 -BRDA:56,0,3,1 -BRDA:56,0,4,0 -BRDA:56,0,5,1 +BRDA:56,0,cover_simple_immediate_56,0 +BRDA:56,0,cover_simple_immediate_stmt_56,0 +BRDA:56,0,cover_final_deferred_immediate_56,0 +BRDA:56,0,cover_observed_deferred_immediate_56,1 +BRDA:56,0,cover_final_deferred_immediate_stmt_56,0 +BRDA:56,0,cover_observed_deferred_immediate_stmt_56,1 DA:58,0 -BRDA:58,0,0,0 -BRDA:58,0,1,0 -BRDA:58,0,2,0 -BRDA:58,0,3,0 -BRDA:58,0,4,0 -BRDA:58,0,5,0 +BRDA:58,0,cover_simple_immediate_58,0 +BRDA:58,0,cover_simple_immediate_stmt_58,0 +BRDA:58,0,cover_final_deferred_immediate_58,0 +BRDA:58,0,cover_observed_deferred_immediate_58,0 +BRDA:58,0,cover_final_deferred_immediate_stmt_58,0 +BRDA:58,0,cover_observed_deferred_immediate_stmt_58,0 DA:63,1 -BRDA:63,0,0,0 -BRDA:63,0,1,0 -BRDA:63,0,2,1 -BRDA:63,0,3,0 -BRDA:63,0,4,1 -BRDA:63,0,5,0 +BRDA:63,0,cover_simple_immediate_63,0 +BRDA:63,0,cover_simple_immediate_stmt_63,0 +BRDA:63,0,cover_final_deferred_immediate_63,1 +BRDA:63,0,cover_observed_deferred_immediate_63,0 +BRDA:63,0,cover_final_deferred_immediate_stmt_63,1 +BRDA:63,0,cover_observed_deferred_immediate_stmt_63,0 DA:65,0 -BRDA:65,0,0,0 -BRDA:65,0,1,0 -BRDA:65,0,2,0 -BRDA:65,0,3,0 -BRDA:65,0,4,0 -BRDA:65,0,5,0 +BRDA:65,0,cover_simple_immediate_65,0 +BRDA:65,0,cover_simple_immediate_stmt_65,0 +BRDA:65,0,cover_final_deferred_immediate_65,0 +BRDA:65,0,cover_observed_deferred_immediate_65,0 +BRDA:65,0,cover_final_deferred_immediate_stmt_65,0 +BRDA:65,0,cover_observed_deferred_immediate_stmt_65,0 DA:69,0 -BRDA:69,0,0,0 -BRDA:69,0,1,0 -BRDA:69,0,2,0 -BRDA:69,0,3,0 -BRDA:69,0,4,0 -BRDA:69,0,5,0 +BRDA:69,0,cover_simple_immediate_69,0 +BRDA:69,0,cover_simple_immediate_stmt_69,0 +BRDA:69,0,cover_final_deferred_immediate_69,0 +BRDA:69,0,cover_observed_deferred_immediate_69,0 +BRDA:69,0,cover_final_deferred_immediate_stmt_69,0 +BRDA:69,0,cover_observed_deferred_immediate_stmt_69,0 DA:71,1 -BRDA:71,0,0,1 -BRDA:71,0,1,1 -BRDA:71,0,2,1 -BRDA:71,0,3,1 -BRDA:71,0,4,1 -BRDA:71,0,5,1 +BRDA:71,0,cover_simple_immediate_71,1 +BRDA:71,0,cover_simple_immediate_stmt_71,1 +BRDA:71,0,cover_final_deferred_immediate_71,1 +BRDA:71,0,cover_observed_deferred_immediate_71,1 +BRDA:71,0,cover_final_deferred_immediate_stmt_71,1 +BRDA:71,0,cover_observed_deferred_immediate_stmt_71,1 DA:73,0 -BRDA:73,0,0,0 -BRDA:73,0,1,0 -BRDA:73,0,2,0 -BRDA:73,0,3,0 -BRDA:73,0,4,0 -BRDA:73,0,5,0 +BRDA:73,0,cover_simple_immediate_73,0 +BRDA:73,0,cover_simple_immediate_stmt_73,0 +BRDA:73,0,cover_final_deferred_immediate_73,0 +BRDA:73,0,cover_observed_deferred_immediate_73,0 +BRDA:73,0,cover_final_deferred_immediate_stmt_73,0 +BRDA:73,0,cover_observed_deferred_immediate_stmt_73,0 DA:76,1 -BRDA:76,0,0,1 -BRDA:76,0,1,1 -BRDA:76,0,2,0 -BRDA:76,0,3,1 -BRDA:76,0,4,0 -BRDA:76,0,5,1 +BRDA:76,0,cover_simple_immediate_76,1 +BRDA:76,0,cover_simple_immediate_stmt_76,1 +BRDA:76,0,cover_final_deferred_immediate_76,0 +BRDA:76,0,cover_observed_deferred_immediate_76,1 +BRDA:76,0,cover_final_deferred_immediate_stmt_76,0 +BRDA:76,0,cover_observed_deferred_immediate_stmt_76,1 DA:78,1 -BRDA:78,0,0,1 -BRDA:78,0,1,1 -BRDA:78,0,2,1 -BRDA:78,0,3,1 -BRDA:78,0,4,1 -BRDA:78,0,5,1 +BRDA:78,0,cover_simple_immediate_78,1 +BRDA:78,0,cover_simple_immediate_stmt_78,1 +BRDA:78,0,cover_final_deferred_immediate_78,1 +BRDA:78,0,cover_observed_deferred_immediate_78,1 +BRDA:78,0,cover_final_deferred_immediate_stmt_78,1 +BRDA:78,0,cover_observed_deferred_immediate_stmt_78,1 DA:80,1 -BRDA:80,0,0,1 -BRDA:80,0,1,1 -BRDA:80,0,2,0 -BRDA:80,0,3,0 -BRDA:80,0,4,0 -BRDA:80,0,5,0 +BRDA:80,0,cover_simple_immediate_80,1 +BRDA:80,0,cover_simple_immediate_stmt_80,1 +BRDA:80,0,cover_final_deferred_immediate_80,0 +BRDA:80,0,cover_observed_deferred_immediate_80,0 +BRDA:80,0,cover_final_deferred_immediate_stmt_80,0 +BRDA:80,0,cover_observed_deferred_immediate_stmt_80,0 DA:82,1 -BRDA:82,0,0,1 -BRDA:82,0,1,1 -BRDA:82,0,2,0 -BRDA:82,0,3,0 -BRDA:82,0,4,0 -BRDA:82,0,5,0 +BRDA:82,0,cover_simple_immediate_82,1 +BRDA:82,0,cover_simple_immediate_stmt_82,1 +BRDA:82,0,cover_final_deferred_immediate_82,0 +BRDA:82,0,cover_observed_deferred_immediate_82,0 +BRDA:82,0,cover_final_deferred_immediate_stmt_82,0 +BRDA:82,0,cover_observed_deferred_immediate_stmt_82,0 DA:84,0 -BRDA:84,0,0,0 -BRDA:84,0,1,0 -BRDA:84,0,2,0 -BRDA:84,0,3,0 -BRDA:84,0,4,0 -BRDA:84,0,5,0 +BRDA:84,0,cover_simple_immediate_84,0 +BRDA:84,0,cover_simple_immediate_stmt_84,0 +BRDA:84,0,cover_final_deferred_immediate_84,0 +BRDA:84,0,cover_observed_deferred_immediate_84,0 +BRDA:84,0,cover_final_deferred_immediate_stmt_84,0 +BRDA:84,0,cover_observed_deferred_immediate_stmt_84,0 DA:86,1 -BRDA:86,0,0,1 -BRDA:86,0,1,1 -BRDA:86,0,2,0 -BRDA:86,0,3,0 -BRDA:86,0,4,0 -BRDA:86,0,5,0 +BRDA:86,0,cover_simple_immediate_86,1 +BRDA:86,0,cover_simple_immediate_stmt_86,1 +BRDA:86,0,cover_final_deferred_immediate_86,0 +BRDA:86,0,cover_observed_deferred_immediate_86,0 +BRDA:86,0,cover_final_deferred_immediate_stmt_86,0 +BRDA:86,0,cover_observed_deferred_immediate_stmt_86,0 DA:88,0 -BRDA:88,0,0,0 -BRDA:88,0,1,0 -BRDA:88,0,2,0 -BRDA:88,0,3,0 -BRDA:88,0,4,0 -BRDA:88,0,5,0 +BRDA:88,0,cover_simple_immediate_88,0 +BRDA:88,0,cover_simple_immediate_stmt_88,0 +BRDA:88,0,cover_final_deferred_immediate_88,0 +BRDA:88,0,cover_observed_deferred_immediate_88,0 +BRDA:88,0,cover_final_deferred_immediate_stmt_88,0 +BRDA:88,0,cover_observed_deferred_immediate_stmt_88,0 DA:90,1 -BRDA:90,0,0,1 -BRDA:90,0,1,1 -BRDA:90,0,2,1 -BRDA:90,0,3,1 -BRDA:90,0,4,1 -BRDA:90,0,5,1 +BRDA:90,0,cover_simple_immediate_90,1 +BRDA:90,0,cover_simple_immediate_stmt_90,1 +BRDA:90,0,cover_final_deferred_immediate_90,1 +BRDA:90,0,cover_observed_deferred_immediate_90,1 +BRDA:90,0,cover_final_deferred_immediate_stmt_90,1 +BRDA:90,0,cover_observed_deferred_immediate_stmt_90,1 DA:92,0 -BRDA:92,0,0,0 -BRDA:92,0,1,0 -BRDA:92,0,2,0 -BRDA:92,0,3,0 -BRDA:92,0,4,0 -BRDA:92,0,5,0 +BRDA:92,0,cover_simple_immediate_92,0 +BRDA:92,0,cover_simple_immediate_stmt_92,0 +BRDA:92,0,cover_final_deferred_immediate_92,0 +BRDA:92,0,cover_observed_deferred_immediate_92,0 +BRDA:92,0,cover_final_deferred_immediate_stmt_92,0 +BRDA:92,0,cover_observed_deferred_immediate_stmt_92,0 DA:97,0 -BRDA:97,0,0,0 -BRDA:97,0,1,0 -BRDA:97,0,2,0 -BRDA:97,0,3,0 -BRDA:97,0,4,0 -BRDA:97,0,5,0 +BRDA:97,0,cover_simple_immediate_97,0 +BRDA:97,0,cover_simple_immediate_stmt_97,0 +BRDA:97,0,cover_final_deferred_immediate_97,0 +BRDA:97,0,cover_observed_deferred_immediate_97,0 +BRDA:97,0,cover_final_deferred_immediate_stmt_97,0 +BRDA:97,0,cover_observed_deferred_immediate_stmt_97,0 DA:100,1 -BRDA:100,0,0,1 -BRDA:100,0,1,1 -BRDA:100,0,2,1 -BRDA:100,0,3,1 -BRDA:100,0,4,1 -BRDA:100,0,5,1 +BRDA:100,0,cover_simple_immediate_100,1 +BRDA:100,0,cover_simple_immediate_stmt_100,1 +BRDA:100,0,cover_final_deferred_immediate_100,1 +BRDA:100,0,cover_observed_deferred_immediate_100,1 +BRDA:100,0,cover_final_deferred_immediate_stmt_100,1 +BRDA:100,0,cover_observed_deferred_immediate_stmt_100,1 DA:103,0 -BRDA:103,0,0,0 -BRDA:103,0,1,0 -BRDA:103,0,2,0 -BRDA:103,0,3,0 -BRDA:103,0,4,0 -BRDA:103,0,5,0 +BRDA:103,0,cover_simple_immediate_103,0 +BRDA:103,0,cover_simple_immediate_stmt_103,0 +BRDA:103,0,cover_final_deferred_immediate_103,0 +BRDA:103,0,cover_observed_deferred_immediate_103,0 +BRDA:103,0,cover_final_deferred_immediate_stmt_103,0 +BRDA:103,0,cover_observed_deferred_immediate_stmt_103,0 DA:106,1 -BRDA:106,0,0,1 -BRDA:106,0,1,1 -BRDA:106,0,2,1 -BRDA:106,0,3,1 -BRDA:106,0,4,1 -BRDA:106,0,5,1 +BRDA:106,0,cover_simple_immediate_106,1 +BRDA:106,0,cover_simple_immediate_stmt_106,1 +BRDA:106,0,cover_final_deferred_immediate_106,1 +BRDA:106,0,cover_observed_deferred_immediate_106,1 +BRDA:106,0,cover_final_deferred_immediate_stmt_106,1 +BRDA:106,0,cover_observed_deferred_immediate_stmt_106,1 DA:108,1 -BRDA:108,0,0,1 -BRDA:108,0,1,1 -BRDA:108,0,2,1 -BRDA:108,0,3,1 -BRDA:108,0,4,1 -BRDA:108,0,5,1 +BRDA:108,0,cover_simple_immediate_108,1 +BRDA:108,0,cover_simple_immediate_stmt_108,1 +BRDA:108,0,cover_final_deferred_immediate_108,1 +BRDA:108,0,cover_observed_deferred_immediate_108,1 +BRDA:108,0,cover_final_deferred_immediate_stmt_108,1 +BRDA:108,0,cover_observed_deferred_immediate_stmt_108,1 DA:110,0 -BRDA:110,0,0,0 -BRDA:110,0,1,0 -BRDA:110,0,2,0 -BRDA:110,0,3,0 -BRDA:110,0,4,0 -BRDA:110,0,5,0 +BRDA:110,0,cover_simple_immediate_110,0 +BRDA:110,0,cover_simple_immediate_stmt_110,0 +BRDA:110,0,cover_final_deferred_immediate_110,0 +BRDA:110,0,cover_observed_deferred_immediate_110,0 +BRDA:110,0,cover_final_deferred_immediate_stmt_110,0 +BRDA:110,0,cover_observed_deferred_immediate_stmt_110,0 DA:112,1 -BRDA:112,0,0,1 -BRDA:112,0,1,1 -BRDA:112,0,2,1 -BRDA:112,0,3,0 -BRDA:112,0,4,1 -BRDA:112,0,5,0 +BRDA:112,0,cover_simple_immediate_112,1 +BRDA:112,0,cover_simple_immediate_stmt_112,1 +BRDA:112,0,cover_final_deferred_immediate_112,1 +BRDA:112,0,cover_observed_deferred_immediate_112,0 +BRDA:112,0,cover_final_deferred_immediate_stmt_112,1 +BRDA:112,0,cover_observed_deferred_immediate_stmt_112,0 DA:192,0 DA:193,0 BRF:150 diff --git a/test_regress/t/t_vlcov_opt_wild.info.out b/test_regress/t/t_vlcov_opt_wild.info.out index efcf737f6..8d8af4f6f 100644 --- a/test_regress/t/t_vlcov_opt_wild.info.out +++ b/test_regress/t/t_vlcov_opt_wild.info.out @@ -5,42 +5,42 @@ DA:14,2 DA:15,1 DA:18,1 DA:20,11 -BRDA:20,0,0,11 -BRDA:20,0,1,5 -BRDA:20,0,2,2 -BRDA:20,0,3,1 -BRDA:20,0,4,0 -BRDA:20,0,5,0 -BRDA:20,0,6,0 -BRDA:20,0,7,0 +BRDA:20,0,cyc_copy[0],11 +BRDA:20,0,cyc_copy[1],5 +BRDA:20,0,cyc_copy[2],2 +BRDA:20,0,cyc_copy[3],1 +BRDA:20,0,cyc_copy[4],0 +BRDA:20,0,cyc_copy[5],0 +BRDA:20,0,cyc_copy[6],0 +BRDA:20,0,cyc_copy[7],0 DA:55,10 DA:56,10 -BRDA:56,0,0,10 -BRDA:56,0,1,0 +BRDA:56,0,if,10 +BRDA:56,0,else,0 DA:57,10 DA:58,10 DA:60,9 -BRDA:60,0,0,1 -BRDA:60,0,1,9 +BRDA:60,0,if,1 +BRDA:60,0,else,9 DA:61,9 -BRDA:61,0,0,1 -BRDA:61,0,1,9 +BRDA:61,0,if,1 +BRDA:61,0,else,9 DA:62,1 DA:63,1 DA:66,9 -BRDA:66,0,0,1 -BRDA:66,0,1,9 +BRDA:66,0,if,1 +BRDA:66,0,else,9 DA:67,9 -BRDA:67,0,0,1 -BRDA:67,0,1,9 +BRDA:67,0,if,1 +BRDA:67,0,else,9 DA:69,9 DA:70,9 DA:73,9 -BRDA:73,0,0,1 -BRDA:73,0,1,9 +BRDA:73,0,if,1 +BRDA:73,0,else,9 DA:74,9 -BRDA:74,0,0,1 -BRDA:74,0,1,9 +BRDA:74,0,if,1 +BRDA:74,0,else,9 DA:75,1 DA:76,1 DA:79,9 @@ -52,8 +52,9 @@ DA:87,1 DA:88,1 DA:89,1 DA:91,7 -BRDA:91,0,0,1 -BRDA:91,0,1,7 +BRDA:91,0,if,1 +BRDA:91,0,else,7 +BRDA:91,0,test_test,5 DA:92,1 DA:93,1 DA:96,7 @@ -63,19 +64,19 @@ DA:101,0 DA:102,0 DA:104,0 DA:105,10 -BRDA:105,0,0,0 -BRDA:105,0,1,10 +BRDA:105,0,block,0 +BRDA:105,0,if,10 DA:106,10 -BRDA:106,0,0,0 -BRDA:106,0,1,10 +BRDA:106,0,block,0 +BRDA:106,0,if,10 DA:107,0 DA:110,1 DA:111,1 DA:113,1 DA:115,1 DA:120,7 -BRDA:120,0,0,1 -BRDA:120,0,1,7 +BRDA:120,0,if,1 +BRDA:120,0,else,7 DA:121,1 DA:122,1 DA:127,1 @@ -84,8 +85,8 @@ DA:138,38 DA:139,4 DA:140,20 DA:141,18 -BRDA:141,0,0,2 -BRDA:141,0,1,18 +BRDA:141,0,if,2 +BRDA:141,0,else,18 DA:142,2 DA:145,18 DA:159,38 @@ -93,29 +94,29 @@ DA:160,4 DA:164,20 DA:165,20 DA:166,20 -BRDA:166,0,0,0 -BRDA:166,0,1,20 +BRDA:166,0,if,0 +BRDA:166,0,else,20 DA:168,0 DA:170,18 -BRDA:170,0,0,2 -BRDA:170,0,1,18 +BRDA:170,0,if,2 +BRDA:170,0,else,18 DA:172,2 DA:174,18 DA:188,1 DA:189,1 DA:190,1 -BRDA:190,0,0,1 -BRDA:190,0,1,0 +BRDA:190,0,if,1 +BRDA:190,0,else,0 DA:191,1 DA:194,11 DA:195,11 -BRDA:195,0,0,11 -BRDA:195,0,1,0 +BRDA:195,0,if,11 +BRDA:195,0,else,0 DA:196,11 DA:199,11 DA:200,11 -BRDA:200,0,0,11 -BRDA:200,0,1,0 +BRDA:200,0,if,11 +BRDA:200,0,else,0 DA:201,11 DA:210,19 DA:211,2 @@ -124,12 +125,12 @@ DA:216,10 DA:219,11 DA:221,11 DA:222,10 -BRDA:222,0,0,1 -BRDA:222,0,1,10 +BRDA:222,0,if,1 +BRDA:222,0,else,10 DA:223,1 DA:225,10 -BRDA:225,0,0,1 -BRDA:225,0,1,10 +BRDA:225,0,if,1 +BRDA:225,0,else,10 DA:226,1 DA:229,11 DA:230,1 @@ -139,18 +140,18 @@ DA:241,19 DA:242,2 DA:252,10 DA:253,9 -BRDA:253,0,0,1 -BRDA:253,0,1,9 +BRDA:253,0,if,1 +BRDA:253,0,else,9 DA:255,1 DA:256,1 -BRDA:256,0,0,0 -BRDA:256,0,1,1 +BRDA:256,0,if,0 +BRDA:256,0,else,1 DA:261,19 DA:262,10 -BRDA:262,0,0,10 -BRDA:262,0,1,5 -BRDA:262,0,2,2 -BRDA:262,0,3,1 +BRDA:262,0,cyc4[0],10 +BRDA:262,0,cyc4[1],5 +BRDA:262,0,cyc4[2],2 +BRDA:262,0,cyc4[3],1 DA:265,10 DA:266,10 DA:267,1 @@ -163,8 +164,8 @@ DA:276,10 DA:277,10 DA:287,0 DA:288,0 -BRDA:288,0,0,0 -BRDA:288,0,1,0 +BRDA:288,0,if,0 +BRDA:288,0,else,0 DA:289,0 DA:291,0 DA:292,0 @@ -174,91 +175,91 @@ DA:303,1 DA:304,20 DA:305,20 DA:309,19 -BRDA:309,0,0,19 -BRDA:309,0,1,11 -BRDA:309,0,2,0 -BRDA:309,0,3,0 -BRDA:309,0,4,0 -BRDA:309,0,5,0 -BRDA:309,0,6,0 -BRDA:309,0,7,0 -BRDA:309,0,8,0 -BRDA:309,0,9,0 -BRDA:309,0,10,0 -BRDA:309,0,11,0 -BRDA:309,0,12,5 -BRDA:309,0,13,0 -BRDA:309,0,14,0 -BRDA:309,0,15,0 -BRDA:309,0,16,0 -BRDA:309,0,17,0 -BRDA:309,0,18,0 -BRDA:309,0,19,0 -BRDA:309,0,20,0 -BRDA:309,0,21,0 -BRDA:309,0,22,0 -BRDA:309,0,23,2 -BRDA:309,0,24,0 -BRDA:309,0,25,0 -BRDA:309,0,26,1 -BRDA:309,0,27,0 -BRDA:309,0,28,0 -BRDA:309,0,29,0 -BRDA:309,0,30,0 -BRDA:309,0,31,0 -BRDA:309,0,32,0 +BRDA:309,0,clk,19 +BRDA:309,0,cyc[0],11 +BRDA:309,0,cyc[10],0 +BRDA:309,0,cyc[11],0 +BRDA:309,0,cyc[12],0 +BRDA:309,0,cyc[13],0 +BRDA:309,0,cyc[14],0 +BRDA:309,0,cyc[15],0 +BRDA:309,0,cyc[16],0 +BRDA:309,0,cyc[17],0 +BRDA:309,0,cyc[18],0 +BRDA:309,0,cyc[19],0 +BRDA:309,0,cyc[1],5 +BRDA:309,0,cyc[20],0 +BRDA:309,0,cyc[21],0 +BRDA:309,0,cyc[22],0 +BRDA:309,0,cyc[23],0 +BRDA:309,0,cyc[24],0 +BRDA:309,0,cyc[25],0 +BRDA:309,0,cyc[26],0 +BRDA:309,0,cyc[27],0 +BRDA:309,0,cyc[28],0 +BRDA:309,0,cyc[29],0 +BRDA:309,0,cyc[2],2 +BRDA:309,0,cyc[30],0 +BRDA:309,0,cyc[31],0 +BRDA:309,0,cyc[3],1 +BRDA:309,0,cyc[4],0 +BRDA:309,0,cyc[5],0 +BRDA:309,0,cyc[6],0 +BRDA:309,0,cyc[7],0 +BRDA:309,0,cyc[8],0 +BRDA:309,0,cyc[9],0 DA:310,19 -BRDA:310,0,0,0 -BRDA:310,0,1,2 -BRDA:310,0,2,19 -BRDA:310,0,3,6 -BRDA:310,0,4,7 -BRDA:310,0,5,1 -BRDA:310,0,6,19 -BRDA:310,0,7,3 -BRDA:310,0,8,0 -BRDA:310,0,9,0 -BRDA:310,0,10,0 +BRDA:310,0,a,0 +BRDA:310,0,b,2 +BRDA:310,0,c,19 +BRDA:310,0,d,6 +BRDA:310,0,e,7 +BRDA:310,0,f,1 +BRDA:310,0,g,19 +BRDA:310,0,h,3 +BRDA:310,0,k,0 +BRDA:310,0,l,0 +BRDA:310,0,m,0 DA:311,1 -BRDA:311,0,0,1 -BRDA:311,0,1,1 -BRDA:311,0,2,0 -BRDA:311,0,3,0 -BRDA:311,0,4,0 -BRDA:311,0,5,0 +BRDA:311,0,tab[0],1 +BRDA:311,0,tab[1],1 +BRDA:311,0,tab[2],0 +BRDA:311,0,tab[3],0 +BRDA:311,0,tab[4],0 +BRDA:311,0,tab[5],0 DA:313,2 -BRDA:313,0,0,0 -BRDA:313,0,1,2 -BRDA:313,0,2,0 -BRDA:313,0,3,0 -BRDA:313,0,4,0 -BRDA:313,0,5,0 -BRDA:313,0,6,0 -BRDA:313,0,7,0 -BRDA:313,0,8,2 -BRDA:313,0,9,0 -BRDA:313,0,10,0 -BRDA:313,0,11,0 -BRDA:313,0,12,0 -BRDA:313,0,13,0 -BRDA:313,0,14,0 -BRDA:313,0,15,0 -BRDA:313,0,16,0 -BRDA:313,0,17,0 -BRDA:313,0,18,0 -BRDA:313,0,19,0 -BRDA:313,0,20,0 -BRDA:313,0,21,0 -BRDA:313,0,22,0 -BRDA:313,0,23,0 -BRDA:313,0,24,0 -BRDA:313,0,25,0 -BRDA:313,0,26,0 -BRDA:313,0,27,0 -BRDA:313,0,28,0 -BRDA:313,0,29,0 -BRDA:313,0,30,0 -BRDA:313,0,31,0 +BRDA:313,0,data[0][0][0],0 +BRDA:313,0,data[0][0][1],2 +BRDA:313,0,data[0][0][2],0 +BRDA:313,0,data[0][0][3],0 +BRDA:313,0,data[0][0][4],0 +BRDA:313,0,data[0][0][5],0 +BRDA:313,0,data[0][0][6],0 +BRDA:313,0,data[0][0][7],0 +BRDA:313,0,data[0][1][0],2 +BRDA:313,0,data[0][1][1],0 +BRDA:313,0,data[0][1][2],0 +BRDA:313,0,data[0][1][3],0 +BRDA:313,0,data[0][1][4],0 +BRDA:313,0,data[0][1][5],0 +BRDA:313,0,data[0][1][6],0 +BRDA:313,0,data[0][1][7],0 +BRDA:313,0,data[1][0][0],0 +BRDA:313,0,data[1][0][1],0 +BRDA:313,0,data[1][0][2],0 +BRDA:313,0,data[1][0][3],0 +BRDA:313,0,data[1][0][4],0 +BRDA:313,0,data[1][0][5],0 +BRDA:313,0,data[1][0][6],0 +BRDA:313,0,data[1][0][7],0 +BRDA:313,0,data[1][1][0],0 +BRDA:313,0,data[1][1][1],0 +BRDA:313,0,data[1][1][2],0 +BRDA:313,0,data[1][1][3],0 +BRDA:313,0,data[1][1][4],0 +BRDA:313,0,data[1][1][5],0 +BRDA:313,0,data[1][1][6],0 +BRDA:313,0,data[1][1][7],0 DA:314,1 DA:317,21 DA:318,21 @@ -266,69 +267,69 @@ DA:319,21 DA:322,10 DA:324,10 DA:327,31 -BRDA:327,0,0,0 -BRDA:327,0,1,31 +BRDA:327,0,cond_then,0 +BRDA:327,0,cond_else,31 DA:328,28 -BRDA:328,0,0,3 -BRDA:328,0,1,28 +BRDA:328,0,cond_then,3 +BRDA:328,0,cond_else,28 DA:329,21 -BRDA:329,0,0,21 -BRDA:329,0,1,0 +BRDA:329,0,cond_then,21 +BRDA:329,0,cond_else,0 DA:330,10 DA:331,10 -BRDA:331,0,0,10 -BRDA:331,0,1,7 -BRDA:331,0,2,3 -BRDA:331,0,3,3 -BRDA:331,0,4,7 +BRDA:331,0,block,10 +BRDA:331,0,(((cyc %25 32'sh3) == 32'sh0)==0) => 0,7 +BRDA:331,0,(((cyc %25 32'sh3) == 32'sh0)==1) => 1,3 +BRDA:331,0,cond_then,3 +BRDA:331,0,cond_else,7 DA:332,10 -BRDA:332,0,0,10 -BRDA:332,0,1,0 -BRDA:332,0,2,10 +BRDA:332,0,block,10 +BRDA:332,0,cond_then,0 +BRDA:332,0,cond_else,10 DA:334,19 -BRDA:334,0,0,12 -BRDA:334,0,1,19 -BRDA:334,0,2,7 -BRDA:334,0,3,5 +BRDA:334,0,cond_then,12 +BRDA:334,0,cond_else,19 +BRDA:334,0,cond_then,7 +BRDA:334,0,cond_else,5 DA:337,11 -BRDA:337,0,0,11 -BRDA:337,0,1,0 +BRDA:337,0,cond_then,11 +BRDA:337,0,cond_else,0 DA:343,11 -BRDA:343,0,0,10 -BRDA:343,0,1,11 +BRDA:343,0,cond_then,10 +BRDA:343,0,cond_else,11 DA:346,11 DA:347,10 -BRDA:347,0,0,1 -BRDA:347,0,1,0 -BRDA:347,0,2,0 -BRDA:347,0,3,1 -BRDA:347,0,4,1 -BRDA:347,0,5,10 +BRDA:347,0,((cyc > 32'sh5)==0) => 0,1 +BRDA:347,0,((cyc > 32'sh5)==1) => 1,0 +BRDA:347,0,cond_then,0 +BRDA:347,0,cond_else,1 +BRDA:347,0,if,1 +BRDA:347,0,else,10 DA:348,10 DA:350,11 -BRDA:350,0,0,11 -BRDA:350,0,1,10 -BRDA:350,0,2,1 -BRDA:350,0,3,1 -BRDA:350,0,4,10 +BRDA:350,0,block,11 +BRDA:350,0,((cyc == 32'sh2)==0) => 0,10 +BRDA:350,0,((cyc == 32'sh2)==1) => 1,1 +BRDA:350,0,cond_then,1 +BRDA:350,0,cond_else,10 DA:353,55 -BRDA:353,0,0,11 -BRDA:353,0,1,11 -BRDA:353,0,2,0 -BRDA:353,0,3,55 +BRDA:353,0,block,11 +BRDA:353,0,((i < 32'sh5)==0) => 0,11 +BRDA:353,0,((i < 32'sh5)==1) => 1,0 +BRDA:353,0,block,55 DA:354,55 DA:356,44 -BRDA:356,0,0,11 -BRDA:356,0,1,0 -BRDA:356,0,2,11 -BRDA:356,0,3,44 +BRDA:356,0,block,11 +BRDA:356,0,((i > 32'sh4)==0) => 0,0 +BRDA:356,0,((i > 32'sh4)==1) => 1,11 +BRDA:356,0,block,44 DA:357,44 DA:360,11 -BRDA:360,0,0,11 -BRDA:360,0,1,0 -BRDA:360,0,2,0 -BRDA:360,0,3,11 +BRDA:360,0,(k==0) => 0,11 +BRDA:360,0,(k==1) => 1,0 +BRDA:360,0,if,0 +BRDA:360,0,else,11 DA:361,11 -BRF:183 +BRF:184 BRH:39 end_of_record diff --git a/test_regress/t/t_vlcov_summary_typed.out b/test_regress/t/t_vlcov_summary_typed.out index e4b3d14f6..f9700d96d 100644 --- a/test_regress/t/t_vlcov_summary_typed.out +++ b/test_regress/t/t_vlcov_summary_typed.out @@ -1,5 +1,5 @@ Coverage Summary: - line : 88.6% ( 39/ 44) + line : 88.9% ( 40/ 45) toggle : 33.3% ( 35/105) branch : 78.1% ( 50/ 64) expr : 66.7% ( 8/ 12) diff --git a/test_regress/t/t_vpi_force.v b/test_regress/t/t_vpi_force.v index ae4913926..fcfa1b5fb 100644 --- a/test_regress/t/t_vpi_force.v +++ b/test_regress/t/t_vpi_force.v @@ -175,8 +175,7 @@ typedef enum byte { // - Continuous assignments do not work // - vpi_handle_by_multi_index is not implemented // - vpi_handle_by_name and vpi_handle_by_index fail with negative indices - // Hence, these signals are excluded from testing with Icarus. Recommend - // Xcelium for cross-checking results. + // Hence, these signals are excluded from testing with Icarus. `ifndef IVERILOG // Force the entire packed array (no partial forcing possible, because // partial indexing only works for bits, not dimension slices) @@ -2422,10 +2421,8 @@ $dumpfile(`STRINGIFY(`TEST_DUMPFILE)); svReleaseValues(); #8 svCheckValuesReleased(); - // Icarus does not support forcing single bits through VPI -`ifndef IVERILOG - // Xcelium supports forcing single bits through VPI, but crashes on some signals -`ifndef XRUN +`ifndef IVERILOG // Does not support forcing single bits through VPI +`ifndef XRUN // Supports forcing single bits through VPI, but crashes on some signals // Force single bit through VPI, release through VPI if (`verbose) $display("*** Forcing single bit through VPI, releasing through VPI ***"); diff --git a/test_regress/t/t_x_rand_mt_stability.out b/test_regress/t/t_x_rand_mt_stability.out index 30d041b29..cf0f962d9 100644 --- a/test_regress/t/t_x_rand_mt_stability.out +++ b/test_regress/t/t_x_rand_mt_stability.out @@ -3,8 +3,8 @@ x_assigned (initial) = 0x00000000 uninitialized2 = 0xdf5768de big = 0x355d75711c3bf0ca3e65805db585c43beae34b336b9dbe44a2d040cbe101a665 random_init = 0x5fa24450 -top.t.the_sub_yes_inline_1 no_init 0x842cd8b1033a58 top.t.the_sub_yes_inline_2 no_init 0xa36c65459f4b9f46 +top.t.the_sub_yes_inline_1 no_init 0x842cd8b1033a58 top.t.the_sub_no_inline_1 no_init 0x42d55205d10c58f8 top.t.the_sub_no_inline_2 no_init 0xac98037e5042d96d rand = 0x5fa24450 diff --git a/test_regress/t/t_x_rand_mt_stability_add.out b/test_regress/t/t_x_rand_mt_stability_add.out index 30d041b29..cf0f962d9 100644 --- a/test_regress/t/t_x_rand_mt_stability_add.out +++ b/test_regress/t/t_x_rand_mt_stability_add.out @@ -3,8 +3,8 @@ x_assigned (initial) = 0x00000000 uninitialized2 = 0xdf5768de big = 0x355d75711c3bf0ca3e65805db585c43beae34b336b9dbe44a2d040cbe101a665 random_init = 0x5fa24450 -top.t.the_sub_yes_inline_1 no_init 0x842cd8b1033a58 top.t.the_sub_yes_inline_2 no_init 0xa36c65459f4b9f46 +top.t.the_sub_yes_inline_1 no_init 0x842cd8b1033a58 top.t.the_sub_no_inline_1 no_init 0x42d55205d10c58f8 top.t.the_sub_no_inline_2 no_init 0xac98037e5042d96d rand = 0x5fa24450 diff --git a/test_regress/t/t_x_rand_mt_stability_add_trace.out b/test_regress/t/t_x_rand_mt_stability_add_trace.out index 30d041b29..cf0f962d9 100644 --- a/test_regress/t/t_x_rand_mt_stability_add_trace.out +++ b/test_regress/t/t_x_rand_mt_stability_add_trace.out @@ -3,8 +3,8 @@ x_assigned (initial) = 0x00000000 uninitialized2 = 0xdf5768de big = 0x355d75711c3bf0ca3e65805db585c43beae34b336b9dbe44a2d040cbe101a665 random_init = 0x5fa24450 -top.t.the_sub_yes_inline_1 no_init 0x842cd8b1033a58 top.t.the_sub_yes_inline_2 no_init 0xa36c65459f4b9f46 +top.t.the_sub_yes_inline_1 no_init 0x842cd8b1033a58 top.t.the_sub_no_inline_1 no_init 0x42d55205d10c58f8 top.t.the_sub_no_inline_2 no_init 0xac98037e5042d96d rand = 0x5fa24450 diff --git a/test_regress/t/t_x_rand_mt_stability_trace.out b/test_regress/t/t_x_rand_mt_stability_trace.out index 30d041b29..cf0f962d9 100644 --- a/test_regress/t/t_x_rand_mt_stability_trace.out +++ b/test_regress/t/t_x_rand_mt_stability_trace.out @@ -3,8 +3,8 @@ x_assigned (initial) = 0x00000000 uninitialized2 = 0xdf5768de big = 0x355d75711c3bf0ca3e65805db585c43beae34b336b9dbe44a2d040cbe101a665 random_init = 0x5fa24450 -top.t.the_sub_yes_inline_1 no_init 0x842cd8b1033a58 top.t.the_sub_yes_inline_2 no_init 0xa36c65459f4b9f46 +top.t.the_sub_yes_inline_1 no_init 0x842cd8b1033a58 top.t.the_sub_no_inline_1 no_init 0x42d55205d10c58f8 top.t.the_sub_no_inline_2 no_init 0xac98037e5042d96d rand = 0x5fa24450 diff --git a/test_regress/t/t_x_rand_mt_stability_zeros.out b/test_regress/t/t_x_rand_mt_stability_zeros.out index 2b3a3a882..eaac43644 100644 --- a/test_regress/t/t_x_rand_mt_stability_zeros.out +++ b/test_regress/t/t_x_rand_mt_stability_zeros.out @@ -3,8 +3,8 @@ x_assigned (initial) = 0x00000000 uninitialized2 = 0x00000000 big = 0x0000000000000000000000000000000000000000000000000000000000000000 random_init = 0x5fa24450 -top.t.the_sub_yes_inline_1 no_init 0x0 top.t.the_sub_yes_inline_2 no_init 0x0 +top.t.the_sub_yes_inline_1 no_init 0x0 top.t.the_sub_no_inline_1 no_init 0x0 top.t.the_sub_no_inline_2 no_init 0x0 rand = 0x5fa24450 diff --git a/test_regress/t/t_x_rand_stability.out b/test_regress/t/t_x_rand_stability.out index 1db7b9396..eaa53dd1f 100644 --- a/test_regress/t/t_x_rand_stability.out +++ b/test_regress/t/t_x_rand_stability.out @@ -3,8 +3,8 @@ x_assigned (initial) = 0x00000000 uninitialized2 = 0xdf5768de big = 0x355d75711c3bf0ca3e65805db585c43beae34b336b9dbe44a2d040cbe101a665 random_init = 0x5fa24450 -top.t.the_sub_yes_inline_1 no_init 0x842cd8b1033a58 top.t.the_sub_yes_inline_2 no_init 0xa36c65459f4b9f46 +top.t.the_sub_yes_inline_1 no_init 0x842cd8b1033a58 top.t.the_sub_no_inline_1 no_init 0x42d55205d10c58f8 top.t.the_sub_no_inline_2 no_init 0xac98037e5042d96d rand = 0x24800459 diff --git a/test_regress/t/t_x_rand_stability_add.out b/test_regress/t/t_x_rand_stability_add.out index 1db7b9396..eaa53dd1f 100644 --- a/test_regress/t/t_x_rand_stability_add.out +++ b/test_regress/t/t_x_rand_stability_add.out @@ -3,8 +3,8 @@ x_assigned (initial) = 0x00000000 uninitialized2 = 0xdf5768de big = 0x355d75711c3bf0ca3e65805db585c43beae34b336b9dbe44a2d040cbe101a665 random_init = 0x5fa24450 -top.t.the_sub_yes_inline_1 no_init 0x842cd8b1033a58 top.t.the_sub_yes_inline_2 no_init 0xa36c65459f4b9f46 +top.t.the_sub_yes_inline_1 no_init 0x842cd8b1033a58 top.t.the_sub_no_inline_1 no_init 0x42d55205d10c58f8 top.t.the_sub_no_inline_2 no_init 0xac98037e5042d96d rand = 0x24800459 diff --git a/test_regress/t/t_x_rand_stability_add_trace.out b/test_regress/t/t_x_rand_stability_add_trace.out index 1db7b9396..eaa53dd1f 100644 --- a/test_regress/t/t_x_rand_stability_add_trace.out +++ b/test_regress/t/t_x_rand_stability_add_trace.out @@ -3,8 +3,8 @@ x_assigned (initial) = 0x00000000 uninitialized2 = 0xdf5768de big = 0x355d75711c3bf0ca3e65805db585c43beae34b336b9dbe44a2d040cbe101a665 random_init = 0x5fa24450 -top.t.the_sub_yes_inline_1 no_init 0x842cd8b1033a58 top.t.the_sub_yes_inline_2 no_init 0xa36c65459f4b9f46 +top.t.the_sub_yes_inline_1 no_init 0x842cd8b1033a58 top.t.the_sub_no_inline_1 no_init 0x42d55205d10c58f8 top.t.the_sub_no_inline_2 no_init 0xac98037e5042d96d rand = 0x24800459 diff --git a/test_regress/t/t_x_rand_stability_trace.out b/test_regress/t/t_x_rand_stability_trace.out index 1db7b9396..eaa53dd1f 100644 --- a/test_regress/t/t_x_rand_stability_trace.out +++ b/test_regress/t/t_x_rand_stability_trace.out @@ -3,8 +3,8 @@ x_assigned (initial) = 0x00000000 uninitialized2 = 0xdf5768de big = 0x355d75711c3bf0ca3e65805db585c43beae34b336b9dbe44a2d040cbe101a665 random_init = 0x5fa24450 -top.t.the_sub_yes_inline_1 no_init 0x842cd8b1033a58 top.t.the_sub_yes_inline_2 no_init 0xa36c65459f4b9f46 +top.t.the_sub_yes_inline_1 no_init 0x842cd8b1033a58 top.t.the_sub_no_inline_1 no_init 0x42d55205d10c58f8 top.t.the_sub_no_inline_2 no_init 0xac98037e5042d96d rand = 0x24800459 diff --git a/test_regress/t/t_x_rand_stability_zeros.out b/test_regress/t/t_x_rand_stability_zeros.out index f0fc3e106..c6dc6b6ab 100644 --- a/test_regress/t/t_x_rand_stability_zeros.out +++ b/test_regress/t/t_x_rand_stability_zeros.out @@ -3,8 +3,8 @@ x_assigned (initial) = 0x00000000 uninitialized2 = 0x00000000 big = 0x0000000000000000000000000000000000000000000000000000000000000000 random_init = 0x5fa24450 -top.t.the_sub_yes_inline_1 no_init 0x0 top.t.the_sub_yes_inline_2 no_init 0x0 +top.t.the_sub_yes_inline_1 no_init 0x0 top.t.the_sub_no_inline_1 no_init 0x0 top.t.the_sub_no_inline_2 no_init 0x0 rand = 0x24800459