diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8959e8ea1..704917c53 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -36,9 +36,9 @@ jobs: m32: [0, 1] exclude: # Build pull requests only with ubuntu-22.04 and without m32 - - os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }} - - os: ${{ github.event_name == 'pull_request' && 'ubuntu-20.04' || 'do-not-exclude' }} - - m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }} + # - os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }} + # - os: ${{ github.event_name == 'pull_request' && 'ubuntu-20.04' || 'do-not-exclude' }} + # - m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }} # Build -m32 only on ubuntu-22.04 clang++ - {os: ubuntu-18.04, m32: 1} - {os: ubuntu-20.04, m32: 1} @@ -107,9 +107,9 @@ jobs: suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, vltmt-0, vltmt-1] exclude: # Build pull requests only with ubuntu-22.04 and without m32 - - os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }} - - os: ${{ github.event_name == 'pull_request' && 'ubuntu-20.04' || 'do-not-exclude' }} - - m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }} + # - os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }} + # - os: ${{ github.event_name == 'pull_request' && 'ubuntu-20.04' || 'do-not-exclude' }} + # - m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }} # Build -m32 only on ubuntu-22.04 - {os: ubuntu-18.04, m32: 1} - {os: ubuntu-20.04, m32: 1} diff --git a/CMakeLists.txt b/CMakeLists.txt index 13957138e..bc8ee7900 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ cmake_minimum_required(VERSION 3.15) cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime project(Verilator - VERSION 5.012 + VERSION 5.014 HOMEPAGE_URL https://verilator.org LANGUAGES CXX ) diff --git a/Changes b/Changes index daf8c20ad..2cd2678df 100644 --- a/Changes +++ b/Changes @@ -8,6 +8,55 @@ The changes in each Verilator version are described below. The contributors that suggested a given feature are shown in []. Thanks! +Verilator 5.014 2023-08-06 +========================== + +**Minor:** + +* Deprecation planned for 32-bit pointer -m32 mode (#4268). +* Deprecate CMake config below version 3.13 (#4389) (#4390). [Vito Gamberini] +* Support some stream operations on queues (#4292). [Ryszard Rozak, Antmicro Ltd] +* Support property declaration with empty parentheses (#4313) (#4317). [Anthony Donlon] +* Support locator methods with "with" on assoc arrays (#4335). [Ryszard Rozak, Antmicro Ltd] +* Support string replication with variable (#4341). [Aleksander Kiryk, Antmicro Ltd] +* Support more types in wait (#4374). [Aleksander Kiryk, Antmicro Ltd] +* Support static method calls as default values of function arguments (#4378). [Ryszard Rozak, Antmicro Ltd] +* Add GENUNNAMED lint warning. [Srinivasan Venkataramanan, Deepa Palaniappan] +* Add MISINDENT lint warning for misleading indentation. +* Fix 'VlForkSync' redeclaration (#4277). [Krzysztof Bieganski, Antmicro Ltd] +* Fix processes that can outlive their parents (#4253). [Krzysztof Boronski, Antmicro Ltd] +* Fix duplicate fork names (#4295). [Ryszard Rozak, Antmicro Ltd] +* Fix splitting coroutines (#4297) (#4307). [Jiamin Zhu] +* Fix error when multiple duplicate DPI exports (#4301). +* Fix class reference assignment checking (#4296). [Ryszard Rozak, Antmicro Ltd] +* Fix handling of ref types in initial values of type parameters (#4304). [Ryszard Rozak, Antmicro Ltd] +* Fix comparison of string parameters (#4308). [Ryszard Rozak, Antmicro Ltd] +* Fix state update for always processes (#4311). [Aleksander Kiryk, Antmicro Ltd] +* Fix multiple edge timing controls in class methods (#4318) (#4320) (#4344). [Krzysztof Bieganski, Antmicro Ltd] +* Fix implicit calls of base class constructors with optional arguments (#4319). [Ryszard Rozak, Antmicro Ltd] +* Fix propagation of process requirement (#4321). [Krzysztof Boroński] +* Fix unhandled overloads in V3InstrCount (#4324). [Krzysztof Boroński] +* Fix selects of static members (#4326). [Ryszard Rozak, Antmicro Ltd] +* Fix references to members of results of static methods (#4327). [Ryszard Rozak, Antmicro Ltd] +* Fix unique..with method on queues of class objects (#4328). [Ryszard Rozak, Antmicro Ltd] +* Fix queue slicing (#4329). [Aleksander Kiryk, Antmicro Ltd] +* Fix wildcard referring types (#4336) (#4342). [Aleksander Kiryk, Antmicro Ltd] +* Fix comparison of class objects (#4346). [Ryszard Rozak, Antmicro Ltd] +* Fix unexpected RefDType on assoc arrays (#4337). [Aleksander Kiryk, Antmicro Ltd] +* Fix cmake astgen for Rocky Linux 8.7 (#4343). [Julian Daube] +* Fix class timescale in class packages (#4348). [Krzysztof Bieganski, Antmicro Ltd] +* Fix string concatenations (#4354). [Ryszard Rozak, Antmicro Ltd] +* Fix unlinked task error from broken context (#4355) (#4402). [Aleksander Kiryk, Antmicro Ltd] +* Fix selects on unpacked structs (#4359). [Ryszard Rozak, Antmicro Ltd] +* Fix select operation on assoc array with wide keys (#4360). [Ryszard Rozak, Antmicro Ltd] +* Fix non-public methods with wide output (#4364). [Ryszard Rozak, Antmicro Ltd] +* Fix handling of super.new calls (#4366). [Ryszard Rozak, Antmicro Ltd] +* Fix assign to input var in methods (#4367). [Aleksander Kiryk, Antmicro Ltd] +* Fix VlProcess not found (#4368). [Aleksander Kiryk, Antmicro Ltd] +* Fix order of evaluation of function calls in statements (#4375). [Ryszard Rozak, Antmicro Ltd] +* Fix config_build.h issues (#4380) (#4381). [Andrew Miloradovsky] + + Verilator 5.012 2023-06-13 ========================== diff --git a/Makefile.in b/Makefile.in index c74aadd73..358823411 100644 --- a/Makefile.in +++ b/Makefile.in @@ -449,8 +449,8 @@ install-msg: IN_WILD := ${srcdir}/*.in ${srcdir}/*/*.in -# autoheader might not change config_build.h.in, so touch it -${srcdir}/config_build.h: ${srcdir}/config_build.h.in configure +# autoheader might not change config_package.h.in, so touch it +${srcdir}/config_package.h: ${srcdir}/config_package.h.in configure cd ${srcdir} && autoheader touch $@ Makefile: Makefile.in config.status $(IN_WILD) diff --git a/README.rst b/README.rst index 1b8cc8435..2c3d98961 100644 --- a/README.rst +++ b/README.rst @@ -1,20 +1,22 @@ .. Github doesn't render images unless absolute URL .. Do not know of a conditional tag, "only: github" nor "github display" works +.. image:: https://img.shields.io/badge/Website-Verilator.org-181717.svg + :target: https://verilator.org .. image:: https://img.shields.io/badge/License-LGPL%20v3-blue.svg - :target: https://www.gnu.org/licenses/lgpl-3.0] + :target: https://www.gnu.org/licenses/lgpl-3.0 .. image:: https://img.shields.io/badge/License-Artistic%202.0-0298c3.svg :target: https://opensource.org/licenses/Artistic-2.0 .. image:: https://repology.org/badge/tiny-repos/verilator.svg?header=distro%20packages :target: https://repology.org/project/verilator/versions +.. image:: https://img.shields.io/docker/pulls/verilator/verilator + :target: https://hub.docker.com/r/verilator/verilator .. image:: https://api.codacy.com/project/badge/Grade/fa78caa433c84a4ab9049c43e9debc6f :target: https://www.codacy.com/gh/verilator/verilator .. image:: https://codecov.io/gh/verilator/verilator/branch/master/graph/badge.svg :target: https://codecov.io/gh/verilator/verilator .. image:: https://github.com/verilator/verilator/workflows/build/badge.svg :target: https://github.com/verilator/verilator/actions?query=workflow%3Abuild -.. image:: https://img.shields.io/docker/pulls/verilator/verilator - :target: https://hub.docker.com/r/verilator/verilator Welcome to Verilator diff --git a/configure.ac b/configure.ac index 51af31653..b20979c00 100644 --- a/configure.ac +++ b/configure.ac @@ -10,11 +10,11 @@ # Then 'make maintainer-dist' #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[5.012 2023-06-13], +AC_INIT([Verilator],[5.014 2023-08-06], [https://verilator.org], [verilator],[https://verilator.org]) -AC_CONFIG_HEADERS(src/config_build.h) +AC_CONFIG_HEADERS(src/config_package.h) AC_CONFIG_FILES(Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h verilator.pc verilator-config.cmake verilator-config-version.cmake) # Version diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 20c63956f..b9b184379 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -13,7 +13,9 @@ Aliaksei Chapyzhenka Ameya Vikram Singh Andreas Kuster Andrei Kostovski +Andrew Miloradovsky Andrew Nolte +Anthony Donlon Arkadiusz Kozdra Aylon Chaim Porat Cameron Kirk @@ -38,6 +40,7 @@ Fan Shupei february cozzocrea Felix Neumärker Felix Yan +G-A. Kamendje Garrett Smith Geza Lore Gianfranco Costamagna @@ -46,7 +49,6 @@ Gökçe Aydos Graham Rushton Guokai Chen Gustav Svensk -G-A. Kamendje Harald Heckmann Hennadii Chernyshchyk Howard Su @@ -54,9 +56,9 @@ Huang Rui Huanghuang Zhou HungMingWu HyungKi Jeong +Ilya Barkov Iru Cai Ivan Vnučec -Ilya Barkov Iztok Jeras Jake Merdich James Hanlon @@ -71,17 +73,18 @@ Jeremy Bennett Jesse Taube Jevin Sweval Jiacheng Qian +Jiamin Zhu Jiuyang Liu Joey Liu John Coiner John Demme John Wehle -Jiamin Zhu Jonathan Drolet Jose Loyola -Joseph Nwabueze Josep Sans +Joseph Nwabueze Josh Redford +Julian Daube Julie Schwartz Julien Margetts Kaleb Barrett @@ -91,6 +94,7 @@ Keith Colbert Kevin Kiningham Kritik Bhimani Krzysztof Bieganski +Krzysztof Boronski Krzysztof Boroński Kuba Ober Larry Doolittle @@ -162,15 +166,17 @@ Varun Koyyalagunta Vassilis Papaefstathiou Veripool API Bot Victor Besyakov +Vito Gamberini William D. Jones Wilson Snyder Xi Zhang Yinan Xu Yoda Lee Yossi Nivin +Yu-Sheng Lin Yuri Victorovich Yutetsu TAKATSUKASA -Yu-Sheng Lin Yves Mathieu Zhanglei Wang Zixi Li +أحمد المحمودي diff --git a/docs/Makefile b/docs/Makefile index a1e151b35..3a44a656a 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -18,12 +18,16 @@ RST2HTML = rst2html PYTHON3 = python3 DOXYGEN = doxygen -SPHINXOPTS ?= -c guide SPHINXBUILD ?= sphinx-build SOURCEDIR = guide BUILDDIR = _build +SPHINXOPTS ?= -c guide +ifneq ($(VERILATOR_ANALYTICS_ID),) +SPHINXOPTS += -D html_theme_options.analytics_id=$(VERILATOR_ANALYTICS_ID) +endif + ###################################################################### .SUFFIXES: diff --git a/docs/guide/conf.py b/docs/guide/conf.py index 730b3e351..d022012c2 100644 --- a/docs/guide/conf.py +++ b/docs/guide/conf.py @@ -115,7 +115,6 @@ html_theme = 'sphinx_rtd_theme' html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] html_theme_options = { - 'analytics_id': 'G-D27B0C9QEB', 'logo_only': True, 'style_nav_header_background': "#45acf8", # Default is #2980B9 # 'canonical_url': diff --git a/docs/guide/deprecations.rst b/docs/guide/deprecations.rst index 1fd8252fd..df4c7d2ac 100644 --- a/docs/guide/deprecations.rst +++ b/docs/guide/deprecations.rst @@ -17,10 +17,10 @@ C++11 compiler support Verilator will require C++20 or newer compilers for both compiling Verilator and compiling all Verilated models no sooner than January 2025. -Verilated_heavy.h - The legacy "verilated_heavy.h" include was replaced with just including - "verilated.h". Verilated_heavy.h is planned for removal no sooner than - July 2022. +32-bit compiler support + Verilator currently regresses both 64-bit and 32-bit pointer modes (GCC's + `-m64` and `-m32`). Support for 32-bit `-m32` mode will be deprecated no + sooner than January 2024. Option `-O` The debug `-O` options have been replaced with diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index a4d0af876..6ec962e1e 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -1539,7 +1539,7 @@ Summary: Disable all code style related warning messages (note that by default, they are already disabled). This is equivalent to ``-Wno-DECLFILENAME -Wno-DEFPARAM - -Wno-EOFNEWLINE -Wno-IMPORTSTAR -Wno-INCABSPATH -Wno-PINCONNECTEMPTY + -Wno-EOFNEWLINE -Wno-GENUNNAMED -Wno-IMPORTSTAR -Wno-INCABSPATH -Wno-PINCONNECTEMPTY -Wno-PINNOCONNECT -Wno-SYNCASYNCNET -Wno-UNDRIVEN -Wno-UNUSEDGENVAR -Wno-UNUSEDPARAM -Wno-UNUSEDSIGNAL -Wno-VARHIDDEN``. @@ -1562,16 +1562,17 @@ Summary: Enable all lint-related warning messages (note that by default, they are already enabled), but do not affect style messages. This is equivalent to - ``-Wwarn-ALWCOMBORDER -Wwarn-BSSPACE -Wwarn-CASEINCOMPLETE - -Wwarn-CASEOVERLAP -Wwarn-CASEX -Wwarn-CASTCONST -Wwarn-CASEWITHX -Wwarn-CMPCONST - -Wwarn-COLONPLUS -Wwarn-IMPLICIT -Wwarn-ASCRANGE - -Wwarn-PINMISSING -Wwarn-REALCVT -Wwarn-UNSIGNED -Wwarn-WIDTH``. + ``-Wwarn-ALWCOMBORDER -Wwarn-ASCRANGE -Wwarn-BSSPACE -Wwarn-CASEINCOMPLETE + -Wwarn-CASEOVERLAP -Wwarn-CASEWITHX -Wwarn-CASEX -Wwarn-CASTCONST -Wwarn-CMPCONST + -Wwarn-COLONPLUS -Wwarn-IMPLICIT -Wwarn-IMPLICITSTATIC -Wwarn-LATCH -Wwarn-MISINDENT + -Wwarn-NEWERSTD -Wwarn-PINMISSING -Wwarn-REALCVT -Wwarn-STATICVAR -Wwarn-UNSIGNED + -Wwarn-WIDTHTRUNC -Wwarn-WIDTHEXPAND -Wwarn-WIDTHXZEXPAND``. .. option:: -Wwarn-style Enable all code style-related warning messages. This is equivalent to ``-Wwarn ASSIGNDLY -Wwarn-DECLFILENAME -Wwarn-DEFPARAM -Wwarn-EOFNEWLINE - -Wwarn-INCABSPATH -Wwarn-PINNOCONNECT -Wwarn-SYNCASYNCNET -Wwarn-UNDRIVEN + -Wwarn-GENUNNAMED -Wwarn-INCABSPATH -Wwarn-PINNOCONNECT -Wwarn-SYNCASYNCNET -Wwarn-UNDRIVEN -Wwarn-UNUSEDGENVAR -Wwarn-UNUSEDPARAM -Wwarn-UNUSEDSIGNAL -Wwarn-VARHIDDEN``. .. option:: --x-assign 0 diff --git a/docs/guide/faq.rst b/docs/guide/faq.rst index 621b0e3b5..d02559a7b 100644 --- a/docs/guide/faq.rst +++ b/docs/guide/faq.rst @@ -486,7 +486,7 @@ From the sc_main.cpp file, you'd then: #include "Vour.h" #include "Vour_our.h" - cout << "clock is " << top->our->clk << endl; + std::cout << "clock is " << top->our->clk << std::endl; In this example, clk is a bool you can read or set as any other variable. diff --git a/docs/guide/simulating.rst b/docs/guide/simulating.rst index 8067b0366..2fc6bc5e3 100644 --- a/docs/guide/simulating.rst +++ b/docs/guide/simulating.rst @@ -500,7 +500,7 @@ feedback-directed optimization. See the appropriate compiler documentation. -.. _Runtime Debugging +.. _Runtime Debugging: Runtime Debugging ================= diff --git a/docs/guide/verilating.rst b/docs/guide/verilating.rst index e1b031c5a..7c1aa361b 100644 --- a/docs/guide/verilating.rst +++ b/docs/guide/verilating.rst @@ -165,7 +165,7 @@ compiled on the different target system. To support this, none of the files that Verilator produces will reference any configure-generated build-system-specific files, such as -:file:`config.h` (which is renamed in Verilator to :file:`config_build.h` +:file:`config.h` (which is renamed in Verilator to :file:`config_package.h` to reduce confusion.) The disadvantage of this approach is that :file:`include/verilatedos.h` must self-detect the requirements of the target system, rather than using configure. diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst index 5dc90fba4..f44082085 100644 --- a/docs/guide/warnings.rst +++ b/docs/guide/warnings.rst @@ -670,6 +670,52 @@ List Of Warnings used as a clock. +.. option:: GENUNNAMED + + Warns that a generate block was unnamed and "genblk" will be used per + IEEE. + + The potential issue is that adding additional generate blocks will + renumber the assigned names, which may cause eventual problems with + synthesis constraints or other tools that depend on hierarchical paths + remaining consistent. + + Blocks that are empty may not be reported with this warning, as no + scopes are created for empty blocks, so there is no harm in having them + unnamed. + + Disabled by default as this is a code-style warning; it will simulate + correctly. + + .. code-block:: sv + :linenos: + :emphasize-lines: 2 + + generate + if (PARAM == 1) begin //<--- Warning + end + + Results in: + + .. code-block:: + + %Warning-GENUNNAMED: example.v:2:9: Unnamed generate block (IEEE 1800-2017 27.6) + + To fix this assign a label (often with the naming convention prefix of + :code:`gen_` or :code:`g_`), for example: + + .. code-block:: sv + :linenos: + :emphasize-lines: 2 + + generate + if (PARAM == 1) begin : gen_param_1 //<--- Repaired + end + + Other tools with similar warnings: Verible's generate-label, "All + generate block statements must have a label." + + .. option:: HIERBLOCK Warns that the top module is marked as a hierarchy block by the @@ -876,6 +922,102 @@ List Of Warnings Ignoring this warning will only suppress the lint check; it will simulate correctly. +.. option:: LIFETIME + + Error when a variable is referenced in a process that can outlive the process + in which it was declared. This can happen when using 'fork..join_none' or + 'fork..join_any' blocks, which spawn process that can outlive their parents. + This error occurs only when Verilator can't replace the reference with a + reference to copy of this variable, local to the forked process. For example: + + .. code-block:: sv + :linenos: + :emphasize-lines: 3 + + task foo(int local_var); + fork + #10 local_var++; + #20 $display("local_var = %d", local_var); + join_none + endtask + + In the example above 'local_var' exists only within scope of 'foo', once foo + finishes, the stack frame containing 'i' gets removed. However, the process + forked from foo continues, as it contains a delay. After 10 units of time + pass, this process attempts to modify 'local_var'. However, this variable no + longer exits. It can't be made local to the forked process upon spawning, because + it's modified and can be referenced somewhere else, for example in the other + forked process, that was delayed by 20 units of time in this example. Thus, + there's no viable stack allocation for it. + + In order to fix it, if the intent is not to share the variable's state outside + of the process, then create a local copy of the variable. + + For example: + + .. code-block:: sv + :linenos: + :emphasize-lines: 4 + + task foo(int local_var); + fork + #10 begin + int forked_var = local_var; + forked_var++; + end + #20 begin + // Note that we are going to print the original value here, + // as `forked_var`is a local copy that was initialized while + // `foo` was still alive. + int forked_var = local_var; + $display("forked_var = %d", forked_var) + end + join_none + endtask + + If you need to share its state, another strategy is to ensure it's allocated + statically: + + .. code-block:: sv + :linenos: + :emphasize-lines: 1 + + int static_var; + + task foo(); + fork + #10 static_var++; + #20 $display("static_var = %d", static_var); + join_none + endtask + + However, if you need to be able to instantiate at runtime, the solution would be to + wrap it in an object, since the forked process can hold a reference to that object + and ensure that the variable stays alive this way: + + .. code-block:: sv + :linenos: + :emphasize-lines: 2 + + class Wrapper; + int m_var; + + // Here we implicitly hold a reference to `this` + task foo(); + fork + #10 m_var++; + #20 $display("this.m_var = %d", m_var); + join_none + endtask + endclass + + // Here we explicitly hold a handle to an object + task bar(Wrapper wrapper); + fork + #10 wrapper.m_var++; + #20 $display("wrapper.m_var = %d", wrapper.m_var); + join_none + endtask .. option:: LITENDIAN @@ -897,6 +1039,51 @@ List Of Warnings unsupported. Verilator uses only the typical delay value. +.. option:: MISINDENT + + Warns that the indentation of a statement is misleading, suggesting the + statement is part of a previous :code:`if` or :code:`while` block while + it is not. + + Verilator suppresses this check when there is an inconsistent mix of + spaces and tabs, as it cannot ensure the width of tabs. Verilator also + ignores blocks with :code:`begin`/:code:`end`, as the :code:`end` + visually indicates the earlier statement's end. + + Ignoring this warning will only suppress the lint check; it will + simulate correctly. + + For example + + .. code-block:: sv + :linenos: + :emphasize-lines: 3 + + if (something) + statement_in_if; + statement_not_in_if; //<--- Warning + + Results in: + + .. code-block:: + + %Warning-MISINDENT: example.v:3:9: Misleading indentation + + To fix this repair the indentation to match the correct earlier + statement, for example: + + .. code-block:: sv + :linenos: + :emphasize-lines: 3 + + if (something) + statement_in_if; + statement_not_in_if; //<--- Repaired + + Other tools with similar warnings: GCC -Wmisleading-indentation, + clang-tidy readability-misleading-indentation. + + .. option:: MODDUP .. TODO better example diff --git a/docs/internals.rst b/docs/internals.rst index ca4b626e4..136c90265 100644 --- a/docs/internals.rst +++ b/docs/internals.rst @@ -2123,7 +2123,7 @@ Or in a hand-written C++ wrapper: :: #ifdef TEST_VERBOSE - cout << "Read a=" << a << endl; + std::cout << "Read a=" << a << std::endl; #endif A filename that should be used to check the output results is given with diff --git a/docs/spelling.txt b/docs/spelling.txt index 2dca6d079..46754fe66 100644 --- a/docs/spelling.txt +++ b/docs/spelling.txt @@ -56,6 +56,7 @@ Das Dcache Deadman Debacker +Deepa Defparams Denio Deprecations @@ -246,6 +247,7 @@ Olof Olofsson Oyvind PLI +Palaniappan Patricio Petr Piechotka @@ -376,6 +378,7 @@ Wfuture Whatson Wildman Wim +Wmisleading Wno Wojciech Wolfel @@ -410,6 +413,7 @@ architected args arrarys assertOn +astgen async ato atoi @@ -905,6 +909,7 @@ undef undefineall undriven ungetc +unhandled uniquified unistd unlink @@ -971,4 +976,3 @@ ypq yurivict zdave Øyvind - diff --git a/include/verilated.cpp b/include/verilated.cpp index af1f419b1..a77094f65 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -1896,6 +1896,12 @@ std::string VL_CVT_PACK_STR_NW(int lwords, const WDataInP lwp) VL_PURE { return std::string{destout, len}; } +std::string VL_CVT_PACK_STR_ND(const VlQueue& q) VL_PURE { + std::string output; + for (const std::string& s : q) output += s; + return output; +} + std::string VL_PUTC_N(const std::string& lhs, IData rhs, CData ths) VL_PURE { std::string lstring = lhs; const int32_t rhs_s = rhs; // To signed value diff --git a/include/verilated_cov.cpp b/include/verilated_cov.cpp index 7ed7e0031..8fe4e99be 100644 --- a/include/verilated_cov.cpp +++ b/include/verilated_cov.cpp @@ -210,8 +210,8 @@ private: std::string result = prefix + "*" + suffix; - // cout << "\nch pre="< instead of " -#endif - -#include "verilated.h" - -#endif // Guard diff --git a/include/verilated_timing.h b/include/verilated_timing.h index 1e63009c5..6ddd0b115 100644 --- a/include/verilated_timing.h +++ b/include/verilated_timing.h @@ -86,36 +86,6 @@ public: #endif }; -//=================================================================== -// VlProcess stores metadata of running processes - -class VlProcess final { - // MEMBERS - int m_state; // Current state of the process - -public: - // TYPES - enum : int { // Type int for compatibility with $c - FINISHED = 0, - RUNNING = 1, - WAITING = 2, - SUSPENDED = 3, - KILLED = 4, - }; - - // CONSTRUCTORS - VlProcess() - : m_state{RUNNING} {} - - // METHODS - int state() { return m_state; } - void state(int s) { m_state = s; } -}; - -using VlProcessRef = std::shared_ptr; - -inline std::string VL_TO_STRING(const VlProcessRef& p) { return std::string("process"); } - //============================================================================= // VlCoroutineHandle is a non-copyable (but movable) coroutine handle. On resume, the handle is // cleared, as we assume that either the coroutine has finished and deleted itself, or, if it got diff --git a/include/verilated_types.h b/include/verilated_types.h index cbd05ad96..bce36f258 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -73,6 +73,36 @@ extern std::string VL_TO_STRING_W(int words, const WDataInP obj); #define VL_OUT(name, msb, lsb) IData name ///< Declare output signal, 17-32 bits #define VL_OUTW(name, msb, lsb, words) VlWide name ///< Declare output signal, 65+ bits +//=================================================================== +// VlProcess stores metadata of running processes + +class VlProcess final { + // MEMBERS + int m_state; // Current state of the process + +public: + // TYPES + enum : int { // Type int for compatibility with $c + FINISHED = 0, + RUNNING = 1, + WAITING = 2, + SUSPENDED = 3, + KILLED = 4, + }; + + // CONSTRUCTORS + VlProcess() + : m_state{RUNNING} {} + + // METHODS + int state() { return m_state; } + void state(int s) { m_state = s; } +}; + +using VlProcessRef = std::shared_ptr; + +inline std::string VL_TO_STRING(const VlProcessRef& p) { return std::string("process"); } + //=================================================================== // Activity trigger vector @@ -487,7 +517,7 @@ public: template VlQueue unique(Func with_func) const { VlQueue out; - std::set saw; + std::set saw; for (const auto& i : m_deque) { const auto i_mapped = with_func(0, i); const auto it = saw.find(i_mapped); @@ -516,7 +546,7 @@ public: VlQueue unique_index(Func with_func) const { VlQueue out; IData index = 0; - std::unordered_set saw; + std::set saw; for (const auto& i : m_deque) { const auto i_mapped = with_func(index, i); auto it = saw.find(i_mapped); @@ -830,6 +860,22 @@ public: } return out; } + template + VlQueue unique(Func with_func) const { + VlQueue out; + T_Key default_key; + using WithType = decltype(with_func(m_map.begin()->first, m_map.begin()->second)); + std::set saw; + for (const auto& i : m_map) { + const auto i_mapped = with_func(default_key, i.second); + const auto it = saw.find(i_mapped); + if (it == saw.end()) { + saw.insert(it, i_mapped); + out.push_back(i.second); + } + } + return out; + } VlQueue unique_index() const { VlQueue out; std::set saw; @@ -843,6 +889,21 @@ public: return out; } template + VlQueue unique_index(Func with_func) const { + VlQueue out; + using WithType = decltype(with_func(m_map.begin()->first, m_map.begin()->second)); + std::set saw; + for (const auto& i : m_map) { + const auto i_mapped = with_func(i.first, i.second); + auto it = saw.find(i_mapped); + if (it == saw.end()) { + saw.insert(it, i_mapped); + out.push_back(i.first); + } + } + return out; + } + template VlQueue find(Func with_func) const { VlQueue out; for (const auto& i : m_map) @@ -903,6 +964,16 @@ public: }); return VlQueue::cons(it->second); } + template + VlQueue min(Func with_func) const { + if (m_map.empty()) return VlQueue(); + const auto it = std::min_element( + m_map.begin(), m_map.end(), + [&with_func](const std::pair& a, const std::pair& b) { + return with_func(a.first, a.second) < with_func(b.first, b.second); + }); + return VlQueue::cons(it->second); + } VlQueue max() const { if (m_map.empty()) return VlQueue(); const auto it = std::max_element( @@ -912,6 +983,16 @@ public: }); return VlQueue::cons(it->second); } + template + VlQueue max(Func with_func) const { + if (m_map.empty()) return VlQueue(); + const auto it = std::max_element( + m_map.begin(), m_map.end(), + [&with_func](const std::pair& a, const std::pair& b) { + return with_func(a.first, a.second) < with_func(b.first, b.second); + }); + return VlQueue::cons(it->second); + } T_Value r_sum() const { T_Value out(0); // Type must have assignment operator @@ -1457,8 +1538,14 @@ public: // For 'if (ptr)...' operator bool() const { return m_objp; } // In SV A == B iff both are handles to the same object (IEEE 1800-2017 8.4) - bool operator==(const VlClassRef& rhs) const { return m_objp == rhs.m_objp; }; - bool operator!=(const VlClassRef& rhs) const { return m_objp != rhs.m_objp; }; + template + bool operator==(const VlClassRef& rhs) const { + return m_objp == rhs.m_objp; + }; + template + bool operator!=(const VlClassRef& rhs) const { + return m_objp != rhs.m_objp; + }; }; template diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index 083137c95..1262a9df0 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -2307,7 +2307,7 @@ PLI_INT32 vpi_flush(void) { VerilatedVpiImp::assertOneCheck(); VL_VPI_ERROR_RESET_(); Verilated::runFlushCallbacks(); - return 0; + return 0; // Gcc coverage bug // LCOV_EXCL_LINE } PLI_INT32 vpi_mcd_flush(PLI_UINT32 mcd) { diff --git a/include/verilatedos.h b/include/verilatedos.h index fdcbe64cd..113d8cd2d 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -119,6 +119,10 @@ // Allowed on: function, method. (-fthread-safety) #define VL_RETURN_CAPABILITY(x) \ VL_CLANG_ATTR(lock_returned(x)) +// Assert that capability is already held. +// Allowed on: function, method. (-fthread-safety) +#define VL_ASSERT_CAPABILITY(x) \ + VL_CLANG_ATTR(assert_capability(x)) // Defaults for unsupported compiler features #ifndef VL_ATTR_ALWINLINE diff --git a/src/.gitignore b/src/.gitignore index 69a397007..0cfb6eb36 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,6 +1,6 @@ *~ *.old -config_build.h +config_package.h Makefile Makefile_obj .objcache* diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dc8dcf182..ba230d891 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -82,6 +82,7 @@ set(HEADERS V3File.h V3FileLine.h V3Force.h + V3Fork.h V3FunctionTraits.h V3Gate.h V3Global.h @@ -227,6 +228,7 @@ set(COMMON_SOURCES V3File.cpp V3FileLine.cpp V3Force.cpp + V3Fork.cpp V3Gate.cpp V3Global.cpp V3Graph.cpp @@ -322,7 +324,7 @@ file(TO_NATIVE_PATH ${srcdir}/../bin/verilator_includer VERILATOR_INCLUDER) file(TO_NATIVE_PATH ${srcdir}/vlcovgen VLCOVGEN) file(TO_NATIVE_PATH ${srcdir}/config_rev CONFIG_REV) -configure_file(config_build.h.in config_build.h @ONLY) +configure_file(config_package.h.in config_package.h @ONLY) add_custom_command( OUTPUT V3Ast__gen_forward_class_decls.h V3Dfg__gen_forward_class_decls.h @@ -414,7 +416,7 @@ foreach(astgen_name ${ASTGENERATED_NAMES}) MAIN_DEPENDENCY ${astgen_name}.cpp DEPENDS ${ASTGEN} V3Ast.h COMMAND ${PYTHON3} ARGS - ${ASTGEN} -I"${srcdir}" --astdef V3AstNodeDType.h --astdef V3AstNodeExpr.h --astdef V3AstNodeOther.h --dfgdef V3DfgVertices.h ${astgen_name}.cpp + ${ASTGEN} -I "${srcdir}" --astdef V3AstNodeDType.h --astdef V3AstNodeExpr.h --astdef V3AstNodeOther.h --dfgdef V3DfgVertices.h ${astgen_name}.cpp ) list(APPEND GENERATED_FILES ${astgen_name}__gen.cpp) endforeach() diff --git a/src/Makefile.in b/src/Makefile.in index c8e94fe50..a1af5cf21 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -95,7 +95,7 @@ clean mostlyclean distclean maintainer-clean:: -rm -f .objcache* distclean maintainer-clean:: - -rm -f Makefile Makefile_obj config_build.h + -rm -f Makefile Makefile_obj config_package.h maintainer-clean:: -rm -f config_rev.h diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 617a8880c..4d364ef6c 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -205,6 +205,7 @@ RAW_OBJS = \ V3File.o \ V3FileLine.o \ V3Force.o \ + V3Fork.o \ V3Gate.o \ V3Global.o \ V3Graph.o \ diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 6135eabde..a731dfee3 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -157,7 +157,7 @@ private: sentreep->unlinkFrBack(); if (m_procedurep) { // To support this need queue of asserts to activate - nodep->v3error("Unsupported: Procedural concurent assertion with" + nodep->v3error("Unsupported: Procedural concurrent assertion with" " clocking event inside always (IEEE 1800-2917 16.14.6)"); } } diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 0be9e89a5..4242138db 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -125,9 +125,7 @@ string AstNode::encodeNumber(int64_t num) { } } -string AstNode::nameProtect() const VL_MT_STABLE { - return VIdProtect::protectIf(name(), protect()); -} +string AstNode::nameProtect() const { return VIdProtect::protectIf(name(), protect()); } string AstNode::origNameProtect() const { return VIdProtect::protectIf(origName(), protect()); } string AstNode::shortName() const { @@ -285,7 +283,7 @@ string AstNode::vpiName(const string& namein) { return pretty; } -string AstNode::prettyTypeName() const VL_MT_STABLE { +string AstNode::prettyTypeName() const { if (name() == "") return typeName(); return std::string{typeName()} + " '" + prettyName() + "'"; } @@ -1081,10 +1079,12 @@ bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ig // private: Return true if the two trees are identical if (!node1p && !node2p) return true; if (!node1p || !node2p) return false; - if (node1p->type() != node2p->type() || node1p->dtypep() != node2p->dtypep() - || !node1p->same(node2p) || (gateOnly && !node1p->isGateOptimizable())) { - return false; - } + if (node1p->type() != node2p->type()) return false; + UASSERT_OBJ( + (!node1p->dtypep() && !node2p->dtypep()) || (node1p->dtypep() && node2p->dtypep()), node1p, + "Comparison of a node with dtypep() with a node without dtypep()\n-node2=" << node2p); + if (node1p->dtypep() && !node1p->dtypep()->similarDType(node2p->dtypep())) return false; + if (!node1p->same(node2p) || (gateOnly && !node1p->isGateOptimizable())) return false; return (sameTreeIter(node1p->m_op1p, node2p->m_op1p, false, gateOnly) && sameTreeIter(node1p->m_op2p, node2p->m_op2p, false, gateOnly) && sameTreeIter(node1p->m_op3p, node2p->m_op3p, false, gateOnly) @@ -1406,6 +1406,9 @@ AstNodeDType* AstNode::findQueueIndexDType() const { AstNodeDType* AstNode::findVoidDType() const { return v3Global.rootp()->typeTablep()->findVoidDType(fileline()); } +AstNodeDType* AstNode::findStreamDType() const { + return v3Global.rootp()->typeTablep()->findStreamDType(fileline()); +} //###################################################################### // VNDeleter diff --git a/src/V3Ast.h b/src/V3Ast.h index b871314c0..f763284ca 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -82,6 +82,17 @@ using MTaskIdSet = std::set; // Set of mtaskIds for Var sorting // Ast*' is returned. #define VN_AS(nodep, nodetypename) (AstNode::privateAs(nodep)) +// Same as VN_AS, but only checks the type in debug builds. Type checking is less critical in node +// child getters (the strongly-typed functions that wrap op*p pointers). This is because the op*p +// pointers are usually populated by code that already asserts the correct type. Having fewer type +// assertions yields better performance in release builds. +#ifdef VL_DEBUG +#define VN_DBG_AS(nodep, nodetypename) VN_AS(nodep, nodetypename) +#else +#define VN_DBG_AS(nodep, nodetypename) \ + (AstNode::unsafePrivateAs(nodep)) +#endif + // (V)erilator (N)ode deleted: Pointer to deleted AstNode (for assertions only) #define VN_DELETED(nodep) VL_UNLIKELY((uint64_t)(nodep) == 0x1) @@ -1686,7 +1697,7 @@ public: static constexpr int INSTR_COUNT_PLI = 20; // PLI routines // ACCESSORS - virtual string name() const VL_MT_STABLE { return ""; } + virtual string name() const { return ""; } virtual string origName() const { return ""; } virtual void name(const string& name) { this->v3fatalSrc("name() called on object without name() method"); @@ -1694,7 +1705,7 @@ public: virtual void tag(const string& text) {} virtual string tag() const { return ""; } virtual string verilogKwd() const { return ""; } - string nameProtect() const VL_MT_STABLE; // Name with --protect-id applied + string nameProtect() const; // Name with --protect-id applied string origNameProtect() const; // origName with --protect-id applied string shortName() const; // Name with __PVT__ removed for concatenating scopes static string dedotName(const string& namein); // Name with dots removed @@ -1707,10 +1718,10 @@ public: static string encodeName(const string& namein); static string encodeNumber(int64_t num); // Encode number into internal C representation static string vcdName(const string& namein); // Name for printing out to vcd files - string prettyName() const VL_MT_STABLE { return prettyName(name()); } + string prettyName() const { return prettyName(name()); } string prettyNameQ() const { return prettyNameQ(name()); } // "VARREF" for error messages (NOT dtype's pretty name) - string prettyTypeName() const VL_MT_STABLE; + string prettyTypeName() const; virtual string prettyOperatorName() const { return "operator " + prettyTypeName(); } FileLine* fileline() const VL_MT_SAFE { return m_fileline; } void fileline(FileLine* fl) { m_fileline = fl; } @@ -1867,6 +1878,7 @@ public: void dtypeSetUInt64() { dtypep(findUInt64DType()); } // Twostate void dtypeSetEmptyQueue() { dtypep(findEmptyQueueDType()); } void dtypeSetVoid() { dtypep(findVoidDType()); } + void dtypeSetStream() { dtypep(findStreamDType()); } // Data type locators AstNodeDType* findBitDType() const { return findBasicDType(VBasicDTypeKwd::LOGIC); } @@ -1878,6 +1890,7 @@ public: AstNodeDType* findCHandleDType() const { return findBasicDType(VBasicDTypeKwd::CHANDLE); } AstNodeDType* findEmptyQueueDType() const; AstNodeDType* findVoidDType() const; + AstNodeDType* findStreamDType() const; AstNodeDType* findQueueIndexDType() const; AstNodeDType* findBitDType(int width, int widthMin, VSigning numeric) const; AstNodeDType* findLogicDType(int width, int widthMin, VSigning numeric) const; @@ -2065,24 +2078,34 @@ public: return nodep && privateTypeTest(nodep) ? reinterpret_cast(nodep) : nullptr; } - // For use via the VN_AS macro only + // For use via privateAs or the VN_DBG_AS macro only template - static T* privateAs(AstNode* nodep) VL_PURE { + static T* unsafePrivateAs(AstNode* nodep) VL_PURE { static_assert(!uselessCast(), "Unnecessary VN_AS, node known to have target type."); static_assert(!impossibleCast(), "Unnecessary VN_AS, node cannot be this type."); - UASSERT_OBJ(!nodep || privateTypeTest(nodep), nodep, - "AstNode is not of expected type, but instead has type '" << nodep->typeName() - << "'"); return reinterpret_cast(nodep); } template - static const T* privateAs(const AstNode* nodep) VL_PURE { + static const T* unsafePrivateAs(const AstNode* nodep) VL_PURE { static_assert(!uselessCast(), "Unnecessary VN_AS, node known to have target type."); static_assert(!impossibleCast(), "Unnecessary VN_AS, node cannot be this type."); + return reinterpret_cast(nodep); + } + + // For use via the VN_AS macro only + template + static T* privateAs(AstNode* nodep) VL_PURE { UASSERT_OBJ(!nodep || privateTypeTest(nodep), nodep, "AstNode is not of expected type, but instead has type '" << nodep->typeName() << "'"); - return reinterpret_cast(nodep); + return unsafePrivateAs(nodep); + } + template + static const T* privateAs(const AstNode* nodep) VL_PURE { + UASSERT_OBJ(!nodep || privateTypeTest(nodep), nodep, + "AstNode is not of expected type, but instead has type '" << nodep->typeName() + << "'"); + return unsafePrivateAs(nodep); } // Predicate that returns true if the given 'nodep' might have a descendant of type 'T_Node'. diff --git a/src/V3AstInlines.h b/src/V3AstInlines.h index d2325c14b..cff4fd9e5 100644 --- a/src/V3AstInlines.h +++ b/src/V3AstInlines.h @@ -154,12 +154,15 @@ AstCExpr::AstCExpr(FileLine* fl, const string& textStmt, int setwidth, bool clea } AstVarRef::AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access) - : ASTGEN_SUPER_VarRef(fl, varp->name(), varp, access) {} + : ASTGEN_SUPER_VarRef(fl, varp, access) {} // This form only allowed post-link (see above) AstVarRef::AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access) - : ASTGEN_SUPER_VarRef(fl, varscp->varp()->name(), varscp->varp(), access) { + : ASTGEN_SUPER_VarRef(fl, varscp->varp(), access) { varScopep(varscp); } + +string AstVarRef::name() const { return varp() ? varp()->name() : ""; } + bool AstVarRef::same(const AstVarRef* samep) const { if (varScopep()) { return (varScopep() == samep->varScopep() && access() == samep->access()); @@ -179,7 +182,8 @@ bool AstVarRef::sameNoLvalue(AstVarRef* samep) const { } AstVarXRef::AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const VAccess& access) - : ASTGEN_SUPER_VarXRef(fl, varp->name(), varp, access) + : ASTGEN_SUPER_VarXRef(fl, varp, access) + , m_name{varp->name()} , m_dotted{dotted} { dtypeFrom(varp); } diff --git a/src/V3AstNodeDType.h b/src/V3AstNodeDType.h index a74eeec6f..180d14cca 100644 --- a/src/V3AstNodeDType.h +++ b/src/V3AstNodeDType.h @@ -126,13 +126,13 @@ public: const char* charIQWN() const { return (isString() ? "N" : isWide() ? "W" : isQuad() ? "Q" : "I"); } - string cType(const string& name, bool forFunc, bool isRef) const VL_MT_STABLE; + string cType(const string& name, bool forFunc, bool isRef) const; // Represents a C++ LiteralType? (can be constexpr) bool isLiteralType() const VL_MT_STABLE; private: class CTypeRecursed; - CTypeRecursed cTypeRecurse(bool compound) const VL_MT_STABLE; + CTypeRecursed cTypeRecurse(bool compound) const; }; class AstNodeArrayDType VL_NOT_FINAL : public AstNodeDType { // Array data type, ie "some_dtype var_name [2:0]" @@ -199,12 +199,9 @@ class AstNodeUOrStructDType VL_NOT_FINAL : public AstNodeDType { // A struct or union; common handling // @astgen op1 := membersp : List[AstMemberDType] private: - // TYPES - using MemberNameMap = std::map; // MEMBERS string m_name; // Name from upper typedef, if any - AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy - MemberNameMap m_members; + AstNodeModule* m_classOrPackagep = nullptr; // Package it will be emitted with const int m_uniqueNum; bool m_packed; bool m_isFourstate = false; // V3Width computes @@ -250,12 +247,6 @@ public: static bool packedUnsup() { return true; } void isFourstate(bool flag) { m_isFourstate = flag; } bool isFourstate() const override VL_MT_SAFE { return m_isFourstate; } - void clearCache() { m_members.clear(); } - void repairMemberCache(); - AstMemberDType* findMember(const string& name) const { - const auto it = m_members.find(name); - return (it == m_members.end()) ? nullptr : it->second; - } static int lo() { return 0; } int hi() const { return dtypep()->width() - 1; } // Packed classes look like arrays VNumRange declRange() const { return VNumRange{hi(), lo()}; } @@ -1062,7 +1053,7 @@ private: // Post-width typedefs are removed and point to type directly AstNodeDType* m_refDTypep = nullptr; // data type pointed to, BELOW the AstTypedef string m_name; // Name of an AstTypedef - AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy + AstNodeModule* m_classOrPackagep = nullptr; // Class/package in which it was defined public: AstRefDType(FileLine* fl, const string& name) : ASTGEN_SUPER_RefDType(fl) @@ -1077,6 +1068,7 @@ public: AstRefDType(FileLine* fl, FlagTypeOfExpr, AstNode* typeofp) : ASTGEN_SUPER_RefDType(fl) { this->typeofp(typeofp); + if (AstNodeDType* const dtp = VN_CAST(typeofp, NodeDType)) refDTypep(dtp); } ASTGEN_MEMBERS_AstRefDType; // METHODS @@ -1188,6 +1180,34 @@ public: int widthTotalBytes() const override { return sizeof(std::map); } bool isCompound() const override { return true; } }; +class AstStreamDType final : public AstNodeDType { + // Stream data type, used only as data type of stream operations + // Should behave like AstPackArrayDType, but it doesn't have a size +public: + explicit AstStreamDType(FileLine* fl) + : ASTGEN_SUPER_StreamDType(fl) { + dtypep(this); + } + ASTGEN_MEMBERS_AstStreamDType; + void dumpSmall(std::ostream& str) const override; + bool hasDType() const override { return true; } + bool maybePointedTo() const override { return true; } + bool undead() const override { return true; } + AstNodeDType* subDTypep() const override VL_MT_SAFE { return nullptr; } + AstNodeDType* virtRefDTypep() const override { return nullptr; } + void virtRefDTypep(AstNodeDType* nodep) override {} + bool similarDType(const AstNodeDType* samep) const override { return this == samep; } + AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; } + // cppcheck-suppress csyleCast + AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; } + // cppcheck-suppress csyleCast + AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } + // cppcheck-suppress csyleCast + AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } + int widthAlignBytes() const override { return 1; } + int widthTotalBytes() const override { return 1; } + bool isCompound() const override { return false; } +}; class AstUnsizedArrayDType final : public AstNodeDType { // Unsized/open-range Array data type, ie "some_dtype var_name []" // @astgen op1 := childDTypep : Optional[AstNodeDType] // moved to refDTypep() in V3Width diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 3ccd63be5..c59775da1 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -214,7 +214,7 @@ class AstNodeFTaskRef VL_NOT_FINAL : public AstNodeExpr { // @astgen op3 := pinsp : List[AstNodeExpr] // @astgen op4 := scopeNamep : Optional[AstScopeName] AstNodeFTask* m_taskp = nullptr; // [AfterLink] Pointer to task referenced - AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy + AstNodeModule* m_classOrPackagep = nullptr; // Class/package of the task string m_name; // Name of variable string m_dotted; // Dotted part of scope the name()ed task/func is under or "" string m_inlinedDots; // Dotted hierarchy flattened out @@ -449,21 +449,18 @@ class AstNodeVarRef VL_NOT_FINAL : public AstNodeExpr { VAccess m_access; // Left hand side assignment AstVar* m_varp; // [AfterLink] Pointer to variable itself AstVarScope* m_varScopep = nullptr; // Varscope for hierarchy - AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy - string m_name; // Name of variable + AstNodeModule* m_classOrPackagep = nullptr; // Class/package of the variable string m_selfPointer; // Output code object pointer (e.g.: 'this') protected: - AstNodeVarRef(VNType t, FileLine* fl, const string& name, const VAccess& access) + AstNodeVarRef(VNType t, FileLine* fl, const VAccess& access) : AstNodeExpr{t, fl} - , m_access{access} - , m_name{name} { + , m_access{access} { varp(nullptr); } - AstNodeVarRef(VNType t, FileLine* fl, const string& name, AstVar* varp, const VAccess& access) + AstNodeVarRef(VNType t, FileLine* fl, AstVar* varp, const VAccess& access) : AstNodeExpr{t, fl} - , m_access{access} - , m_name{name} { + , m_access{access} { // May have varp==nullptr this->varp(varp); } @@ -474,8 +471,6 @@ public: const char* broken() const override; int instrCount() const override { return widthInstrs(); } void cloneRelink() override; - string name() const override VL_MT_STABLE { return m_name; } // * = Var name - void name(const string& name) override { m_name = name; } VAccess access() const { return m_access; } void access(const VAccess& flag) { m_access = flag; } // Avoid using this; Set in constructor AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable @@ -721,7 +716,7 @@ class AstClassOrPackageRef final : public AstNodeExpr { private: string m_name; // Node not NodeModule to appease some early parser usage - AstNode* m_classOrPackageNodep; // Package hierarchy + AstNode* m_classOrPackageNodep; // Pointer to class/package referenced public: AstClassOrPackageRef(FileLine* fl, const string& name, AstNode* classOrPackageNodep, AstPin* paramsp) @@ -1062,7 +1057,7 @@ public: }; class AstEnumItemRef final : public AstNodeExpr { AstEnumItem* m_itemp; // [AfterLink] Pointer to item - AstNodeModule* m_classOrPackagep; // Package hierarchy + AstNodeModule* m_classOrPackagep; // Class/package in which it was defined public: AstEnumItemRef(FileLine* fl, AstEnumItem* itemp, AstNodeModule* classOrPackagep) : ASTGEN_SUPER_EnumItemRef(fl) @@ -1428,6 +1423,7 @@ class AstMemberSel final : public AstNodeExpr { // @astgen op1 := fromp : AstNodeExpr // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it string m_name; + VAccess m_access; // Read or write, as in AstNodeVarRef AstVar* m_varp = nullptr; // Post link, variable within class that is target of selection public: AstMemberSel(FileLine* fl, AstNodeExpr* fromp, VFlagChildDType, const string& name) @@ -1448,10 +1444,12 @@ public: void dump(std::ostream& str) const override; string name() const override VL_MT_STABLE { return m_name; } void name(const string& name) override { m_name = name; } + VAccess access() const { return m_access; } + void access(const VAccess& flag) { m_access = flag; } string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return true; } - bool same(const AstNode* samep) const override { return true; } // dtype comparison does it + bool same(const AstNode* samep) const override; int instrCount() const override { return widthInstrs(); } AstVar* varp() const { return m_varp; } void varp(AstVar* nodep) { m_varp = nodep; } @@ -1911,7 +1909,7 @@ public: bool same(const AstNode* /*samep*/) const override { return true; } }; class AstStructSel final : public AstNodeExpr { - // Unpacked struct member access + // Unpacked struct/union member access // Parents: math|stmt // Children: varref, math // @astgen op1 := fromp : AstNodeExpr @@ -1929,7 +1927,10 @@ public: void name(const string& name) override { m_name = name; } string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } - bool cleanOut() const override { return false; } + bool cleanOut() const override { + // Not a union + return VN_IS(fromp()->dtypep()->skipRefp(), StructDType); + } bool same(const AstNode* samep) const override { const AstStructSel* const sp = static_cast(samep); return m_name == sp->m_name; @@ -4671,7 +4672,7 @@ public: ASTGEN_MEMBERS_AstCvtPackString; void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAssign(lhs); } string emitVerilog() override { return "%f$_CAST(%l)"; } - string emitC() override { return "VL_CVT_PACK_STR_N%lq(%lW, %li)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return true; } bool cleanLhs() const override { return true; } bool sizeMattersLhs() const override { return false; } @@ -5349,15 +5350,15 @@ public: class AstVarRef final : public AstNodeVarRef { // A reference to a variable (lvalue or rvalue) public: - AstVarRef(FileLine* fl, const string& name, const VAccess& access) - : ASTGEN_SUPER_VarRef(fl, name, nullptr, access) {} // This form only allowed post-link because output/wire compression may // lead to deletion of AstVar's inline AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access); // This form only allowed post-link (see above) inline AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access); ASTGEN_MEMBERS_AstVarRef; + inline string name() const override; // * = Var name void dump(std::ostream& str) const override; + const char* broken() const override; bool same(const AstNode* samep) const override; inline bool same(const AstVarRef* samep) const; inline bool sameNoLvalue(AstVarRef* samep) const; @@ -5369,14 +5370,17 @@ public: class AstVarXRef final : public AstNodeVarRef { // A VarRef to something in another module before AstScope. // Includes pin on a cell, as part of a ASSIGN statement to connect I/Os until AstScope + string m_name; string m_dotted; // Dotted part of scope the name()'ed reference is under or "" string m_inlinedDots; // Dotted hierarchy flattened out public: AstVarXRef(FileLine* fl, const string& name, const string& dotted, const VAccess& access) - : ASTGEN_SUPER_VarXRef(fl, name, nullptr, access) + : ASTGEN_SUPER_VarXRef(fl, nullptr, access) + , m_name{name} , m_dotted{dotted} {} inline AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const VAccess& access); ASTGEN_MEMBERS_AstVarXRef; + string name() const override VL_MT_STABLE { return m_name; } // * = Var name void dump(std::ostream& str) const override; string dotted() const { return m_dotted; } void dotted(const string& dotted) { m_dotted = dotted; } diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 90e475d15..dc5f038e1 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -86,7 +86,7 @@ private: bool m_recursive : 1; // Recursive or part of recursion bool m_underGenerate : 1; // Under generate (for warning) bool m_virtual : 1; // Virtual method in class - bool m_fromStd : 1; // Part of std + bool m_needProcess : 1; // Implements part of a process that allocates std::process VLifetime m_lifetime; // Lifetime protected: AstNodeFTask(VNType t, FileLine* fl, const string& name, AstNode* stmtsp) @@ -112,7 +112,7 @@ protected: , m_recursive{false} , m_underGenerate{false} , m_virtual{false} - , m_fromStd{false} { + , m_needProcess{false} { addStmtsp(stmtsp); cname(name); // Might be overridden by dpi import/export } @@ -172,8 +172,8 @@ public: bool underGenerate() const { return m_underGenerate; } void isVirtual(bool flag) { m_virtual = flag; } bool isVirtual() const { return m_virtual; } - void isFromStd(bool flag) { m_fromStd = flag; } - bool isFromStd() const { return m_fromStd; } + void setNeedProcess() { m_needProcess = true; } + bool needProcess() const { return m_needProcess; } void lifetime(const VLifetime& flag) { m_lifetime = flag; } VLifetime lifetime() const { return m_lifetime; } bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); } @@ -1513,6 +1513,7 @@ class AstTypeTable final : public AstNode { AstEmptyQueueDType* m_emptyQueuep = nullptr; AstQueueDType* m_queueIndexp = nullptr; AstVoidDType* m_voidp = nullptr; + AstStreamDType* m_streamp = nullptr; AstBasicDType* m_basicps[VBasicDTypeKwd::_ENUM_MAX]{}; // using DetailedMap = std::map; @@ -1538,6 +1539,7 @@ public: AstEmptyQueueDType* findEmptyQueueDType(FileLine* fl); AstQueueDType* findQueueIndexDType(FileLine* fl); AstVoidDType* findVoidDType(FileLine* fl); + AstStreamDType* findStreamDType(FileLine* fl); void clearCache(); void repairCache(); void dump(std::ostream& str = std::cout) const override; @@ -1810,7 +1812,7 @@ public: string dpiTmpVarType(const string& varName) const; // Return Verilator internal type for argument: CData, SData, IData, WData string vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc = "", - bool asRef = false) const VL_MT_STABLE; + bool asRef = false) const; string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc string vlPropDecl(const string& propName) const; // Return VerilatorVarProps declaration @@ -2135,17 +2137,13 @@ public: // === AstNodeModule === class AstClass final : public AstNodeModule { // @astgen op4 := extendsp : List[AstClassExtends] - // TYPES - using MemberNameMap = std::map; // MEMBERS - MemberNameMap m_members; // Members or method children - AstClassPackage* m_classOrPackagep = nullptr; // Class package this is under + AstClassPackage* m_classOrPackagep = nullptr; // Package it will be emitted with bool m_extended = false; // Is extension or extended by other classes bool m_interfaceClass = false; // Interface class bool m_needRNG = false; // Need RNG, uses srandom/randomize bool m_virtual = false; // Virtual class bool m_parameterized = false; // Parameterized class - void insertCache(AstNode* nodep); public: AstClass(FileLine* fl, const string& name) @@ -2160,16 +2158,7 @@ public: AstClassPackage* classOrPackagep() const VL_MT_SAFE { return m_classOrPackagep; } void classOrPackagep(AstClassPackage* classpackagep) { m_classOrPackagep = classpackagep; } AstNode* membersp() const { return stmtsp(); } - void addMembersp(AstNode* nodep) { - insertCache(nodep); - addStmtsp(nodep); - } - void clearCache() { m_members.clear(); } - void repairCache(); - AstNode* findMember(const string& name) const { - const auto it = m_members.find(name); - return (it == m_members.end()) ? nullptr : it->second; - } + void addMembersp(AstNode* nodep) { addStmtsp(nodep); } bool isExtended() const { return m_extended; } void isExtended(bool flag) { m_extended = flag; } bool isInterfaceClass() const { return m_interfaceClass; } @@ -2185,6 +2174,7 @@ public: static bool isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp); // Return the lowest class extended from, or this class AstClass* baseMostClassp(); + static bool isCacheableChild(const AstNode* nodep); }; class AstClassPackage final : public AstNodeModule { // The static information portion of a class (treated similarly to a package) diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 45a99e7ce..ad31bc0f4 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -103,29 +103,8 @@ int AstNodeSel::bitConst() const { return (constp ? constp->toSInt() : 0); } -void AstNodeUOrStructDType::repairMemberCache() { - clearCache(); - for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) { - if (m_members.find(itemp->name()) != m_members.end()) { - itemp->v3error("Duplicate declaration of member name: " << itemp->prettyNameQ()); - } else { - m_members.emplace(itemp->name(), itemp); - } - } -} - const char* AstNodeUOrStructDType::broken() const { BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); - std::unordered_set exists; - for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) { - exists.insert(itemp); - } - for (MemberNameMap::const_iterator it = m_members.begin(); it != m_members.end(); ++it) { - if (VL_UNCOVERABLE(exists.find(it->second) == exists.end())) { - this->v3error("Internal: Structure member broken: " << it->first); - return "member broken"; - } - } return nullptr; } @@ -399,7 +378,7 @@ string AstVar::verilogKwd() const { } string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc, - bool asRef) const VL_MT_STABLE { + bool asRef) const { UASSERT_OBJ(!forReturn, this, "Internal data is never passed as return, but as first argument"); string ostatic; @@ -716,12 +695,12 @@ public: } }; -string AstNodeDType::cType(const string& name, bool /*forFunc*/, bool isRef) const VL_MT_STABLE { +string AstNodeDType::cType(const string& name, bool /*forFunc*/, bool isRef) const { const CTypeRecursed info = cTypeRecurse(false); return info.render(name, isRef); } -AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const VL_MT_STABLE { +AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const { // Legacy compound argument currently just passed through and unused CTypeRecursed info; @@ -1071,6 +1050,15 @@ AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) { return m_voidp; } +AstStreamDType* AstTypeTable::findStreamDType(FileLine* fl) { + if (VL_UNLIKELY(!m_streamp)) { + AstStreamDType* const newp = new AstStreamDType{fl}; + addTypesp(newp); + m_streamp = newp; + } + return m_streamp; +} + AstQueueDType* AstTypeTable::findQueueIndexDType(FileLine* fl) { if (VL_UNLIKELY(!m_queueIndexp)) { AstQueueDType* const newp = new AstQueueDType{fl, AstNode::findUInt32DType(), nullptr}; @@ -1418,29 +1406,10 @@ const char* AstClassPackage::broken() const { void AstClassPackage::cloneRelink() { if (m_classp && m_classp->clonep()) m_classp = m_classp->clonep(); } -void AstClass::insertCache(AstNode* nodep) { - const bool doit = (VN_IS(nodep, Var) || VN_IS(nodep, EnumItemRef) - || (VN_IS(nodep, NodeFTask) && !VN_AS(nodep, NodeFTask)->isExternProto()) - || VN_IS(nodep, CFunc)); - if (doit) { - if (m_members.find(nodep->name()) != m_members.end()) { - nodep->v3error("Duplicate declaration of member name: " << nodep->prettyNameQ()); - } else { - m_members.emplace(nodep->name(), nodep); - } - } -} -void AstClass::repairCache() { - clearCache(); - for (auto* itemp = membersp(); itemp; itemp = itemp->nextp()) { - if (const auto* const scopep = VN_CAST(itemp, Scope)) { - for (auto* blockp = scopep->blocksp(); blockp; blockp = blockp->nextp()) { - insertCache(blockp); - } - } else { - insertCache(itemp); - } - } +bool AstClass::isCacheableChild(const AstNode* nodep) { + return (VN_IS(nodep, Var) || VN_IS(nodep, EnumItemRef) + || (VN_IS(nodep, NodeFTask) && !VN_AS(nodep, NodeFTask)->isExternProto()) + || VN_IS(nodep, CFunc)); } AstClass* AstClass::baseMostClassp() { AstClass* basep = this; @@ -1667,6 +1636,12 @@ AstNodeUOrStructDType* AstMemberDType::getChildStructp() const { return VN_CAST(subdtp, NodeUOrStructDType); // Maybe nullptr } +bool AstMemberSel::same(const AstNode* samep) const { + const AstMemberSel* const sp = static_cast(samep); + return sp != nullptr && access() == sp->access() && fromp()->same(sp->fromp()) + && name() == sp->name() && varp()->same(sp->varp()); +} + void AstMemberSel::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); str << " -> "; @@ -2055,6 +2030,10 @@ void AstVoidDType::dumpSmall(std::ostream& str) const { this->AstNodeDType::dumpSmall(str); str << "void"; } +void AstStreamDType::dumpSmall(std::ostream& str) const { + this->AstNodeDType::dumpSmall(str); + str << "stream"; +} void AstVarScope::dump(std::ostream& str) const { this->AstNode::dump(str); if (isTrace()) str << " [T]"; @@ -2097,6 +2076,10 @@ void AstVarRef::dump(std::ostream& str) const { str << "UNLINKED"; } } +const char* AstVarRef::broken() const { + BROKEN_RTN(!varp()); + return AstNodeVarRef::broken(); +} bool AstVarRef::same(const AstNode* samep) const { return same(static_cast(samep)); } diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index d18f4be1d..abe27a1dc 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -40,39 +40,6 @@ VL_DEFINE_DEBUG_FUNCTIONS; //###################################################################### -class RenameStaticVisitor final : public VNVisitor { -private: - // STATE - const std::set& m_staticFuncVarsr; // Static variables from m_ftaskp - AstNodeFTask* const m_ftaskp; // Current function/task - - // VISITORS - void visit(AstVarRef* nodep) override { - const auto it = m_staticFuncVarsr.find(nodep->varp()); - if (it != m_staticFuncVarsr.end()) nodep->name((*it)->name()); - iterateChildren(nodep); - } - - void visit(AstInitialStatic* nodep) override { - iterateChildren(nodep); - nodep->unlinkFrBack(); - m_ftaskp->addHereThisAsNext(nodep); - } - - void visit(AstNode* nodep) override { iterateChildren(nodep); } - -public: - // CONSTRUCTORS - RenameStaticVisitor(std::set& staticFuncVars, AstNodeFTask* ftaskp, AstNode* nodep) - : m_staticFuncVarsr(staticFuncVars) - , m_ftaskp(ftaskp) { - iterateChildren(nodep); - } - ~RenameStaticVisitor() override = default; -}; - -//###################################################################### - class BeginState final { private: // NODE STATE @@ -105,7 +72,6 @@ private: string m_unnamedScope; // Name of begin blocks, including unnamed blocks int m_ifDepth = 0; // Current if depth bool m_keepBegins = false; // True if begins should not be inlined - std::set m_staticFuncVars; // Static variables from m_ftaskp // METHODS @@ -212,7 +178,10 @@ private: m_ftaskp = nodep; m_liftedp = nullptr; iterateChildren(nodep); - RenameStaticVisitor{m_staticFuncVars, m_ftaskp, nodep}; + nodep->foreach([&](AstInitialStatic* const initp) { + initp->unlinkFrBack(); + m_ftaskp->addHereThisAsNext(initp); + }); if (m_liftedp) { // Place lifted nodes at beginning of stmtsp, so Var nodes appear before referenced if (AstNode* const stmtsp = nodep->stmtsp()) { @@ -222,7 +191,6 @@ private: nodep->addStmtsp(m_liftedp); m_liftedp = nullptr; } - m_staticFuncVars.clear(); m_ftaskp = nullptr; } } @@ -266,7 +234,6 @@ private: nodep->name(newName); nodep->unlinkFrBack(); m_ftaskp->addHereThisAsNext(nodep); - m_staticFuncVars.insert(nodep); nodep->funcLocal(false); } else if (m_unnamedScope != "") { // Rename it @@ -377,7 +344,6 @@ private: void visit(AstVarRef* nodep) override { if (nodep->varp()->user1()) { // It was converted UINFO(9, " relinVarRef " << nodep << endl); - nodep->name(nodep->varp()->name()); } iterateChildren(nodep); } diff --git a/src/V3Class.cpp b/src/V3Class.cpp index 3653b8b2d..ab62db18c 100644 --- a/src/V3Class.cpp +++ b/src/V3Class.cpp @@ -67,6 +67,7 @@ private: nodep->editCountInc(); nodep->classOrPackagep(packagep); packagep->classp(nodep); + packagep->timeunit(nodep->timeunit()); v3Global.rootp()->addModulesp(packagep); // Add package to hierarchy AstCell* const cellp = new AstCell{packagep->fileline(), @@ -105,7 +106,6 @@ private: m_prefix = nodep->name() + "__02e"; // . iterateChildren(nodep); } - nodep->repairCache(); } void visit(AstNodeModule* nodep) override { // Visit for NodeModules that are not AstClass (AstClass is-a AstNodeModule) diff --git a/src/V3Clean.cpp b/src/V3Clean.cpp index f69d0e153..026ebe039 100644 --- a/src/V3Clean.cpp +++ b/src/V3Clean.cpp @@ -95,6 +95,7 @@ private: || VN_IS(nodep->dtypep()->skipRefp(), DynArrayDType) || VN_IS(nodep->dtypep()->skipRefp(), ClassRefDType) || VN_IS(nodep->dtypep()->skipRefp(), QueueDType) + || VN_IS(nodep->dtypep()->skipRefp(), StreamDType) || VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType) || VN_IS(nodep->dtypep()->skipRefp(), VoidDType)) { } else { @@ -234,11 +235,6 @@ private: operandTriop(nodep); setClean(nodep, nodep->cleanOut()); } - void visit(AstStructSel* nodep) override { - iterateChildren(nodep); - AstStructDType* dtypep = VN_CAST(nodep->dtypep()->skipRefp(), StructDType); - setClean(nodep, dtypep && !dtypep->packed()); - } void visit(AstUCFunc* nodep) override { iterateChildren(nodep); computeCppWidth(nodep); diff --git a/src/V3Const.cpp b/src/V3Const.cpp index f0656eaa5..c8448ff6c 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -2166,7 +2166,12 @@ private: AstNodeExpr* const srcp = nodep->rhsp()->unlinkFrBack(); // Connect the rhs to the stream operator and update its width VN_AS(streamp, StreamL)->lhsp(srcp); - streamp->dtypeSetLogicUnsized(srcp->width(), srcp->widthMin(), VSigning::UNSIGNED); + if (VN_IS(srcp->dtypep(), DynArrayDType) || VN_IS(srcp->dtypep(), QueueDType) + || VN_IS(srcp->dtypep(), UnpackArrayDType)) { + streamp->dtypeSetStream(); + } else { + streamp->dtypeSetLogicUnsized(srcp->width(), srcp->widthMin(), VSigning::UNSIGNED); + } // Shrink the RHS if necessary if (sWidth > dWidth) { streamp = new AstSel{streamp->fileline(), streamp, sWidth - dWidth, dWidth}; @@ -3650,6 +3655,7 @@ private: public: // Processing Mode Enum enum ProcMode : uint8_t { + PROC_PARAMS_NOWARN, PROC_PARAMS, PROC_GENERATE, PROC_LIVE, @@ -3665,16 +3671,18 @@ public: , m_concswapNames{globalPass ? ("__Vconcswap_" + cvtToStr(s_globalPassNum++)) : ""} { // clang-format off switch (pmode) { - case PROC_PARAMS: m_doV = true; m_doNConst = true; m_params = true; - m_required = true; break; - case PROC_GENERATE: m_doV = true; m_doNConst = true; m_params = true; - m_required = true; m_doGenerate = true; break; - case PROC_LIVE: break; - case PROC_V_WARN: m_doV = true; m_doNConst = true; m_warn = true; break; - case PROC_V_NOWARN: m_doV = true; m_doNConst = true; break; - case PROC_V_EXPENSIVE: m_doV = true; m_doNConst = true; m_doExpensive = true; break; - case PROC_CPP: m_doV = false; m_doNConst = true; m_doCpp = true; break; - default: v3fatalSrc("Bad case"); break; + case PROC_PARAMS_NOWARN: m_doV = true; m_doNConst = true; m_params = true; + m_required = false; break; + case PROC_PARAMS: m_doV = true; m_doNConst = true; m_params = true; + m_required = true; break; + case PROC_GENERATE: m_doV = true; m_doNConst = true; m_params = true; + m_required = true; m_doGenerate = true; break; + case PROC_LIVE: break; + case PROC_V_WARN: m_doV = true; m_doNConst = true; m_warn = true; break; + case PROC_V_NOWARN: m_doV = true; m_doNConst = true; break; + case PROC_V_EXPENSIVE: m_doV = true; m_doNConst = true; m_doExpensive = true; break; + case PROC_CPP: m_doV = false; m_doNConst = true; m_doCpp = true; break; + default: v3fatalSrc("Bad case"); break; } // clang-format on } @@ -3722,6 +3730,29 @@ AstNode* V3Const::constifyParamsEdit(AstNode* nodep) { return nodep; } +//! Constify this cell node's parameter list if possible +//! @return Pointer to the edited node. +AstNode* V3Const::constifyParamsNoWarnEdit(AstNode* nodep) { + // if (debug() > 0) nodep->dumpTree("- forceConPRE : "); + // Resize even if the node already has a width, because buried in the tree + // we may have a node we just created with signing, etc, that isn't sized yet. + + // Make sure we've sized everything first + nodep = V3Width::widthParamsEdit(nodep); + ConstVisitor visitor{ConstVisitor::PROC_PARAMS_NOWARN, /* globalPass: */ false}; + if (AstVar* const varp = VN_CAST(nodep, Var)) { + // If a var wants to be constified, it's really a param, and + // we want the value to be constant. We aren't passed just the + // init value because we need widthing above to handle the var's type. + if (varp->valuep()) visitor.mainAcceptEdit(varp->valuep()); + } else { + nodep = visitor.mainAcceptEdit(nodep); + } + // Because we do edits, nodep links may get trashed and core dump this. + // if (debug() > 0) nodep->dumpTree("- forceConDONE: "); + return nodep; +} + //! Force this cell node's parameter list to become a constant inside generate. //! If we are inside a generated "if", "case" or "for", we don't want to //! trigger warnings when we deal with the width. It is possible that these diff --git a/src/V3Const.h b/src/V3Const.h index c171a5afe..a0c0cf797 100644 --- a/src/V3Const.h +++ b/src/V3Const.h @@ -30,6 +30,10 @@ public: static AstNodeExpr* constifyParamsEdit(AstNodeExpr* exprp) { return VN_AS(constifyParamsEdit(static_cast(exprp)), NodeExpr); } + static AstNode* constifyParamsNoWarnEdit(AstNode* nodep); + static AstNodeExpr* constifyParamsNoWarnEdit(AstNodeExpr* exprp) { + return VN_AS(constifyParamsNoWarnEdit(static_cast(exprp)), NodeExpr); + } static AstNode* constifyGenerateParamsEdit(AstNode* nodep); // Only do constant pushing, without removing dead logic static void constifyAllLive(AstNetlist* nodep); diff --git a/src/V3DfgPeephole.h b/src/V3DfgPeephole.h index a20cadf6a..70cf8e044 100644 --- a/src/V3DfgPeephole.h +++ b/src/V3DfgPeephole.h @@ -123,9 +123,9 @@ struct V3DfgPeepholeContext final { const std::string m_label; // Label to apply to stats // Enable flags for each optimization - bool m_enabled[VDfgPeepholePattern::_ENUM_END]; + std::array m_enabled; // Count of applications for each optimization (for statistics) - VDouble0 m_count[VDfgPeepholePattern::_ENUM_END]; + std::array m_count; explicit V3DfgPeepholeContext(const std::string& label); ~V3DfgPeepholeContext(); diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index 4be6b7b91..88fa6cae6 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -62,7 +62,7 @@ public: static string symClassAssign() { return symClassName() + "* const __restrict vlSymsp VL_ATTR_UNUSED = vlSelf->vlSymsp;\n"; } - static string prefixNameProtect(const AstNode* nodep) VL_MT_STABLE { // C++ name with prefix + static string prefixNameProtect(const AstNode* nodep) { // C++ name with prefix return v3Global.opt.modPrefix() + "_" + VIdProtect::protect(nodep->name()); } static bool isAnonOk(const AstVar* varp) { diff --git a/src/V3EmitCFunc.cpp b/src/V3EmitCFunc.cpp index 195e41ea8..cbb894671 100644 --- a/src/V3EmitCFunc.cpp +++ b/src/V3EmitCFunc.cpp @@ -419,7 +419,7 @@ void EmitCFunc::emitCCallArgs(const AstNodeCCall* nodep, const string& selfPoint } if (nodep->funcp()->needProcess()) { if (comma) puts(", "); - if (VN_IS(nodep->backp(), CAwait)) { + if (VN_IS(nodep->backp(), CAwait) || !nodep->funcp()->isCoroutine()) { puts("vlProcess"); } else { puts("std::make_shared()"); @@ -452,6 +452,10 @@ void EmitCFunc::emitCvtPackStr(AstNode* nodep) { putbs("std::string{"); putsQuoted(constp->num().toString()); puts("}"); + } else if (VN_IS(nodep->dtypep(), StreamDType)) { + putbs("VL_CVT_PACK_STR_ND("); + iterateAndNextConstNull(nodep); + puts(")"); } else { putbs("VL_CVT_PACK_STR_N"); emitIQW(nodep); diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index be40a5f53..ba7c10e54 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -22,6 +22,7 @@ #include "V3EmitCConstInit.h" #include "V3Global.h" +#include "V3MemberMap.h" #include #include @@ -115,6 +116,7 @@ public: class EmitCFunc VL_NOT_FINAL : public EmitCConstInit { private: + VMemberMap m_memberMap; AstVarRef* m_wideTempRefp = nullptr; // Variable that _WW macros should be setting int m_labelNum = 0; // Next label number int m_splitSize = 0; // # of cfunc nodes placed into output file @@ -148,6 +150,22 @@ protected: bool m_useSelfForThis = false; // Replace "this" with "vlSelf" const AstNodeModule* m_modp = nullptr; // Current module being emitted const AstCFunc* m_cfuncp = nullptr; // Current function being emitted + bool m_instantiatesOwnProcess = false; + + bool constructorNeedsProcess(const AstClass* const classp) { + const AstNode* const newp = m_memberMap.findMember(classp, "new"); + if (!newp) return false; + const AstCFunc* const ctorp = VN_CAST(newp, CFunc); + if (!ctorp) return false; + UASSERT_OBJ(ctorp->isConstructor(), ctorp, "`new` is not a constructor!"); + return ctorp->needProcess(); + } + + bool constructorNeedsProcess(const AstNodeDType* const dtypep) { + if (const AstClassRefDType* const crefdtypep = VN_CAST(dtypep, ClassRefDType)) + return constructorNeedsProcess(crefdtypep->classp()); + return false; + } public: // METHODS @@ -212,13 +230,34 @@ public: comma = true; } } + template + string optionalProcArg(const T* const nodep) { + return (nodep && constructorNeedsProcess(nodep)) ? "vlProcess, " : ""; + } + const AstCNew* getSuperNewCallRecursep(AstNode* const nodep) { + // Get the super.new call + if (!nodep) return nullptr; + if (const AstCNew* const cnewp = VN_CAST(nodep, CNew)) return cnewp; + if (const AstStmtExpr* const stmtp = VN_CAST(nodep, StmtExpr)) { + if (const AstCNew* const cnewp = VN_CAST(stmtp->exprp(), CNew)) return cnewp; + } + if (const AstJumpBlock* const blockp = VN_CAST(nodep, JumpBlock)) { + if (const AstCNew* const cnewp = getSuperNewCallRecursep(blockp->stmtsp())) { + return cnewp; + } + } + if (const AstCNew* const cnewp = getSuperNewCallRecursep(nodep->nextp())) return cnewp; + return nullptr; + } // VISITORS using EmitCConstInit::visit; void visit(AstCFunc* nodep) override { VL_RESTORER(m_useSelfForThis); VL_RESTORER(m_cfuncp); + VL_RESTORER(m_instantiatesOwnProcess) m_cfuncp = nodep; + m_instantiatesOwnProcess = false; splitSizeInc(nodep); @@ -231,20 +270,16 @@ public: if (!nodep->baseCtors().empty()) { puts(": "); puts(nodep->baseCtors()); - puts("(vlSymsp"); + const AstClass* const classp = VN_CAST(nodep->scopep()->modp(), Class); // Find call to super.new to get the arguments - for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { - AstNode* exprp; - if (VN_IS(stmtp, StmtExpr)) { - exprp = VN_CAST(stmtp, StmtExpr)->exprp(); - } else { - exprp = stmtp; - } - if (AstCNew* const newRefp = VN_CAST(exprp, CNew)) { - putCommaIterateNext(newRefp->argsp(), true); - break; - } + if (classp && constructorNeedsProcess(classp)) { + puts("(vlProcess, vlSymsp"); + } else { + puts("(vlSymsp"); } + const AstCNew* const superNewCallp = getSuperNewCallRecursep(nodep->stmtsp()); + UASSERT_OBJ(superNewCallp, nodep, "super.new call not found"); + putCommaIterateNext(superNewCallp->argsp(), true); puts(")"); } puts(" {\n"); @@ -265,6 +300,23 @@ public: puts(nodep->isLoose() ? "__" : "::"); puts(nodep->nameProtect() + "\\n\"); );\n"); + // Instantiate a process class if it's going to be needed somewhere later + nodep->forall([&](const AstNodeCCall* ccallp) -> bool { + if (ccallp->funcp()->needProcess() + && (ccallp->funcp()->isCoroutine() == VN_IS(ccallp->backp(), CAwait))) { + if (!nodep->needProcess() && !m_instantiatesOwnProcess) { + m_instantiatesOwnProcess = true; + return false; + } + } + return true; + }); + if (m_instantiatesOwnProcess) { + AstNode* const vlprocp = new AstCStmt{ + nodep->fileline(), "VlProcessRef vlProcess = std::make_shared();\n"}; + nodep->stmtsp()->addHereThisAsNext(vlprocp); + } + for (AstNode* subnodep = nodep->argsp(); subnodep; subnodep = subnodep->nextp()) { if (AstVar* const varp = VN_CAST(subnodep, Var)) { if (varp->isFuncReturn()) emitVarDecl(varp); @@ -383,19 +435,17 @@ public: void visit(AstAssocSel* nodep) override { iterateAndNextConstNull(nodep->fromp()); putbs(".at("); - AstAssocArrayDType* const adtypep = VN_AS(nodep->fromp()->dtypep(), AssocArrayDType); + AstAssocArrayDType* const adtypep + = VN_AS(nodep->fromp()->dtypep()->skipRefp(), AssocArrayDType); UASSERT_OBJ(adtypep, nodep, "Associative select on non-associative type"); - if (adtypep->keyDTypep()->isWide()) { - emitCvtWideArray(nodep->bitp(), nodep->fromp()); - } else { - iterateAndNextConstNull(nodep->bitp()); - } + iterateAndNextConstNull(nodep->bitp()); puts(")"); } void visit(AstWildcardSel* nodep) override { iterateAndNextConstNull(nodep->fromp()); putbs(".at("); - AstWildcardArrayDType* const adtypep = VN_AS(nodep->fromp()->dtypep(), WildcardArrayDType); + AstWildcardArrayDType* const adtypep + = VN_AS(nodep->fromp()->dtypep()->skipRefp(), WildcardArrayDType); UASSERT_OBJ(adtypep, nodep, "Wildcard select on non-wildcard-associative type"); iterateAndNextConstNull(nodep->bitp()); puts(")"); @@ -443,8 +493,9 @@ public: // super.new case return; } - // assignment case - puts("VL_NEW(" + prefixNameProtect(nodep->dtypep()) + ", vlSymsp"); + // assignment case; + puts("VL_NEW(" + prefixNameProtect(nodep->dtypep()) + ", " + + optionalProcArg(nodep->dtypep()) + "vlSymsp"); putCommaIterateNext(nodep->argsp(), true); puts(")"); } @@ -1026,6 +1077,7 @@ public: UASSERT_OBJ(!emitSimpleOk(nodep), nodep, "Triop cannot be described in a simple way"); emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), nodep->thsp()); } + void visit(AstCvtPackString* nodep) override { emitCvtPackStr(nodep->lhsp()); } void visit(AstRedXor* nodep) override { if (nodep->lhsp()->isWide()) { visit(static_cast(nodep)); @@ -1088,7 +1140,8 @@ public: puts(")"); } void visit(AstNewCopy* nodep) override { - puts("VL_NEW(" + prefixNameProtect(nodep->dtypep()) + ", "); + puts("VL_NEW(" + prefixNameProtect(nodep->dtypep()) + ", " + + optionalProcArg(nodep->dtypep())); puts("*"); // i.e. make into a reference iterateAndNextConstNull(nodep->rhsp()); puts(")"); diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index f47b5bcf9..e11daab55 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -147,7 +147,7 @@ class EmitCGatherDependencies final : VNVisitorConst { } public: - static const std::set gather(AstCFunc* cfuncp) VL_MT_STABLE { + static const std::set gather(AstCFunc* cfuncp) { const EmitCGatherDependencies visitor{cfuncp}; return std::move(visitor.m_dependencies); } @@ -566,8 +566,7 @@ class EmitCImp final : EmitCFunc { ~EmitCImp() override = default; public: - static void main(const AstNodeModule* modp, bool slow, - std::deque& cfilesr) VL_MT_STABLE { + static void main(const AstNodeModule* modp, bool slow, std::deque& cfilesr) { EmitCImp{modp, slow, cfilesr}; } }; @@ -932,11 +931,11 @@ void V3EmitC::emitcImp() { const AstNodeModule* const modp = VN_AS(nodep, NodeModule); cfiles.emplace_back(); auto& slowCfilesr = cfiles.back(); - futures.push_back(V3ThreadPool::s().enqueue( + futures.push_back(V3ThreadPool::s().enqueue( [modp, &slowCfilesr]() { EmitCImp::main(modp, /* slow: */ true, slowCfilesr); })); cfiles.emplace_back(); auto& fastCfilesr = cfiles.back(); - futures.push_back(V3ThreadPool::s().enqueue( + futures.push_back(V3ThreadPool::s().enqueue( [modp, &fastCfilesr]() { EmitCImp::main(modp, /* slow: */ false, fastCfilesr); })); } @@ -944,12 +943,12 @@ void V3EmitC::emitcImp() { if (v3Global.opt.trace() && !v3Global.opt.lintOnly()) { cfiles.emplace_back(); auto& slowCfilesr = cfiles.back(); - futures.push_back(V3ThreadPool::s().enqueue([&slowCfilesr]() { + futures.push_back(V3ThreadPool::s().enqueue([&slowCfilesr]() { EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ true, slowCfilesr); })); cfiles.emplace_back(); auto& fastCfilesr = cfiles.back(); - futures.push_back(V3ThreadPool::s().enqueue([&fastCfilesr]() { + futures.push_back(V3ThreadPool::s().enqueue([&fastCfilesr]() { EmitCTrace::main(v3Global.rootp()->topModulep(), /* slow: */ false, fastCfilesr); })); } diff --git a/src/V3Error.cpp b/src/V3Error.cpp index a0fa7a3d3..57ec24e91 100644 --- a/src/V3Error.cpp +++ b/src/V3Error.cpp @@ -222,20 +222,18 @@ void V3ErrorGuarded::v3errorEnd(std::ostringstream& sstr, const string& extra) #ifndef V3ERROR_NO_GLOBAL_ if (dumpTreeLevel() || debug()) { V3Broken::allowMidvisitorCheck(true); - V3ThreadPool::s().requestExclusiveAccess([&]() VL_REQUIRES(m_mutex) { - if (dumpTreeLevel()) { - v3Global.rootp()->dumpTreeFile( - v3Global.debugFilename("final.tree", 990)); - } - if (debug()) { - execErrorExitCb(); - V3Stats::statsFinalAll(v3Global.rootp()); - V3Stats::statsReport(); - } - // Abort in exclusive access to make sure other threads - // don't change error code - vlAbortOrExit(); - }); + const V3ThreadPool::ScopedExclusiveAccess exclusiveAccess; + if (dumpTreeLevel()) { + v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("final.tree", 990)); + } + if (debug()) { + execErrorExitCb(); + V3Stats::statsFinalAll(v3Global.rootp()); + V3Stats::statsReport(); + } + // Abort in exclusive access to make sure other threads + // don't change error code + vlAbortOrExit(); } #endif } diff --git a/src/V3Error.h b/src/V3Error.h index da7a17a9b..e5450675c 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -60,6 +60,7 @@ public: I_TRACING, // Tracing is on/off from /*verilator tracing_on/off*/ I_UNUSED, // Unused genvar, parameter or signal message (Backward Compatibility) // Error codes: + E_LIFETIME, // Error: Reference to a variable might outlive the variable. E_NEEDTIMINGOPT, // Error: --timing/--no-timing option not specified E_NOTIMING, // Timing control encountered with --no-timing E_PORTSHORT, // Error: Output port is connected to a constant, electrical short @@ -98,6 +99,7 @@ public: ENUMVALUE, // Error: enum type needs explicit cast EOFNEWLINE, // End-of-file missing newline GENCLK, // Generated Clock. Historical, never issued. + GENUNNAMED, // Generate unnamed, without label HIERBLOCK, // Ignored hierarchical block setting IFDEPTH, // If statements too deep IGNOREDRETURN, // Ignoring return value (function as task) @@ -113,6 +115,7 @@ public: LATCH, // Latch detected outside of always_latch block LITENDIAN, // Little endian, renamed to ASCRANGE MINTYPMAXDLY, // Unsupported: min/typ/max delay expressions + MISINDENT, // Misleading indentation MODDUP, // Duplicate module MULTIDRIVEN, // Driven from multiple blocks MULTITOP, // Multiple top level modules @@ -183,7 +186,7 @@ public: // Boolean " I_CELLDEFINE", " I_COVERAGE", " I_DEF_NETTYPE_WIRE", " I_LINT", " I_TIMING", " I_TRACING", " I_UNUSED", // Errors - "NEEDTIMINGOPT", "NOTIMING", "PORTSHORT", "TASKNSVAR", "UNSUPPORTED", + "LIFETIME", "NEEDTIMINGOPT", "NOTIMING", "PORTSHORT", "TASKNSVAR", "UNSUPPORTED", // Warnings " EC_FIRST_WARN", "ALWCOMBORDER", "ASCRANGE", "ASSIGNDLY", "ASSIGNIN", "BADSTDPRAGMA", @@ -191,11 +194,12 @@ public: "CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CASTCONST", "CDCRSTLOGIC", "CLKDATA", "CMPCONST", "COLONPLUS", "COMBDLY", "CONSTRAINTIGN", "CONTASSREG", "DECLFILENAME", "DEFPARAM", "DEPRECATED", - "ENCAPSULATED", "ENDLABEL", "ENUMVALUE", "EOFNEWLINE", "GENCLK", "HIERBLOCK", + "ENCAPSULATED", "ENDLABEL", "ENUMVALUE", "EOFNEWLINE", "GENCLK", "GENUNNAMED", + "HIERBLOCK", "IFDEPTH", "IGNOREDRETURN", "IMPERFECTSCH", "IMPLICIT", "IMPLICITSTATIC", "IMPORTSTAR", "IMPURE", "INCABSPATH", "INFINITELOOP", "INITIALDLY", "INSECURE", - "LATCH", "LITENDIAN", "MINTYPMAXDLY", "MODDUP", + "LATCH", "LITENDIAN", "MINTYPMAXDLY", "MISINDENT", "MODDUP", "MULTIDRIVEN", "MULTITOP", "NEWERSTD", "NOLATCH", "NULLPORT", "PINCONNECTEMPTY", "PINMISSING", "PINNOCONNECT", "PINNOTFOUND", "PKGNODECL", "PROCASSWIRE", "PROFOUTOFDATE", "PROTECTED", "RANDC", "REALCVT", "REDEFMACRO", "RISEFALLDLY", @@ -234,18 +238,18 @@ public: return (m_e == ALWCOMBORDER || m_e == ASCRANGE || m_e == BSSPACE || m_e == CASEINCOMPLETE || m_e == CASEOVERLAP || m_e == CASEWITHX || m_e == CASEX || m_e == CASTCONST || m_e == CMPCONST || m_e == COLONPLUS || m_e == IMPLICIT || m_e == IMPLICITSTATIC - || m_e == LATCH || m_e == NEWERSTD || m_e == PINMISSING || m_e == REALCVT - || m_e == STATICVAR || m_e == UNSIGNED || m_e == WIDTH || m_e == WIDTHTRUNC - || m_e == WIDTHEXPAND || m_e == WIDTHXZEXPAND); + || m_e == LATCH || m_e == MISINDENT || m_e == NEWERSTD || m_e == PINMISSING + || m_e == REALCVT || m_e == STATICVAR || m_e == UNSIGNED || m_e == WIDTH + || m_e == WIDTHTRUNC || m_e == WIDTHEXPAND || m_e == WIDTHXZEXPAND); } // Warnings that are style only bool styleError() const VL_MT_SAFE { return (m_e == ASSIGNDLY // More than style, but for backward compatibility || m_e == BLKSEQ || m_e == DEFPARAM || m_e == DECLFILENAME || m_e == EOFNEWLINE - || m_e == IMPORTSTAR || m_e == INCABSPATH || m_e == PINCONNECTEMPTY - || m_e == PINNOCONNECT || m_e == SYNCASYNCNET || m_e == UNDRIVEN - || m_e == UNUSEDGENVAR || m_e == UNUSEDPARAM || m_e == UNUSEDSIGNAL - || m_e == VARHIDDEN); + || m_e == GENUNNAMED || m_e == IMPORTSTAR || m_e == INCABSPATH + || m_e == PINCONNECTEMPTY || m_e == PINNOCONNECT || m_e == SYNCASYNCNET + || m_e == UNDRIVEN || m_e == UNUSEDGENVAR || m_e == UNUSEDPARAM + || m_e == UNUSEDSIGNAL || m_e == VARHIDDEN); } // Warnings that are unused only bool unusedError() const VL_MT_SAFE { @@ -335,7 +339,7 @@ public: v3errorEnd( (v3errorPrep(V3ErrorCode::EC_FATALEXIT), (v3errorStr() << "Exiting due to too many errors encountered; --error-limit=" - << errorCount() << endl), + << errorCount() << std::endl), v3errorStr())); assert(0); // LCOV_EXCL_LINE VL_UNREACHABLE; @@ -588,12 +592,12 @@ inline void v3errorEndFatal(std::ostringstream& sstr) #define UINFO(level, stmsg) \ do { \ if (VL_UNCOVERABLE(debug() >= (level))) { \ - cout << "- " << V3Error::lineStr(__FILE__, __LINE__) << stmsg; \ + std::cout << "- " << V3Error::lineStr(__FILE__, __LINE__) << stmsg; \ } \ } while (false) #define UINFONL(level, stmsg) \ do { \ - if (VL_UNCOVERABLE(debug() >= (level))) { cout << stmsg; } \ + if (VL_UNCOVERABLE(debug() >= (level))) { std::cout << stmsg; } \ } while (false) #ifdef VL_DEBUG diff --git a/src/V3File.cpp b/src/V3File.cpp index a197f6d6c..157e8d028 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -489,8 +489,8 @@ private: void startFilter(const string& command) { if (command == "") {} // Prevent Unused #ifdef INFILTER_PIPE - int fd_stdin[2]; - int fd_stdout[2]; + int fd_stdin[2]; // Can't use std::array + int fd_stdout[2]; // Can't use std::array constexpr int P_RD = 0; constexpr int P_WR = 1; diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index 06421f12a..5de357085 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -433,6 +433,12 @@ string FileLine::source() const VL_MT_SAFE { } // LCOV_EXCL_STOP return m_contentp->getLine(m_contentLineno); } +string FileLine::sourcePrefix(int toColumn) const VL_MT_SAFE { + const std::string src = source(); + if (toColumn > static_cast(src.length())) toColumn = static_cast(src.length()); + if (toColumn < 1) return ""; + return src.substr(0, toColumn - 1); +} string FileLine::prettySource() const VL_MT_SAFE { string out = source(); // Drop ignore trailing newline diff --git a/src/V3FileLine.h b/src/V3FileLine.h index 8f1cf140b..cb29f24f9 100644 --- a/src/V3FileLine.h +++ b/src/V3FileLine.h @@ -241,6 +241,7 @@ public: // as the parser errors etc generally make more sense pointing at the last parse point int lineno() const VL_MT_SAFE { return m_lastLineno; } string source() const VL_MT_SAFE; + string sourcePrefix(int toColumn) const VL_MT_SAFE; string prettySource() const VL_MT_SAFE; // Source, w/stripped unprintables and newlines FileLine* parent() const VL_MT_SAFE { return m_parent; } V3LangCode language() const { return singleton().numberToLang(filenameno()); } diff --git a/src/V3Fork.cpp b/src/V3Fork.cpp new file mode 100644 index 000000000..427775cdc --- /dev/null +++ b/src/V3Fork.cpp @@ -0,0 +1,245 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Create separate tasks for forked processes that +// can outlive their parents +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2023 by Wilson Snyder. This program is free software; you +// can redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* +// V3Fork's Transformations: +// +// Each module: +// Look for FORKs [JOIN_NONE]/[JOIN_ANY] +// FORK(stmts) -> TASK(stmts), FORK(TASKREF(inits)) +// +// FORKs that spawn tasks which might outlive their parents require those +// tasks to carry their own frames and as such they require their own +// variable scopes. +// +//************************************************************************* + +#include "config_build.h" +#include "verilatedos.h" + +#include "V3Fork.h" + +#include "V3Ast.h" +#include "V3AstNodeExpr.h" +#include "V3Global.h" + +#include +#include + +VL_DEFINE_DEBUG_FUNCTIONS; + +//###################################################################### +// Fork visitor, transforms asynchronous blocks into separate tasks + +class ForkVisitor final : public VNVisitor { +private: + // NODE STATE + // AstNode::user1() -> bool, 1 = Node was created as a call to an asynchronous task + // AstVarRef::user2() -> bool, 1 = Node is a class handle reference. The handle gets + // modified in the context of this reference. + const VNUser1InUse m_inuser1; + const VNUser2InUse m_inuser2; + + // STATE + AstNodeModule* m_modp = nullptr; // Class/module we are currently under + int m_forkDepth = 0; // Nesting level of asynchronous forks + bool m_newProcess = false; // True if we are directly under an asynchronous fork. + AstVar* m_capturedVarsp = nullptr; // Local copies of captured variables + std::set m_forkLocalsp; // Variables local to a given fork + AstArg* m_capturedVarRefsp = nullptr; // References to captured variables (as args) + int m_createdTasksCount = 0; // Number of tasks created by this visitor + + // METHODS + AstVar* captureRef(AstNodeExpr* refp) { + AstVar* varp = nullptr; + for (varp = m_capturedVarsp; varp; varp = VN_AS(varp->nextp(), Var)) + if (varp->name() == refp->name()) break; + if (!varp) { + // Create a local copy for a capture + varp = new AstVar{refp->fileline(), VVarType::BLOCKTEMP, refp->name(), refp->dtypep()}; + varp->direction(VDirection::INPUT); + varp->funcLocal(true); + varp->lifetime(VLifetime::AUTOMATIC); + m_capturedVarsp = AstNode::addNext(m_capturedVarsp, varp); + // Use the original ref as an argument for call + AstArg* arg = new AstArg{refp->fileline(), refp->name(), refp->cloneTree(false)}; + m_capturedVarRefsp = AstNode::addNext(m_capturedVarRefsp, arg); + } + return varp; + } + + AstTask* makeTask(FileLine* fl, AstNode* stmtsp, std::string name) { + stmtsp = AstNode::addNext(static_cast(m_capturedVarsp), stmtsp); + AstTask* const taskp = new AstTask{fl, name, stmtsp}; + ++m_createdTasksCount; + return taskp; + } + + std::string generateTaskName(AstNode* fromp, std::string kind) { + // TODO: Ensure no collisions occur + return "__V" + kind + (!fromp->name().empty() ? (fromp->name() + "__") : "UNNAMED__") + + cvtToHex(fromp); + } + + void visitTaskifiable(AstNode* nodep) { + if (!m_newProcess || nodep->user1()) { + VL_RESTORER(m_forkDepth); + if (nodep->user1()) { + UASSERT(m_forkDepth > 0, "Wrong fork depth!"); + --m_forkDepth; + } + iterateChildren(nodep); + return; + } + + VL_RESTORER(m_capturedVarsp); + VL_RESTORER(m_capturedVarRefsp); + VL_RESTORER(m_newProcess); + m_capturedVarsp = nullptr; + m_capturedVarRefsp = nullptr; + m_newProcess = false; + + iterateChildren(nodep); + + // If there are no captures, there's no need to taskify + if (m_forkLocalsp.empty() && (m_capturedVarsp == nullptr) && !v3Global.opt.fTaskifyAll()) + return; + + VNRelinker handle; + AstTask* taskp = nullptr; + + if (AstBegin* beginp = VN_CAST(nodep, Begin)) { + UASSERT(beginp->stmtsp(), "No stmtsp\n"); + const std::string taskName = generateTaskName(beginp, "__FORK_BEGIN_"); + taskp + = makeTask(beginp->fileline(), beginp->stmtsp()->unlinkFrBackWithNext(), taskName); + beginp->unlinkFrBack(&handle); + VL_DO_DANGLING(beginp->deleteTree(), beginp); + } else if (AstNodeStmt* stmtp = VN_CAST(nodep, NodeStmt)) { + const std::string taskName = generateTaskName(stmtp, "__FORK_STMT_"); + taskp = makeTask(stmtp->fileline(), stmtp->unlinkFrBack(&handle), taskName); + } else if (AstFork* forkp = VN_CAST(nodep, Fork)) { + const std::string taskName = generateTaskName(forkp, "__FORK_NESTED_"); + taskp = makeTask(forkp->fileline(), forkp->unlinkFrBack(&handle), taskName); + } + + m_modp->addStmtsp(taskp); + + AstTaskRef* const taskrefp + = new AstTaskRef{nodep->fileline(), taskp->name(), m_capturedVarRefsp}; + AstStmtExpr* const taskcallp = new AstStmtExpr{nodep->fileline(), taskrefp}; + // Replaced nodes will be revisited, so we don't need to "lift" the arguments + // as captures in case of nested forks. + handle.relink(taskcallp); + taskcallp->user1(true); + } + + // VISITORS + void visit(AstFork* nodep) override { + bool nested = m_newProcess; + + VL_RESTORER(m_forkLocalsp); + VL_RESTORER(m_newProcess); + VL_RESTORER(m_forkDepth) + if (!nodep->joinType().join()) { + ++m_forkDepth; + m_newProcess = true; + m_forkLocalsp.clear(); + // Nested forks get moved into separate tasks + if (nested) { + visitTaskifiable(nodep); + return; + } + } else { + m_newProcess = false; + } + iterateChildren(nodep); + } + void visit(AstBegin* nodep) override { visitTaskifiable(nodep); } + void visit(AstNodeStmt* nodep) override { visitTaskifiable(nodep); } + void visit(AstVar* nodep) override { + if (m_forkDepth) m_forkLocalsp.insert(nodep); + } + void visit(AstVarRef* nodep) override { + + // VL_KEEP_THIS ensures that we hold a handle to the class + if (m_forkDepth && !nodep->varp()->isFuncLocal() && nodep->varp()->isClassMember()) return; + + if (m_forkDepth && (m_forkLocalsp.count(nodep->varp()) == 0) + && !nodep->varp()->lifetime().isStatic()) { + if (nodep->access().isWriteOrRW() + && (!nodep->isClassHandleValue() || nodep->user2())) { + nodep->v3warn( + E_LIFETIME, + "Invalid reference: Process might outlive variable `" + << nodep->varp()->name() << "`.\n" + << nodep->varp()->warnMore() + << "... Suggest use it as read-only to initialize a local copy at the " + "beginning of the process, or declare it as static. It is also " + "possible to refer by reference to objects and their members."); + return; + } + UASSERT_OBJ( + !nodep->varp()->lifetime().isNone(), nodep, + "Variable's lifetime is unknown. Can't determine if a capture is necessary."); + + AstVar* const varp = captureRef(nodep); + nodep->varp(varp); + } + } + void visit(AstAssign* nodep) override { + if (VN_IS(nodep->lhsp(), VarRef) && nodep->lhsp()->isClassHandleValue()) { + nodep->lhsp()->user2(true); + } + visit(static_cast(nodep)); + } + void visit(AstThisRef* nodep) override { return; } + void visit(AstNodeModule* nodep) override { + VL_RESTORER(m_modp); + m_modp = nodep; + iterateChildren(nodep); + } + void visit(AstNode* nodep) override { + VL_RESTORER(m_newProcess) + VL_RESTORER(m_forkDepth); + if (nodep->user1()) --m_forkDepth; + m_newProcess = false; + iterateChildren(nodep); + } + +public: + // CONSTRUCTORS + ForkVisitor(AstNetlist* nodep) { visit(nodep); } + ~ForkVisitor() override = default; + + // UTILITY + int createdTasksCount() { return m_createdTasksCount; } +}; + +//###################################################################### +// Fork class functions + +int V3Fork::makeTasks(AstNetlist* nodep) { + int createdTasksCount; + + UINFO(2, __FUNCTION__ << ": " << endl); + { + ForkVisitor fork_visitor(nodep); + createdTasksCount = fork_visitor.createdTasksCount(); + } + V3Global::dumpCheckGlobalTree("fork", 0, dumpTreeLevel() >= 3); + + return createdTasksCount; +} diff --git a/src/V3Fork.h b/src/V3Fork.h new file mode 100644 index 000000000..8554fa75f --- /dev/null +++ b/src/V3Fork.h @@ -0,0 +1,35 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Create separate tasks for forked processes that +// can outlive their parents +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2023 by Wilson Snyder. This program is free software; you +// can redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* + +#ifndef VERILATOR_V3FORK_H_ +#define VERILATOR_V3FORK_H_ + +#include "config_build.h" +#include "verilatedos.h" + +class AstNetlist; + +//============================================================================ + +class V3Fork final { +public: + // Create tasks out of begin blocks that can outlive processes in which they were forked. + // Return value: number of tasks created + static int makeTasks(AstNetlist* nodep); +}; + +#endif // Guard diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 252a68ce4..09ff35046 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -176,9 +176,7 @@ public: , m_slow{slow} {} ~GateLogicVertex() override = default; // ACCESSORS - string name() const override VL_MT_STABLE { - return (cvtToHex(m_nodep) + "@" + scopep()->prettyName()); - } + string name() const override { return (cvtToHex(m_nodep) + "@" + scopep()->prettyName()); } string dotColor() const override { return "purple"; } FileLine* fileline() const override { return nodep()->fileline(); } AstNode* nodep() const { return m_nodep; } diff --git a/src/V3Global.h b/src/V3Global.h index fcb4b7e20..f9ee59dd0 100644 --- a/src/V3Global.h +++ b/src/V3Global.h @@ -19,8 +19,8 @@ // clang-format off #include "config_build.h" -#ifndef HAVE_CONFIG_BUILD -# error "Something failed during ./configure as config_build.h is incomplete. Perhaps you used autoreconf, don't." +#ifndef HAVE_CONFIG_PACKAGE +# error "Something failed during ./configure as config_package.h is incomplete. Perhaps you used autoreconf, don't." #endif // clang-format on diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index 43aac0fa4..e97ce6ec6 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -384,7 +384,6 @@ private: nodep->v3fatalSrc("Null connection?"); } } - nodep->name(nodep->varp()->name()); } void visit(AstVarXRef* nodep) override { // Track what scope it was originally under so V3LinkDot can resolve it diff --git a/src/V3InstrCount.cpp b/src/V3InstrCount.cpp index 68574f6c9..c236da288 100644 --- a/src/V3InstrCount.cpp +++ b/src/V3InstrCount.cpp @@ -147,12 +147,6 @@ private: iterateAndNextConstNull(nodep->lsbp()); iterateAndNextConstNull(nodep->widthp()); } - void visit(AstSliceSel* nodep) override { // LCOV_EXCL_LINE - nodep->v3fatalSrc("AstSliceSel unhandled"); - } - void visit(AstMemberSel* nodep) override { // LCOV_EXCL_LINE - nodep->v3fatalSrc("AstMemberSel unhandled"); - } void visit(AstConcat* nodep) override { if (m_ignoreRemaining) return; // Nop. diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 378942655..283e15206 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -69,6 +69,7 @@ #include "V3Ast.h" #include "V3Global.h" #include "V3Graph.h" +#include "V3MemberMap.h" #include "V3String.h" #include "V3SymTable.h" @@ -215,6 +216,7 @@ public: VSymGraph* symsp() { return &m_syms; } int stepNumber() const { return int(m_step); } bool forPrimary() const { return m_step == LDS_PRIMARY; } + bool forParamed() const { return m_step == LDS_PARAMED; } bool forPrearray() const { return m_step == LDS_PARAMED || m_step == LDS_PRIMARY; } bool forScopeCreation() const { return m_step == LDS_SCOPED; } @@ -751,6 +753,8 @@ class LinkDotFindVisitor final : public VNVisitor { // METHODS void makeImplicitNew(AstClass* nodep) { AstFunc* const newp = new AstFunc{nodep->fileline(), "new", nullptr, nullptr}; + // If needed, super.new() call is added the 2nd pass of V3LinkDotResolve, + // because base classes are already resolved there. newp->isConstructor(true); nodep->addMembersp(newp); UINFO(8, "Made implicit new for " << nodep->name() << ": " << nodep << endl); @@ -2025,6 +2029,7 @@ private: // (except the default instances) // They are added to the set only in linkDotPrimary. bool m_insideClassExtParam = false; // Inside a class from m_extendsParam + bool m_explicitSuperNew = false; // Hit a "super.new" call inside a "new" function struct DotStates { DotPosition m_dotPos; // Scope part of dotted resolution @@ -2060,40 +2065,38 @@ private: } m_ds; // State to preserve across recursions // METHODS - Variables - void createImplicitVar(VSymEnt* /*lookupSymp*/, AstVarRef* nodep, AstNodeModule* modp, - VSymEnt* moduleSymp, bool noWarn) { + AstVar* createImplicitVar(VSymEnt* /*lookupSymp*/, AstParseRef* nodep, AstNodeModule* modp, + VSymEnt* moduleSymp, bool noWarn) { // Create implicit after warning - if (!nodep->varp()) { - if (!noWarn) { - if (nodep->fileline()->warnIsOff(V3ErrorCode::I_DEF_NETTYPE_WIRE)) { - const string suggest = m_statep->suggestSymFallback(moduleSymp, nodep->name(), - LinkNodeMatcherVar{}); - nodep->v3error("Signal definition not found, and implicit disabled with " - "`default_nettype: " - << nodep->prettyNameQ() << '\n' - << (suggest.empty() ? "" : nodep->warnMore() + suggest)); + if (!noWarn) { + if (nodep->fileline()->warnIsOff(V3ErrorCode::I_DEF_NETTYPE_WIRE)) { + const string suggest = m_statep->suggestSymFallback(moduleSymp, nodep->name(), + LinkNodeMatcherVar{}); + nodep->v3error("Signal definition not found, and implicit disabled with " + "`default_nettype: " + << nodep->prettyNameQ() << '\n' + << (suggest.empty() ? "" : nodep->warnMore() + suggest)); - } - // Bypass looking for suggestions if IMPLICIT is turned off - // as there could be thousands of these suppressed in large netlists - else if (!nodep->fileline()->warnIsOff(V3ErrorCode::IMPLICIT)) { - const string suggest = m_statep->suggestSymFallback(moduleSymp, nodep->name(), - LinkNodeMatcherVar{}); - nodep->v3warn(IMPLICIT, - "Signal definition not found, creating implicitly: " - << nodep->prettyNameQ() << '\n' - << (suggest.empty() ? "" : nodep->warnMore() + suggest)); - } } - AstVar* const newp = new AstVar{nodep->fileline(), VVarType::WIRE, nodep->name(), - VFlagLogicPacked{}, 1}; - newp->trace(modp->modTrace()); - nodep->varp(newp); - modp->addStmtsp(newp); - // Link it to signal list, must add the variable under the module; - // current scope might be lower now - m_statep->insertSym(moduleSymp, newp->name(), newp, nullptr /*classOrPackagep*/); + // Bypass looking for suggestions if IMPLICIT is turned off + // as there could be thousands of these suppressed in large netlists + else if (!nodep->fileline()->warnIsOff(V3ErrorCode::IMPLICIT)) { + const string suggest = m_statep->suggestSymFallback(moduleSymp, nodep->name(), + LinkNodeMatcherVar{}); + nodep->v3warn(IMPLICIT, + "Signal definition not found, creating implicitly: " + << nodep->prettyNameQ() << '\n' + << (suggest.empty() ? "" : nodep->warnMore() + suggest)); + } } + AstVar* const newp + = new AstVar{nodep->fileline(), VVarType::WIRE, nodep->name(), VFlagLogicPacked{}, 1}; + newp->trace(modp->modTrace()); + modp->addStmtsp(newp); + // Link it to signal list, must add the variable under the module; + // current scope might be lower now + m_statep->insertSym(moduleSymp, newp->name(), newp, nullptr /*classOrPackagep*/); + return newp; } AstVar* foundToVarp(const VSymEnt* symp, AstNode* nodep, VAccess access) { // Return a variable if possible, auto converting a modport to variable @@ -2112,6 +2115,25 @@ private: return nullptr; } } + AstNodeStmt* addImplicitSuperNewCall(AstFunc* nodep) { + // Returns the added node + FileLine* const fl = nodep->fileline(); + AstDot* const superNewp + = new AstDot{fl, false, new AstParseRef{fl, VParseRefExp::PX_ROOT, "super"}, + new AstNew{fl, nullptr}}; + AstNodeStmt* const superNewStmtp = superNewp->makeStmt(); + for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { + // super.new shall be the first statement (section 8.15 of IEEE Std 1800-2017) + // but some nodes (such as variable declarations and typedefs) should stay before + if (VN_IS(stmtp, NodeStmt)) { + stmtp->addHereThisAsNext(superNewStmtp); + return superNewStmtp; + } + } + // There were no statements + nodep->addStmtsp(superNewStmtp); + return superNewStmtp; + } void taskFuncSwapCheck(AstNodeFTaskRef* nodep) { if (nodep->taskp() && VN_IS(nodep->taskp(), Task) && VN_IS(nodep, FuncRef)) { nodep->v3error("Illegal call of a task as a function: " << nodep->prettyNameQ()); @@ -2120,7 +2142,7 @@ private: void checkNoDot(AstNode* nodep) { if (VL_UNLIKELY(m_ds.m_dotPos != DP_NONE)) { // UINFO(9, "ds=" << m_ds.ascii() << endl); - nodep->v3error("Syntax Error: Not expecting " << nodep->type() << " under a " + nodep->v3error("Syntax error: Not expecting " << nodep->type() << " under a " << nodep->backp()->type() << " in dotted expression"); m_ds.m_dotErr = true; @@ -2820,11 +2842,11 @@ private: if (checkImplicit) { // Create if implicit, and also if error (so only complain once) // Else if a scope is allowed, making a signal won't help error cascade + auto varp = createImplicitVar(m_curSymp, nodep, m_modp, m_modSymp, err); AstVarRef* const newp - = new AstVarRef{nodep->fileline(), nodep->name(), VAccess::READ}; + = new AstVarRef{nodep->fileline(), varp, VAccess::READ}; nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); - createImplicitVar(m_curSymp, newp, m_modp, m_modSymp, err); } } } @@ -3026,7 +3048,8 @@ private: } UASSERT_OBJ(cpackagerefp->classOrPackagep(), m_ds.m_dotp->lhsp(), "Bad package link"); nodep->classOrPackagep(cpackagerefp->classOrPackagep()); - m_ds.m_dotPos = DP_SCOPE; + // Class/package :: HERE function() . method_called_on_function_return_value() + m_ds.m_dotPos = DP_MEMBER; m_ds.m_dotp = nullptr; } else if (m_ds.m_dotp && m_ds.m_dotPos == DP_FINAL) { nodep->dotted(m_ds.m_dotText); // Maybe "" @@ -3129,7 +3152,15 @@ private: } else if (nodep->name() == "randomize" || nodep->name() == "srandom" || nodep->name() == "get_randstate" || nodep->name() == "set_randstate") { - // Resolved in V3Width + if (AstClass* const classp = VN_CAST(m_modp, Class)) { + nodep->classOrPackagep(classp); + } else { + nodep->v3error("Calling implicit class method " + << nodep->prettyNameQ() << " without being under class"); + nodep->replaceWith(new AstConst{nodep->fileline(), 0}); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + return; + } } else if (nodep->dotted() == "") { if (nodep->pli()) { if (v3Global.opt.bboxSys()) { @@ -3215,7 +3246,7 @@ private: if (nodep->user3SetOnce()) return; if (m_ds.m_dotPos == DP_SCOPE) { // Already under dot, so this is {modulepart} DOT {modulepart} - nodep->v3error("Syntax Error: Range ':', '+:' etc are not allowed in the instance " + nodep->v3error("Syntax error: Range ':', '+:' etc are not allowed in the instance " "part of a dotted reference"); m_ds.m_dotErr = true; return; @@ -3273,7 +3304,16 @@ private: { m_ftaskp = nodep; m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep); + const bool isNew = nodep->name() == "new"; + if (isNew) m_explicitSuperNew = false; iterateChildren(nodep); + if (isNew && !m_explicitSuperNew && m_statep->forParamed()) { + const AstClassExtends* const classExtendsp = VN_AS(m_modp, Class)->extendsp(); + if (classExtendsp && classExtendsp->classOrNullp()) { + AstNodeStmt* const superNewp = addImplicitSuperNewCall(VN_AS(nodep, Func)); + iterate(superNewp); + } + } } m_ds.m_dotSymp = m_curSymp = oldCurSymp; m_ftaskp = nullptr; @@ -3389,6 +3429,7 @@ private: checkNoDot(nodep); VL_RESTORER(m_curSymp); VL_RESTORER(m_modSymp); + VL_RESTORER(m_modp); VL_RESTORER(m_ifClassImpNames); VL_RESTORER(m_insideClassExtParam); { @@ -3457,15 +3498,16 @@ private: // V3Width when determines types needs to find enum values and such // so add members pointing to appropriate enum values { - nodep->repairCache(); + VMemberMap memberMap; for (VSymEnt::const_iterator it = m_curSymp->begin(); it != m_curSymp->end(); ++it) { AstNode* const itemp = it->second->nodep(); - if (!nodep->findMember(it->first)) { + if (!memberMap.findMember(nodep, it->first)) { if (AstEnumItem* const aitemp = VN_CAST(itemp, EnumItem)) { AstEnumItemRef* const newp = new AstEnumItemRef{ aitemp->fileline(), aitemp, it->second->classOrPackagep()}; UINFO(8, "Class import noderef '" << it->first << "' " << newp << endl); nodep->addMembersp(newp); + memberMap.insert(nodep, newp); } } } @@ -3595,6 +3637,19 @@ private: UINFO(5, " AstCellArrayRef: " << nodep << " " << m_ds.ascii() << endl); // No need to iterate, if we have a UnlinkedVarXRef, we're already done } + void visit(AstStmtExpr* nodep) override { + checkNoDot(nodep); + // Check if nodep represents a super.new call; + if (VN_IS(nodep->exprp(), New)) { + // in this case it was already linked, so it doesn't have a super reference + m_explicitSuperNew = true; + } else if (const AstDot* const dotp = VN_CAST(nodep->exprp(), Dot)) { + if (dotp->lhsp()->name() == "super" && VN_IS(dotp->rhsp(), New)) { + m_explicitSuperNew = true; + } + } + iterateChildren(nodep); + } void visit(AstNode* nodep) override { checkNoDot(nodep); diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp index e8648fd6a..6ba79865f 100644 --- a/src/V3LinkLValue.cpp +++ b/src/V3LinkLValue.cpp @@ -41,7 +41,6 @@ private: bool m_setContinuously = false; // Set that var has some continuous assignment bool m_setStrengthSpecified = false; // Set that var has assignment with strength specified. VAccess m_setRefLvalue; // Set VarRefs to lvalues for pin assignments - AstNodeFTask* m_ftaskp = nullptr; // Function or task we're inside // VISITs // Result handing @@ -55,7 +54,8 @@ private: // so it is needed to check only if m_setContinuously is true if (m_setStrengthSpecified) nodep->varp()->hasStrengthAssignment(true); } - if (nodep->access().isWriteOrRW() && !m_ftaskp && nodep->varp()->isReadOnly()) { + if (nodep->access().isWriteOrRW() && !nodep->varp()->isFuncLocal() + && nodep->varp()->isReadOnly()) { nodep->v3warn(ASSIGNIN, "Assigning to input/const variable: " << nodep->prettyNameQ()); } @@ -275,9 +275,14 @@ private: iterateAndNextNull(nodep->thsp()); } } - void visit(AstNodeFTask* nodep) override { - VL_RESTORER(m_ftaskp); - m_ftaskp = nodep; + void visit(AstMemberSel* nodep) override { + if (m_setRefLvalue != VAccess::NOCHANGE) { + nodep->access(m_setRefLvalue); + } else { + // It is the only place where the access is set to member select nodes. + // If it doesn't have to be set to WRITE, it means that it is READ. + nodep->access(VAccess::READ); + } iterateChildren(nodep); } void visit(AstNodeFTaskRef* nodep) override { diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 9da829f30..117104a30 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -76,6 +76,8 @@ private: // without suppressing other token's messages as a side effect. // We could have verilog.l create a new one on every token, // but that's a lot more structures than only doing AST nodes. + // TODO: Many places copy the filename when suppressing warnings, + // perhaps audit to make consistent and this is no longer needed if (m_filelines.find(nodep->fileline()) != m_filelines.end()) { nodep->fileline(new FileLine{nodep->fileline()}); } @@ -125,6 +127,58 @@ private: && !nodep->stmtsp()->nextp()); // Has only one item } + void checkIndent(AstNode* nodep, AstNode* childp) { + // Try very hard to avoid false positives + AstNode* nextp = nodep->nextp(); + if (!childp) return; + if (!nextp && VN_IS(nodep, While) && VN_IS(nodep->backp(), Begin)) + nextp = nodep->backp()->nextp(); + if (!nextp) return; + if (VN_IS(childp, Begin)) return; + FileLine* const nodeFlp = nodep->fileline(); + FileLine* const childFlp = childp->fileline(); + FileLine* const nextFlp = nextp->fileline(); + // UINFO(0, "checkInd " << nodeFlp->firstColumn() << " " << nodep << endl); + // UINFO(0, " child " << childFlp->firstColumn() << " " << childp << endl); + // UINFO(0, " next " << nextFlp->firstColumn() << " " << nextp << endl); + // Same filename, later line numbers (no macro magic going on) + if (nodeFlp->filenameno() != childFlp->filenameno()) return; + if (nodeFlp->filenameno() != nextFlp->filenameno()) return; + if (nodeFlp->lastLineno() >= childFlp->firstLineno()) return; + if (childFlp->lastLineno() >= nextFlp->firstLineno()) return; + // This block has indent 'a' + // Child block has indent 'b' where indent('b') > indent('a') + // Next block has indent 'b' + // (note similar code below) + if (!(nodeFlp->firstColumn() < childFlp->firstColumn() + && nextFlp->firstColumn() >= childFlp->firstColumn())) + return; + // Might be a tab difference in spaces up to the node prefix, if so + // just ignore this warning + // Note it's correct we look at nodep's column in all of these + const std::string nodePrefix = nodeFlp->sourcePrefix(nodeFlp->firstColumn()); + const std::string childPrefix = childFlp->sourcePrefix(nodeFlp->firstColumn()); + const std::string nextPrefix = nextFlp->sourcePrefix(nodeFlp->firstColumn()); + if (childPrefix != nodePrefix) return; + if (nextPrefix != childPrefix) return; + // Some file lines start after the indentation, so make another check + // using actual file contents + const std::string nodeSource = nodeFlp->source(); + const std::string childSource = childFlp->source(); + const std::string nextSource = nextFlp->source(); + if (!(VString::leadingWhitespaceCount(nodeSource) + < VString::leadingWhitespaceCount(childSource) + && VString::leadingWhitespaceCount(nextSource) + >= VString::leadingWhitespaceCount(childSource))) + return; + nextp->v3warn(MISINDENT, + "Misleading indentation\n" + << nextp->warnContextPrimary() << '\n' + << nodep->warnOther() + << "... Expected indentation matching this earlier statement's line:\n" + << nodep->warnContextSecondary()); + } + // VISITs void visit(AstNodeFTask* nodep) override { if (!nodep->user1SetOnce()) { // Process only once. @@ -316,9 +370,11 @@ private: // Making an AstAssign (vs AstAssignW) to a wire is an error, suppress it FileLine* const newfl = new FileLine{fl}; newfl->warnOff(V3ErrorCode::PROCASSWIRE, true); - auto* const assp - = new AstAssign{newfl, new AstVarRef{newfl, nodep->name(), VAccess::WRITE}, - VN_AS(nodep->valuep()->unlinkFrBack(), NodeExpr)}; + // Create a ParseRef to the wire. We cannot use the var as it may be deleted if + // it's a port (see t_var_set_link.v) + auto* const assp = new AstAssign{ + newfl, new AstParseRef{newfl, VParseRefExp::PX_TEXT, nodep->name()}, + VN_AS(nodep->valuep()->unlinkFrBack(), NodeExpr)}; if (nodep->lifetime().isAutomatic()) { nodep->addNextHere(new AstInitialAutomatic{newfl, assp}); } else { @@ -327,7 +383,7 @@ private: } // 4. Under blocks, it's an initial value to be under an assign else { nodep->addNextHere( - new AstAssign{fl, new AstVarRef{fl, nodep->name(), VAccess::WRITE}, + new AstAssign{fl, new AstVarRef{fl, nodep, VAccess::WRITE}, VN_AS(nodep->valuep()->unlinkFrBack(), NodeExpr)}); } } @@ -476,6 +532,7 @@ private: void visit(AstForeach* nodep) override { // FOREACH(array, loopvars, body) UINFO(9, "FOREACH " << nodep << endl); + cleanFileline(nodep); // Separate iteration vars from base from variable // Input: // v--- arrayp @@ -510,13 +567,16 @@ private: iterateChildren(nodep); } void visit(AstRepeat* nodep) override { + cleanFileline(nodep); VL_RESTORER(m_insideLoop); { m_insideLoop = true; + checkIndent(nodep, nodep->stmtsp()); iterateChildren(nodep); } } void visit(AstDoWhile* nodep) override { + cleanFileline(nodep); VL_RESTORER(m_insideLoop); { m_insideLoop = true; @@ -524,9 +584,11 @@ private: } } void visit(AstWhile* nodep) override { + cleanFileline(nodep); VL_RESTORER(m_insideLoop); { m_insideLoop = true; + checkIndent(nodep, nodep->stmtsp()); iterateChildren(nodep); } } @@ -580,14 +642,25 @@ private: // The genblk name will get attached to the if true/false LOWER begin block(s) const bool nestedIf = nestedIfBegin(nodep); // It's not FOR(BEGIN(...)) but we earlier changed it to BEGIN(FOR(...)) + int assignGenBlkNum = -1; if (nodep->genforp()) { ++m_genblkNum; - if (nodep->name() == "") nodep->name("genblk" + cvtToStr(m_genblkNum)); + if (nodep->name() == "") assignGenBlkNum = m_genblkNum; + } else if (nodep->generate() && nodep->name() == "" && assignGenBlkNum == -1 + && (VN_IS(backp, CaseItem) || VN_IS(backp, GenIf)) && !nestedIf) { + assignGenBlkNum = m_genblkAbove; } - if (nodep->generate() && nodep->name() == "" - && (VN_IS(backp, CaseItem) || VN_IS(backp, GenIf)) && !nestedIf) { - nodep->name("genblk" + cvtToStr(m_genblkAbove)); + if (assignGenBlkNum != -1) { + nodep->name("genblk" + cvtToStr(assignGenBlkNum)); + if (nodep->stmtsp()) { + nodep->v3warn(GENUNNAMED, + "Unnamed generate block " + << nodep->prettyNameQ() << " (IEEE 1800-2017 27.6)" + << nodep->warnMore() + << "... Suggest assign a label with 'begin : gen_'"); + } } + if (nodep->name() != "") { VL_RESTORER(m_genblkAbove); VL_RESTORER(m_genblkNum); @@ -611,6 +684,7 @@ private: } void visit(AstGenIf* nodep) override { cleanFileline(nodep); + checkIndent(nodep, nodep->elsesp() ? nodep->elsesp() : nodep->thensp()); const bool nestedIf = (VN_IS(nodep->backp(), Begin) && nestedIfBegin(VN_CAST(nodep->backp(), Begin))); if (nestedIf) { @@ -655,6 +729,11 @@ private: } } } + void visit(AstIf* nodep) override { + cleanFileline(nodep); + checkIndent(nodep, nodep->elsesp() ? nodep->elsesp() : nodep->thensp()); + iterateChildren(nodep); + } void visit(AstPrintTimeScale* nodep) override { // Inlining may change hierarchy, so just save timescale where needed cleanFileline(nodep); @@ -683,6 +762,7 @@ private: nodep->timeunit(m_modp->timeunit()); } void visit(AstTimeUnit* nodep) override { + cleanFileline(nodep); iterateChildren(nodep); nodep->timeunit(m_modp->timeunit()); } @@ -711,6 +791,7 @@ private: } } void visit(AstClocking* nodep) override { + cleanFileline(nodep); VL_RESTORER(m_defaultInSkewp); VL_RESTORER(m_defaultOutSkewp); // Find default input and output skews @@ -745,6 +826,7 @@ private: iterateChildren(nodep); } void visit(AstClockingItem* nodep) override { + cleanFileline(nodep); if (nodep->direction() == VDirection::OUTPUT) { if (!nodep->skewp()) { if (m_defaultOutSkewp) { diff --git a/src/V3MemberMap.h b/src/V3MemberMap.h new file mode 100644 index 000000000..8601214ca --- /dev/null +++ b/src/V3MemberMap.h @@ -0,0 +1,95 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Member names for classes/structs +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2023 by Wilson Snyder. This program is free software; you +// can redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* +// +// For a class or struct, create a map of names of each member. +// Used for faster lookup to avoid O(n^2) processing times. +// +//************************************************************************* + +#ifndef VERILATOR_V3MEMBERMAP_H_ +#define VERILATOR_V3MEMBERMAP_H_ + +#include "config_build.h" +#include "verilatedos.h" + +#include "V3Ast.h" +#include "V3Global.h" + +#include + +//###################################################################### + +class VMemberMap final { + // MEMBERS + using MemberMap = std::map; + using NodeMap = std::map; + NodeMap m_map; // Map of nodes being tracked +public: + void clear() { m_map.clear(); } + // Find 'name' under 'nodep', caching nodep's children if needed + AstNode* findMember(const AstNode* nodep, const std::string& name) { + auto nit = m_map.find(nodep); + if (VL_UNLIKELY(nit == m_map.end())) { + scan(nodep); + nit = m_map.find(nodep); + } + const auto mit = nit->second.find(name); + if (mit == nit->second.end()) return nullptr; + return mit->second; + } + // Insert under the given parent node the child's name + void insert(const AstNode* nodep, AstNode* childp) { + auto nit = m_map.find(nodep); + if (nit == m_map.end()) { + scan(nodep); + nit = m_map.find(nodep); + } + memberInsert(nit->second, childp, false); + } + +private: + void scan(const AstNode* nodep) { + const auto nitPair = m_map.emplace(nodep, MemberMap{}); + MemberMap& mmapr = nitPair.first->second; + if (const AstClass* const anodep = VN_CAST(nodep, Class)) { + for (AstNode* itemp = anodep->membersp(); itemp; itemp = itemp->nextp()) { + if (const AstScope* const scopep = VN_CAST(itemp, Scope)) { + for (AstNode* blockp = scopep->blocksp(); blockp; blockp = blockp->nextp()) { + if (AstClass::isCacheableChild(blockp)) memberInsert(mmapr, blockp); + } + } else { + if (AstClass::isCacheableChild(itemp)) memberInsert(mmapr, itemp); + } + } + } else if (const AstNodeUOrStructDType* const anodep + = VN_CAST(nodep, NodeUOrStructDType)) { + for (AstNode* itemp = anodep->membersp(); itemp; itemp = itemp->nextp()) { + memberInsert(mmapr, itemp); + } + } else { + nodep->v3fatalSrc("Unsupported node type"); + } + } + void memberInsert(MemberMap& mmapr, AstNode* childp, bool warn = true) { + const auto mitPair = mmapr.emplace(childp->name(), childp); + if (VL_UNCOVERABLE(!mitPair.second && warn)) { + // Probably an internal error, but we'll make it user friendly if happens + childp->v3error("Duplicate declaration of member name: " << childp->prettyNameQ()); + } + } +}; + +#endif // guard diff --git a/src/V3Mutex.h b/src/V3Mutex.h index c5f3883a7..7f4bc20cf 100644 --- a/src/V3Mutex.h +++ b/src/V3Mutex.h @@ -109,6 +109,10 @@ public: bool try_lock() VL_TRY_ACQUIRE(true) VL_MT_SAFE { return V3MutexConfig::s().enable() ? m_mutex.try_lock() : true; } + /// Assume that the mutex is already held. Purely for Clang thread safety analyzer. + void assumeLocked() VL_ASSERT_CAPABILITY(this) VL_MT_SAFE {} + /// Pretend that the mutex is being unlocked. Purely for Clang thread safety analyzer. + void pretendUnlock() VL_RELEASE() VL_MT_SAFE {} /// Acquire/lock mutex and check for stop request /// It tries to lock the mutex and if it fails, it check if stop request was send. /// It returns after locking mutex. diff --git a/src/V3Name.cpp b/src/V3Name.cpp index cf4bec4f0..fc532f498 100644 --- a/src/V3Name.cpp +++ b/src/V3Name.cpp @@ -89,12 +89,7 @@ private: rename(nodep, false); } } - void visit(AstVarRef* nodep) override { - if (nodep->varp()) { - iterate(nodep->varp()); - nodep->name(nodep->varp()->name()); - } - } + void visit(AstVarRef* nodep) override { iterate(nodep->varp()); } void visit(AstCell* nodep) override { if (!nodep->user1()) { rename(nodep, (!nodep->modp()->modPublic() && !VN_IS(nodep->modp(), ClassPackage))); diff --git a/src/V3Number.cpp b/src/V3Number.cpp index 9e5e295c5..cc1d22514 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -1866,12 +1866,15 @@ V3Number& V3Number::opAdd(const V3Number& lhs, const V3Number& rhs) { if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX(); setZero(); // Addem - int carry = 0; - for (int bit = 0; bit < width(); bit++) { - const int sum = ((lhs.bitIs1(bit) ? 1 : 0) + (rhs.bitIs1(bit) ? 1 : 0) + carry); - if (sum & 1) setBit(bit, 1); - carry = (sum >= 2); + uint64_t carry = 0; + for (int word = 0; word < words(); word++) { + const uint64_t lwordval = lhs.m_data.num()[word].m_value; + const uint64_t rwordval = rhs.m_data.num()[word].m_value; + const uint64_t sum = lwordval + rwordval + carry; + m_data.num()[word].m_value = sum & 0xffffffffULL; + carry = sum > 0xffffffffULL; } + opCleanThis(); // Just in case it produced extra bits in result return *this; } V3Number& V3Number::opSub(const V3Number& lhs, const V3Number& rhs) { diff --git a/src/V3OptionParser.h b/src/V3OptionParser.h index 264d209ee..cc22b8f0a 100644 --- a/src/V3OptionParser.h +++ b/src/V3OptionParser.h @@ -43,7 +43,7 @@ class VOptionBool; // if (int consumed = parser.parse(i, argc, argv)) { // i += consumed; // } else { // error -// cerr << parser.getSuggestion(argv[i]) << endl; +// std::cerr << parser.getSuggestion(argv[i]) << std::endl; // } // } // diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 219c8e30c..8d0d3e26f 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -896,7 +896,7 @@ void V3Options::notify() { // V3 Options accessors string V3Options::version() VL_PURE { - string ver = DTVERSION; + string ver = PACKAGE_STRING; ver += " rev " + cvtToStr(DTVERSION_rev); return ver; } @@ -1224,6 +1224,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-fsubst", FOnOff, &m_fSubst); DECL_OPTION("-fsubst-const", FOnOff, &m_fSubstConst); DECL_OPTION("-ftable", FOnOff, &m_fTable); + DECL_OPTION("-ftaskify-all-forked", FOnOff, &m_fTaskifyAll).undocumented(); // Debug DECL_OPTION("-G", CbPartialMatch, [this](const char* optp) { addParameter(optp, false); }); DECL_OPTION("-gate-stmts", Set, &m_gateStmts); diff --git a/src/V3Options.h b/src/V3Options.h index fea00aaf8..dcdf0d96b 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -374,6 +374,7 @@ private: bool m_fSubst; // main switch: -fno-subst: substitute expression temp values bool m_fSubstConst; // main switch: -fno-subst-const: final constant substitution bool m_fTable; // main switch: -fno-table: lookup table creation + bool m_fTaskifyAll = false; // main switch: --ftaskify-all-forked // clang-format on bool m_available = false; // Set to true at the end of option parsing @@ -633,6 +634,7 @@ public: bool fSubst() const { return m_fSubst; } bool fSubstConst() const { return m_fSubstConst; } bool fTable() const { return m_fTable; } + bool fTaskifyAll() const { return m_fTaskifyAll; } string traceClassBase() const { return m_traceFormat.classBase(); } string traceClassLang() const { return m_traceFormat.classBase() + (systemC() ? "Sc" : "C"); } diff --git a/src/V3Param.cpp b/src/V3Param.cpp index ba39ef6e6..2502bc459 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -394,6 +394,11 @@ class ParamProcessor final : public VNDeleter { } return nullptr; } + bool isString(AstNodeDType* nodep) { + if (AstBasicDType* const basicp = VN_CAST(nodep->skipRefToEnump(), BasicDType)) + return basicp->isString(); + return false; + } void collectPins(CloneMap* clonemapp, AstNodeModule* modp, bool originalIsCopy) { // Grab all I/O so we can remap our pins later for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) { @@ -670,6 +675,19 @@ class ParamProcessor final : public VNDeleter { return modInfop; } + void convertToStringp(AstNode* nodep) { + // Should be called on values of parameters of type string to convert them + // to properly typed string constants. + // Has no effect if the value is not a string constant. + AstConst* const constp = VN_CAST(nodep, Const); + // Check if it wasn't already converted + if (constp && !constp->num().isString()) { + constp->replaceWith( + new AstConst{constp->fileline(), AstConst::String{}, constp->num().toString()}); + constp->deleteTree(); + } + } + void cellPinCleanup(AstNode* nodep, AstPin* pinp, AstNodeModule* srcModp, string& longnamer, bool& any_overridesr) { if (!pinp->exprp()) return; // No-connect @@ -684,8 +702,16 @@ class ParamProcessor final : public VNDeleter { any_overridesr = true; } else { V3Const::constifyParamsEdit(pinp->exprp()); + // String constants are parsed as logic arrays and converted to strings in V3Const. + // At this moment, some constants may have been already converted. + // To correctly compare constants, both should be of the same type, + // so they need to be converted. + if (isString(modvarp->subDTypep())) { + convertToStringp(pinp->exprp()); + convertToStringp(modvarp->valuep()); + } AstConst* const exprp = VN_CAST(pinp->exprp(), Const); - const AstConst* const origp = VN_CAST(modvarp->valuep(), Const); + AstConst* const origp = VN_CAST(modvarp->valuep(), Const); if (!exprp) { if (debug()) pinp->dumpTree("- "); pinp->v3error("Can't convert defparam value to constant: Param " @@ -709,7 +735,7 @@ class ParamProcessor final : public VNDeleter { } } else if (AstParamTypeDType* const modvarp = pinp->modPTypep()) { AstNodeDType* const exprp = VN_CAST(pinp->exprp(), NodeDType); - const AstNodeDType* const origp = modvarp->subDTypep(); + const AstNodeDType* const origp = modvarp->skipRefToEnump(); if (!exprp) { pinp->v3error("Parameter type pin value isn't a type: Param " << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); diff --git a/src/V3ParseGrammar.cpp b/src/V3ParseGrammar.cpp index f2f7f7949..74b729abc 100644 --- a/src/V3ParseGrammar.cpp +++ b/src/V3ParseGrammar.cpp @@ -85,9 +85,10 @@ AstArg* V3ParseGrammar::argWrapList(AstNodeExpr* nodep) { } AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, const string& name, int value) { - AstAssignW* assignp = new AstAssignW{fileline, new AstVarRef{fileline, name, VAccess::WRITE}, - value ? new AstConst{fileline, AstConst::All1{}} - : new AstConst{fileline, AstConst::All0{}}}; + AstAssignW* assignp + = new AstAssignW{fileline, new AstParseRef{fileline, VParseRefExp::PX_TEXT, name}, + value ? new AstConst{fileline, AstConst::All1{}} + : new AstConst{fileline, AstConst::All0{}}}; AstStrengthSpec* strengthSpecp = new AstStrengthSpec{fileline, VStrength::SUPPLY, VStrength::SUPPLY}; assignp->strengthSpecp(strengthSpecp); diff --git a/src/V3ParseSym.h b/src/V3ParseSym.h index 422e86c35..c29db09d3 100644 --- a/src/V3ParseSym.h +++ b/src/V3ParseSym.h @@ -119,7 +119,7 @@ public: if (VL_UNCOVERABLE(symCurrentp()->nodep() != nodep)) { // LCOV_EXCL_START if (debug()) { showUpward(); - dumpSelf(cout, "-mism: "); + dumpSelf(std::cout, "-mism: "); } nodep->v3fatalSrc("Symbols suggest ending " << symCurrentp()->nodep()->prettyTypeName() << " but parser thinks ending " diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index 41b41ba51..4eeb0d6a2 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -518,7 +518,7 @@ class MTaskEdge final : public V3GraphEdge, public MergeCandidate { // MEMBERS // This edge can be in 2 EdgeHeaps, one forward and one reverse. We allocate the heap nodes // directly within the edge as they are always required and this makes association cheap. - EdgeHeap::Node m_edgeHeapNode[GraphWay::NUM_WAYS]; + std::array m_edgeHeapNode; public: // CONSTRUCTORS @@ -1060,7 +1060,7 @@ class PartPropagateCpSelfTest final { private: // MEMBERS V3Graph m_graph; // A graph - LogicMTask* m_vx[50]; // All vertices within the graph + std::array m_vx; // All vertices within the graph // CONSTRUCTORS PartPropagateCpSelfTest() = default; diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 6f88a2372..95013b505 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -30,6 +30,7 @@ #include "V3Randomize.h" #include "V3Ast.h" +#include "V3MemberMap.h" VL_DEFINE_DEBUG_FUNCTIONS; @@ -138,6 +139,7 @@ private: const VNUser2InUse m_inuser2; // STATE + VMemberMap memberMap; // Member names cached for fast lookup AstNodeModule* m_modp = nullptr; // Current module const AstNodeFTask* m_ftaskp = nullptr; // Current function/task size_t m_enumValueTabCount = 0; // Number of tables with enum values created @@ -213,7 +215,7 @@ private: } } void addPrePostCall(AstClass* classp, AstFunc* funcp, const string& name) { - if (AstTask* userFuncp = VN_CAST(classp->findMember(name), Task)) { + if (AstTask* userFuncp = VN_CAST(memberMap.findMember(classp, name), Task)) { AstTaskRef* const callp = new AstTaskRef{userFuncp->fileline(), userFuncp->name(), nullptr}; callp->taskp(userFuncp); @@ -380,7 +382,8 @@ void V3Randomize::randomizeNetlist(AstNetlist* nodep) { } AstFunc* V3Randomize::newRandomizeFunc(AstClass* nodep) { - AstFunc* funcp = VN_AS(nodep->findMember("randomize"), Func); + VMemberMap memberMap; + AstFunc* funcp = VN_AS(memberMap.findMember(nodep, "randomize"), Func); if (!funcp) { v3Global.useRandomizeMethods(true); AstNodeDType* const dtypep @@ -395,7 +398,6 @@ AstFunc* V3Randomize::newRandomizeFunc(AstClass* nodep) { funcp->classMethod(true); funcp->isVirtual(nodep->isExtended()); nodep->addMembersp(funcp); - nodep->repairCache(); AstClass* const basep = nodep->baseMostClassp(); basep->needRNG(true); } @@ -403,8 +405,9 @@ AstFunc* V3Randomize::newRandomizeFunc(AstClass* nodep) { } AstFunc* V3Randomize::newSRandomFunc(AstClass* nodep) { + VMemberMap memberMap; AstClass* const basep = nodep->baseMostClassp(); - AstFunc* funcp = VN_AS(basep->findMember("srandom"), Func); + AstFunc* funcp = VN_AS(memberMap.findMember(basep, "srandom"), Func); if (!funcp) { v3Global.useRandomizeMethods(true); AstNodeDType* const dtypep @@ -418,7 +421,6 @@ AstFunc* V3Randomize::newSRandomFunc(AstClass* nodep) { funcp->classMethod(true); funcp->isVirtual(false); basep->addMembersp(funcp); - basep->repairCache(); funcp->addStmtsp(new AstCStmt{basep->fileline(), "__Vm_rng.srandom(seed);\n"}); basep->needRNG(true); } diff --git a/src/V3Sched.cpp b/src/V3Sched.cpp index 78f09d44b..28c561c95 100644 --- a/src/V3Sched.cpp +++ b/src/V3Sched.cpp @@ -125,8 +125,43 @@ void splitCheck(AstCFunc* ofuncp) { int funcnum = 0; int func_stmts = 0; + const bool is_ofuncp_coroutine = ofuncp->isCoroutine(); AstCFunc* funcp = nullptr; + const auto createNewSubFuncp = [&]() { + AstCFunc* const subFuncp = new AstCFunc{ + ofuncp->fileline(), ofuncp->name() + "__" + cvtToStr(funcnum++), ofuncp->scopep()}; + subFuncp->dontCombine(true); + subFuncp->isStatic(false); + subFuncp->isLoose(true); + subFuncp->slow(ofuncp->slow()); + subFuncp->declPrivate(ofuncp->declPrivate()); + + func_stmts = 0; + + return subFuncp; + }; + + const auto finishSubFuncp = [&](AstCFunc* subFuncp) { + ofuncp->scopep()->addBlocksp(subFuncp); + AstCCall* const callp = new AstCCall{subFuncp->fileline(), subFuncp}; + callp->dtypeSetVoid(); + + if (is_ofuncp_coroutine && subFuncp->exists([](const AstCAwait*) { + return true; + })) { // Wrap call with co_await + subFuncp->rtnType("VlCoroutine"); + + AstCAwait* const awaitp = new AstCAwait{subFuncp->fileline(), callp}; + awaitp->dtypeSetVoid(); + ofuncp->addStmtsp(awaitp->makeStmt()); + } else { + ofuncp->addStmtsp(callp->makeStmt()); + } + }; + + funcp = createNewSubFuncp(); + // Unlink all statements, then add item by item to new sub-functions AstBegin* const tempp = new AstBegin{ofuncp->fileline(), "[EditWrapper]", ofuncp->stmtsp()->unlinkFrBackWithNext()}; @@ -135,24 +170,16 @@ void splitCheck(AstCFunc* ofuncp) { while (tempp->stmtsp()) { AstNode* const itemp = tempp->stmtsp()->unlinkFrBack(); const int stmts = itemp->nodeCount(); - if (!funcp || (func_stmts + stmts) > v3Global.opt.outputSplitCFuncs()) { - // Make a new function - funcp = new AstCFunc{ofuncp->fileline(), ofuncp->name() + "__" + cvtToStr(funcnum++), - ofuncp->scopep()}; - funcp->dontCombine(true); - funcp->isStatic(false); - funcp->isLoose(true); - funcp->slow(ofuncp->slow()); - ofuncp->scopep()->addBlocksp(funcp); - // - AstCCall* const callp = new AstCCall{funcp->fileline(), funcp}; - callp->dtypeSetVoid(); - ofuncp->addStmtsp(callp->makeStmt()); - func_stmts = 0; + + if ((func_stmts + stmts) > v3Global.opt.outputSplitCFuncs()) { + finishSubFuncp(funcp); + funcp = createNewSubFuncp(); } + funcp->addStmtsp(itemp); func_stmts += stmts; } + finishSubFuncp(funcp); VL_DO_DANGLING(tempp->deleteTree(), tempp); } @@ -247,7 +274,6 @@ void orderSequentially(AstCFunc* funcp, const LogicByScope& lbs) { subFuncp = createNewSubFuncp(scopep); subFuncp->name(subFuncp->name() + "__" + cvtToStr(scopep->user2Inc())); subFuncp->rtnType("VlCoroutine"); - if (procp->needProcess()) subFuncp->setNeedProcess(); if (VN_IS(procp, Always)) { subFuncp->slow(false); FileLine* const flp = procp->fileline(); @@ -256,6 +282,8 @@ void orderSequentially(AstCFunc* funcp, const LogicByScope& lbs) { } } subFuncp->addStmtsp(bodyp); + if (procp->needProcess()) subFuncp->setNeedProcess(); + splitCheck(subFuncp); } } else { logicp->unlinkFrBack(); diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp index ec816bc70..1c80c3736 100644 --- a/src/V3SchedTiming.cpp +++ b/src/V3SchedTiming.cpp @@ -290,26 +290,18 @@ void transformForks(AstNetlist* const netlistp) { funcp->foreach([&](AstNodeVarRef* refp) { AstVar* const varp = refp->varp(); AstBasicDType* const dtypep = varp->dtypep()->basicp(); - // If it a fork sync or an intra-assignment variable, pass it by value - const bool passByValue = (dtypep && dtypep->isForkSync()) - || VString::startsWith(varp->name(), "__Vintra"); - if (passByValue) { - // We can just pass it to the new function + bool passByValue = false; + if (VString::startsWith(varp->name(), "__Vintra")) { + // Pass it by value to the new function, as otherwise there are issues with + // -flocalize (see t_timing_intra_assign) + passByValue = true; } else if (!varp->user1() || !varp->isFuncLocal()) { // Not func local, or not declared before the fork. Their lifetime is longer // than the forked process. Skip return; - } else if (m_forkp->joinType().join()) { - // If it's fork..join, we can refer to variables from the parent process - } else { - // TODO: It is possible to relax this by allowing the use of such variables up - // until the first await. Also, variables defined within a forked process - // (inside a begin) are extracted out by V3Begin, so they also trigger this - // error. Preventing this (or detecting such cases and moving the vars back) - // would also allow for using them freely. - refp->v3warn(E_UNSUPPORTED, "Unsupported: variable local to a forking process " - "accessed in a fork..join_any or fork..join_none"); - return; + } else if (dtypep && dtypep->isForkSync()) { + // We can just pass it by value to the new function + passByValue = true; } // Remap the reference AstVarScope* const vscp = refp->varScopep(); diff --git a/src/V3SenExprBuilder.h b/src/V3SenExprBuilder.h index 86b09d03f..3928c7ea5 100644 --- a/src/V3SenExprBuilder.h +++ b/src/V3SenExprBuilder.h @@ -232,7 +232,13 @@ public: } std::vector getAndClearInits() { return std::move(m_inits); } - std::vector getAndClearLocals() { return std::move(m_locals); } + + std::vector getAndClearLocals() { + // With m_locals empty, m_prev and m_curr are no longer valid + m_prev.clear(); + m_curr.clear(); + return std::move(m_locals); + } std::vector getAndClearPreUpdates() { m_hasPreUpdate.clear(); diff --git a/src/V3Simulate.h b/src/V3Simulate.h index fa28b67b8..e73f111f7 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -178,8 +178,8 @@ public: m_whyNotNodep = nodep; if (debug() >= 5) { UINFO(0, "Clear optimizable: " << why); - if (nodep) cout << ": " << nodep; - cout << endl; + if (nodep) std::cout << ": " << nodep; + std::cout << std::endl; } m_whyNotOptimizable = why; std::ostringstream stack; diff --git a/src/V3Split.cpp b/src/V3Split.cpp index c937deb08..cbabdbffc 100644 --- a/src/V3Split.cpp +++ b/src/V3Split.cpp @@ -109,9 +109,7 @@ protected: // ACCESSORS // Do not make accessor for nodep(), It may change due to // reordering a lower block, but we don't repair it - string name() const override VL_MT_STABLE { - return cvtToHex(m_nodep) + ' ' + m_nodep->prettyTypeName(); - } + string name() const override { return cvtToHex(m_nodep) + ' ' + m_nodep->prettyTypeName(); } FileLine* fileline() const override { return nodep()->fileline(); } public: @@ -148,7 +146,7 @@ public: SplitVarPostVertex(V3Graph* graphp, AstNode* nodep) : SplitNodeVertex{graphp, nodep} {} ~SplitVarPostVertex() override = default; - string name() const override VL_MT_STABLE { return string{"POST "} + SplitNodeVertex::name(); } + string name() const override { return string{"POST "} + SplitNodeVertex::name(); } string dotColor() const override { return "CadetBlue"; } }; diff --git a/src/V3String.cpp b/src/V3String.cpp index 5dcf0f63d..9c1365c60 100644 --- a/src/V3String.cpp +++ b/src/V3String.cpp @@ -158,6 +158,15 @@ bool VString::isWhitespace(const string& str) { return true; } +string::size_type VString::leadingWhitespaceCount(const string& str) { + string::size_type result = 0; + for (const char c : str) { + ++result; + if (!std::isspace(c)) break; + } + return result; +} + double VString::parseDouble(const string& str, bool* successp) { char* const strgp = new char[str.size() + 1]; char* dp = strgp; diff --git a/src/V3String.h b/src/V3String.h index bd31909cc..cbca5de56 100644 --- a/src/V3String.h +++ b/src/V3String.h @@ -113,6 +113,8 @@ public: static string removeWhitespace(const string& str); // Return true if only whitespace or "" static bool isWhitespace(const string& str); + // Return number of spaces/tabs leading in string + static string::size_type leadingWhitespaceCount(const string& str); // Return double by parsing string static double parseDouble(const string& str, bool* successp); // Replace all occurrences of the word 'from' in 'str' with 'to'. A word is considered diff --git a/src/V3SymTable.h b/src/V3SymTable.h index 482753a5c..534aedd3e 100644 --- a/src/V3SymTable.h +++ b/src/V3SymTable.h @@ -123,7 +123,8 @@ public: << " " << entp->nodep() << endl); if (name != "" && m_idNameMap.find(name) != m_idNameMap.end()) { if (!V3Error::errorCount()) { // Else may have just reported warning - if (debug() >= 9 || V3Error::debugDefault()) dumpSelf(cout, "- err-dump: ", 1); + if (debug() >= 9 || V3Error::debugDefault()) + dumpSelf(std::cout, "- err-dump: ", 1); entp->nodep()->v3fatalSrc("Inserting two symbols with same name: " << name); } } else { diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 5f1e195ce..fd4cb172b 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -350,7 +350,6 @@ private: // TYPES enum InsertMode : uint8_t { IM_BEFORE, // Pointing at statement ref is in, insert before this - IM_AFTER, // Pointing at last inserted stmt, insert after IM_WHILE_PRECOND // Pointing to for loop, add to body end }; using DpiCFuncs = std::map>; @@ -413,7 +412,6 @@ private: AstVarScope* const newvscp = VN_AS(refp->varp()->user2p(), VarScope); refp->varScopep(newvscp); refp->varp(refp->varScopep()->varp()); - refp->name(refp->varp()->name()); } }); } @@ -657,8 +655,15 @@ private: args += ", "; dpiproto += ", "; } + // Include both the Verilator and C type names, as if either + // differ we may get C compilation problems later + const std::string dpiType = portp->dpiArgType(false, false); + dpiproto += dpiType; + const std::string vType = portp->dtypep()->prettyDTypeName(); + if (!portp->isDpiOpenArray() && dpiType != vType) { + dpiproto += " /* " + vType + " */ "; + } args += portp->name(); // Leftover so ,'s look nice - if (nodep->dpiImport()) dpiproto += portp->dpiArgType(false, false); } } } @@ -929,15 +934,15 @@ private: m_dpiNames.emplace(nodep->cname(), std::make_tuple(nodep, signature, funcp)); return funcp; } else { - // Seen this cname before. Check if it's the same prototype. + // Seen this cname import before. Check if it's the same prototype. const AstNodeFTask* firstNodep; string firstSignature; AstCFunc* firstFuncp; std::tie(firstNodep, firstSignature, firstFuncp) = it->second; if (signature != firstSignature) { // Different signature, so error. - nodep->v3error("Duplicate declaration of DPI function with different signature: " - << nodep->prettyNameQ() << '\n' + nodep->v3error("Duplicate declaration of DPI function with different signature: '" + << nodep->cname() << "'\n" << nodep->warnContextPrimary() << '\n' << nodep->warnMore() // << "... New signature: " << signature << '\n' // @@ -1093,7 +1098,7 @@ private: if (nodep->isFunction()) { AstVar* const portp = VN_AS(nodep->fvarp(), Var); UASSERT_OBJ(portp, nodep, "function without function output variable"); - if (!portp->isFuncReturn()) nodep->v3error("Not marked as function return var"); + UASSERT_OBJ(portp->isFuncReturn(), nodep, "Not marked as function return var"); if (nodep->dpiImport() || nodep->dpiExport()) { AstBasicDType* const bdtypep = portp->dtypep()->basicp(); if (!bdtypep->isDpiPrimitive()) { @@ -1108,7 +1113,7 @@ private: "other than a single 'logic' (IEEE 1800-2017 35.5.5)"); } } - } else { + } else if (nodep->taskPublic()) { if (portp->isWide()) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: Public functions with return > 64 bits wide.\n" @@ -1317,7 +1322,7 @@ private: } // Mark the fact that this function allocates std::process - if (nodep->isFromStd() && nodep->name() == "self") cfuncp->setNeedProcess(); + if (nodep->needProcess()) cfuncp->setNeedProcess(); // Delete rest of cloned task and return new func VL_DO_DANGLING(pushDeletep(nodep), nodep); @@ -1339,16 +1344,13 @@ private: AstNode* insertBeforeStmt(AstNode* nodep, AstNode* newp) { // Return node that must be visited, if any if (debug() >= 9) nodep->dumpTree("- newstmt: "); - UASSERT_OBJ(m_insStmtp, nodep, "Function not underneath a statement"); + UASSERT_OBJ(m_insStmtp, nodep, "Function call not underneath a statement"); AstNode* visitp = nullptr; if (m_insMode == IM_BEFORE) { // Add the whole thing before insertAt UINFO(5, " IM_Before " << m_insStmtp << endl); if (debug() >= 9) newp->dumpTree("- newfunc: "); m_insStmtp->addHereThisAsNext(newp); - } else if (m_insMode == IM_AFTER) { - UINFO(5, " IM_After " << m_insStmtp << endl); - m_insStmtp->addNextHere(newp); } else if (m_insMode == IM_WHILE_PRECOND) { UINFO(5, " IM_While_Precond " << m_insStmtp << endl); AstWhile* const whilep = VN_AS(m_insStmtp, While); @@ -1358,8 +1360,6 @@ private: } else { nodep->v3fatalSrc("Unknown InsertMode"); } - m_insMode = IM_AFTER; - m_insStmtp = newp; return visitp; } @@ -1539,6 +1539,13 @@ private: iterateChildren(nodep); m_insStmtp = nullptr; // Next thing should be new statement } + void visit(AstVar* nodep) override { + if (nodep->isFuncLocal() && nodep->direction() == VDirection::INPUT && nodep->valuep()) { + // It's the default value of optional argument. + // Such values are added to function calls on this stage and aren't needed here. + pushDeletep(nodep->valuep()->unlinkFrBack()); + } + } void visit(AstStmtExpr* nodep) override { m_insMode = IM_BEFORE; m_insStmtp = nodep; @@ -1651,7 +1658,14 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp) << portp->prettyNameQ() << " in function call to " << nodep->taskp()->prettyTypeName()); newvaluep = new AstConst{nodep->fileline(), AstConst::Unsized32{}, 0}; - } else if (!VN_IS(portp->valuep(), Const)) { + } else if (AstFuncRef* const funcRefp = VN_CAST(portp->valuep(), FuncRef)) { + const AstNodeFTask* const funcp = funcRefp->taskp(); + if (funcp->classMethod() && funcp->lifetime().isStatic()) newvaluep = funcRefp; + } else if (AstConst* const constp = VN_CAST(portp->valuep(), Const)) { + newvaluep = constp; + } + + if (!newvaluep) { // The default value for this port might be a constant // expression that hasn't been folded yet. Try folding it // now; we don't have much to lose if it fails. @@ -1665,12 +1679,9 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp) << portp->prettyNameQ() << " in function call to " << nodep->taskp()->prettyTypeName()); newvaluep = new AstConst{nodep->fileline(), AstConst::Unsized32{}, 0}; - } else { - newvaluep = newvaluep->cloneTree(true); } - } else { - newvaluep = VN_AS(portp->valuep(), NodeExpr)->cloneTree(true); } + newvaluep = newvaluep->cloneTree(true); // To avoid problems with callee needing to know to deleteTree // or not, we make this into a pin UINFO(9, "Default pin for " << portp << endl); diff --git a/src/V3ThreadPool.cpp b/src/V3ThreadPool.cpp index 63469681a..8eadc7b61 100644 --- a/src/V3ThreadPool.cpp +++ b/src/V3ThreadPool.cpp @@ -61,7 +61,7 @@ void V3ThreadPool::workerJobLoop(int id) VL_MT_SAFE { while (true) { // Wait for a notification waitIfStopRequested(); - job_t job; + VAnyPackagedTask job; { V3LockGuard lock(m_mutex); m_cv.wait(m_mutex, [&]() VL_REQUIRES(m_mutex) { @@ -72,7 +72,7 @@ void V3ThreadPool::workerJobLoop(int id) VL_MT_SAFE { // Get the job UASSERT(!m_queue.empty(), "Job should be available"); - job = m_queue.front(); + job = std::move(m_queue.front()); m_queue.pop(); } @@ -81,40 +81,6 @@ void V3ThreadPool::workerJobLoop(int id) VL_MT_SAFE { } } -template <> -void V3ThreadPool::pushJob(std::shared_ptr>& prom, - std::function&& f) VL_MT_SAFE { - if (willExecuteSynchronously()) { - f(); - prom->set_value(); - } else { - const V3LockGuard lock{m_mutex}; - m_queue.push([prom, f] { - f(); - prom->set_value(); - }); - } -} - -void V3ThreadPool::requestExclusiveAccess(const V3ThreadPool::job_t&& exclusiveAccessJob) - VL_MT_SAFE { - if (willExecuteSynchronously()) { - exclusiveAccessJob(); - } else { - V3LockGuard stoppedJobLock{m_stoppedJobsMutex}; - // if some other job already requested exclusive access - // wait until it stops - if (stopRequested()) { waitStopRequested(); } - m_stopRequested = true; - waitOtherThreads(); - m_exclusiveAccess = true; - exclusiveAccessJob(); - m_exclusiveAccess = false; - m_stopRequested = false; - m_stoppedJobsCV.notify_all(); - } -} - bool V3ThreadPool::waitIfStopRequested() VL_MT_SAFE VL_EXCLUDES(m_stoppedJobsMutex) { if (!stopRequested()) return false; V3LockGuard stoppedJobLock(m_stoppedJobsMutex); @@ -150,11 +116,10 @@ void V3ThreadPool::selfTest() { auto firstJob = [&](int sleep) -> void { std::this_thread::sleep_for(std::chrono::milliseconds{sleep}); - s().requestExclusiveAccess([&]() { - commonValue = 10; - std::this_thread::sleep_for(std::chrono::milliseconds{sleep + 10}); - UASSERT(commonValue == 10, "unexpected commonValue = " << commonValue); - }); + const V3ThreadPool::ScopedExclusiveAccess exclusiveAccess; + commonValue = 10; + std::this_thread::sleep_for(std::chrono::milliseconds{sleep + 10}); + UASSERT(commonValue == 10, "unexpected commonValue = " << commonValue); }; auto secondJob = [&](int sleep) -> void { commonMutex.lock(); @@ -175,19 +140,19 @@ void V3ThreadPool::selfTest() { }; std::list> futures; - futures.push_back(s().enqueue(std::bind(firstJob, 100))); - futures.push_back(s().enqueue(std::bind(secondJob, 100))); - futures.push_back(s().enqueue(std::bind(firstJob, 100))); - futures.push_back(s().enqueue(std::bind(secondJob, 100))); - futures.push_back(s().enqueue(std::bind(secondJob, 200))); - futures.push_back(s().enqueue(std::bind(firstJob, 200))); - futures.push_back(s().enqueue(std::bind(firstJob, 300))); + futures.push_back(s().enqueue(std::bind(firstJob, 100))); + futures.push_back(s().enqueue(std::bind(secondJob, 100))); + futures.push_back(s().enqueue(std::bind(firstJob, 100))); + futures.push_back(s().enqueue(std::bind(secondJob, 100))); + futures.push_back(s().enqueue(std::bind(secondJob, 200))); + futures.push_back(s().enqueue(std::bind(firstJob, 200))); + futures.push_back(s().enqueue(std::bind(firstJob, 300))); while (!futures.empty()) { s().waitForFuture(futures.front()); futures.pop_front(); } - futures.push_back(s().enqueue(std::bind(thirdJob, 100))); - futures.push_back(s().enqueue(std::bind(thirdJob, 100))); + futures.push_back(s().enqueue(std::bind(thirdJob, 100))); + futures.push_back(s().enqueue(std::bind(thirdJob, 100))); V3ThreadPool::waitForFutures(futures); s().waitIfStopRequested(); @@ -195,7 +160,7 @@ void V3ThreadPool::selfTest() { auto forthJob = [&]() -> int { return 1234; }; std::list> futuresInt; - futuresInt.push_back(s().enqueue(forthJob)); + futuresInt.push_back(s().enqueue(forthJob)); auto result = V3ThreadPool::waitForFutures(futuresInt); UASSERT(result.back() == 1234, "unexpected future result = " << result.back()); } diff --git a/src/V3ThreadPool.h b/src/V3ThreadPool.h index d87d5be17..b7c0658f4 100644 --- a/src/V3ThreadPool.h +++ b/src/V3ThreadPool.h @@ -29,13 +29,53 @@ //============================================================================ +// Callable, type-erased wrapper for std::packaged_task with any Signature. +class VAnyPackagedTask final { + // TYPES + struct PTWrapperBase { + virtual ~PTWrapperBase() {} + virtual void operator()() = 0; + }; + + template + struct PTWrapper final : PTWrapperBase { + std::packaged_task m_pt; + + PTWrapper(std::packaged_task&& pt) + : m_pt(std::move(pt)) {} + + void operator()() final override { m_pt(); } + }; + + // MEMBERS + std::unique_ptr m_ptWrapperp = nullptr; // Wrapper to call + +public: + // CONSTRUCTORS + template + VAnyPackagedTask(std::packaged_task&& pt) + : m_ptWrapperp{std::make_unique>(std::move(pt))} {} + + VAnyPackagedTask() = default; + ~VAnyPackagedTask() = default; + + VAnyPackagedTask(const VAnyPackagedTask&) = delete; + VAnyPackagedTask& operator=(const VAnyPackagedTask&) = delete; + + VAnyPackagedTask(VAnyPackagedTask&&) = default; + VAnyPackagedTask& operator=(VAnyPackagedTask&&) = default; + + // METHODS + // Call the wrapped function + void operator()() { (*m_ptWrapperp)(); } +}; + class V3ThreadPool final { // MEMBERS static constexpr unsigned int FUTUREWAITFOR_MS = 100; - using job_t = std::function; - mutable V3Mutex m_mutex; // Mutex for use by m_queue - std::queue m_queue VL_GUARDED_BY(m_mutex); // Queue of jobs + V3Mutex m_mutex; // Mutex for use by m_queue + std::queue m_queue VL_GUARDED_BY(m_mutex); // Queue of jobs // We don't need to guard this condition_variable as // both `notify_one` and `notify_all` functions are atomic, // `wait` function is not atomic, but we are guarding `m_queue` that is @@ -62,6 +102,9 @@ class V3ThreadPool final { } public: + // Request exclusive access to processing for the object lifetime. + class ScopedExclusiveAccess; + // METHODS // Singleton static V3ThreadPool& s() VL_MT_SAFE { @@ -79,8 +122,8 @@ public: // will call it. `VL_MT_START` here indicates that // every function call inside this `std::function` requires // annotations. - template - std::future enqueue(std::function&& f) VL_MT_START; + template + auto enqueue(Callable&& f) VL_MT_START; // Request exclusive access to processing. // It sends request to stop all other threads and waits for them to stop. @@ -88,7 +131,9 @@ public: // they can be stopped. // When all other threads are stopped, this function executes the job // and resumes execution of other jobs. - void requestExclusiveAccess(const job_t&& exclusiveAccessJob) VL_MT_SAFE; + template + void requestExclusiveAccess(Callable&& exclusiveAccessJob) VL_MT_SAFE + VL_EXCLUDES(m_stoppedJobsMutex); // Check if other thread requested exclusive access to processing, // if so, it waits for it to complete. Afterwards it is resumed. @@ -151,14 +196,39 @@ private: // Waits until all other jobs are stopped void waitOtherThreads() VL_MT_SAFE_EXCLUDES(m_mutex) VL_REQUIRES(m_stoppedJobsMutex); - template - void pushJob(std::shared_ptr>& prom, std::function&& f) VL_MT_SAFE; - void workerJobLoop(int id) VL_MT_SAFE; static void startWorker(V3ThreadPool* selfThreadp, int id) VL_MT_SAFE; }; +class VL_SCOPED_CAPABILITY V3ThreadPool::ScopedExclusiveAccess final { +public: + ScopedExclusiveAccess() VL_ACQUIRE(V3ThreadPool::s().m_stoppedJobsMutex) VL_MT_SAFE { + if (!V3ThreadPool::s().willExecuteSynchronously()) { + V3ThreadPool::s().m_stoppedJobsMutex.lock(); + + if (V3ThreadPool::s().stopRequested()) { V3ThreadPool::s().waitStopRequested(); } + V3ThreadPool::s().m_stopRequested = true; + V3ThreadPool::s().waitOtherThreads(); + V3ThreadPool::s().m_exclusiveAccess = true; + } else { + V3ThreadPool::s().m_stoppedJobsMutex.assumeLocked(); + } + } + ~ScopedExclusiveAccess() VL_RELEASE(V3ThreadPool::s().m_stoppedJobsMutex) VL_MT_SAFE { + // Can't use `willExecuteSynchronously`, we're still in exclusive execution state. + if (V3ThreadPool::s().m_exclusiveAccess) { + V3ThreadPool::s().m_exclusiveAccess = false; + V3ThreadPool::s().m_stopRequested = false; + V3ThreadPool::s().m_stoppedJobsCV.notify_all(); + + V3ThreadPool::s().m_stoppedJobsMutex.unlock(); + } else { + V3ThreadPool::s().m_stoppedJobsMutex.pretendUnlock(); + } + } +}; + template T V3ThreadPool::waitForFuture(std::future& future) VL_MT_SAFE_EXCLUDES(m_mutex) { while (true) { @@ -175,29 +245,28 @@ T V3ThreadPool::waitForFuture(std::future& future) VL_MT_SAFE_EXCLUDES(m_mute } } -template -std::future V3ThreadPool::enqueue(std::function&& f) VL_MT_START { - std::shared_ptr> prom = std::make_shared>(); - std::future result = prom->get_future(); - pushJob(prom, std::move(f)); - const V3LockGuard guard{m_mutex}; - m_cv.notify_one(); - return result; -} - -template -void V3ThreadPool::pushJob(std::shared_ptr>& prom, - std::function&& f) VL_MT_SAFE { +template +auto V3ThreadPool::enqueue(Callable&& f) VL_MT_START { + using result_t = decltype(f()); + auto&& job = std::packaged_task{std::forward(f)}; + auto future = job.get_future(); if (willExecuteSynchronously()) { - prom->set_value(f()); + job(); } else { - const V3LockGuard guard{m_mutex}; - m_queue.push([prom, f] { prom->set_value(f()); }); + { + const V3LockGuard guard{m_mutex}; + m_queue.push(std::move(job)); + } + m_cv.notify_one(); } + return future; } -template <> -void V3ThreadPool::pushJob(std::shared_ptr>& prom, - std::function&& f) VL_MT_SAFE; +template +void V3ThreadPool::requestExclusiveAccess(Callable&& exclusiveAccessJob) VL_MT_SAFE + VL_EXCLUDES(m_stoppedJobsMutex) { + ScopedExclusiveAccess exclusive_access; + exclusiveAccessJob(); +} #endif // Guard diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index fc2d06029..ab099d647 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -53,6 +53,7 @@ #include "V3Const.h" #include "V3EmitV.h" #include "V3Graph.h" +#include "V3MemberMap.h" #include "V3SenExprBuilder.h" #include "V3SenTree.h" #include "V3UniqueNames.h" @@ -63,41 +64,85 @@ VL_DEFINE_DEBUG_FUNCTIONS; // ###################################################################### -enum TimingFlag : uint8_t { - // Properties of flags with higher numbers include properties of flags with - // lower numbers - T_NORM = 0, // Normal non-suspendable process - T_SUSP = 1, // Suspendable - T_PROC = 2 // Suspendable with process metadata +enum NodeFlag : uint8_t { + T_SUSPENDEE = 1 << 0, // Suspendable (due to dependence on another suspendable) + T_SUSPENDER = 1 << 1, // Suspendable (has timing control) + T_HAS_PROC = 1 << 2, // Has an associated std::process + T_CALLS_PROC_SELF = 1 << 3, // Calls std::process::self +}; + +enum ForkType : uint8_t { + F_NONE = 0, // Not under a fork + F_MIGHT_SUSPEND = 1 << 0, // Fork might suspend the execution of current process + F_MIGHT_NEED_PROC = 1 << 1, // Fork might need a process (any fork really) +}; + +enum PropagationType : uint8_t { + P_CALL = 1, // Propagation through call to a function/task/method + P_FORK = 2, // Propagation due to fork's behaviour + P_SIGNATURE = 3, // Propagation required to maintain C++ function's signature requirements }; // ###################################################################### -// Detect nodes affected by timing +// Detect nodes affected by timing and/or requiring a process class TimingSuspendableVisitor final : public VNVisitor { private: // TYPES // Vertex of a dependency graph of suspendable nodes, e.g. if a node (process or task) is // suspendable, all its dependents should also be suspendable - class TimingDependencyVertex final : public V3GraphVertex { + class DepVtx VL_NOT_FINAL : public V3GraphVertex { + AstClass* const m_classp; // Class associated with a method AstNode* const m_nodep; // AST node represented by this graph vertex // ACCESSORS - string name() const override VL_MT_STABLE { + string name() const override { + if (m_classp) { + if (VN_IS(nodep(), CFunc)) { + return cvtToHex(nodep()) + ' ' + classp()->name() + "::" + nodep()->name(); + } + } return cvtToHex(nodep()) + ' ' + nodep()->prettyTypeName(); } FileLine* fileline() const override { return nodep()->fileline(); } - string dotColor() const override { return nodep()->user2() ? "red" : "black"; } public: // CONSTRUCTORS - TimingDependencyVertex(V3Graph* graphp, AstNode* nodep) + DepVtx(V3Graph* graphp, AstNode* nodep, AstClass* classp) : V3GraphVertex{graphp} + , m_classp{classp} , m_nodep{nodep} {} - ~TimingDependencyVertex() override = default; + ~DepVtx() override = default; // ACCESSORS virtual AstNode* nodep() const VL_MT_STABLE { return m_nodep; } + virtual AstNode* classp() const VL_MT_STABLE { return m_classp; } + }; + + class SuspendDepVtx final : public DepVtx { + string dotColor() const override { + if (nodep()->user2() & T_SUSPENDER) return "red"; + if (nodep()->user2() & T_SUSPENDEE) return "blue"; + return "black"; + } + + public: + SuspendDepVtx(V3Graph* graphp, AstNode* nodep, AstClass* classp) + : DepVtx{graphp, nodep, classp} {} + ~SuspendDepVtx() override = default; + }; + + class NeedsProcDepVtx final : public DepVtx { + string dotColor() const override { + if (nodep()->user2() & T_CALLS_PROC_SELF) return "red"; + if (nodep()->user2() & T_HAS_PROC) return "blue"; + return "black"; + } + + public: + NeedsProcDepVtx(V3Graph* graphp, AstNode* nodep, AstClass* classp) + : DepVtx{graphp, nodep, classp} {} + ~NeedsProcDepVtx() override = default; }; // NODE STATE @@ -108,40 +153,70 @@ private: // process/task suspendable // and to T_PROC if it // needs process metadata. - // Ast{NodeProcedure,CFunc,Begin}::user3() -> DependencyVertex*. Vertex in m_depGraph + // Ast{NodeProcedure,CFunc,Begin}::user3() -> DependencyVertex*. Vertex in m_suspGraph + // Ast{NodeProcedure,CFunc,Begin}::user3() -> DependencyVertex*. Vertex in m_procGraph const VNUser1InUse m_user1InUse; const VNUser2InUse m_user2InUse; const VNUser3InUse m_user3InUse; + const VNUser5InUse m_user5InUse; // STATE + VMemberMap memberMap; // Member names cached for fast lookup AstClass* m_classp = nullptr; // Current class AstNode* m_procp = nullptr; // NodeProcedure/CFunc/Begin we're under - V3Graph m_depGraph; // Dependency graph where a node is a dependency of another if it being - // suspendable makes the other node suspendable + uint8_t m_underFork = F_NONE; // F_NONE or flags of a fork we are under + V3Graph m_suspGraph; // Dependency graph where a node is a dependency of another if it being + // suspendable makes the other node suspendable + V3Graph m_procGraph; // Dependency graph where a node is a dependency of another if it being + // suspendable makes the other node suspendable // METHODS // Get or create the dependency vertex for the given node - TimingDependencyVertex* getDependencyVertex(AstNode* const nodep) { - if (!nodep->user3p()) nodep->user3p(new TimingDependencyVertex{&m_depGraph, nodep}); - return nodep->user3u().to(); + DepVtx* getSuspendDepVtx(AstNode* const nodep) { + AstClass* classp = nullptr; + if (AstCFunc* funcp = VN_CAST(nodep, CFunc)) { + if (funcp->scopep() && funcp->scopep()->modp()) { + classp = VN_CAST(funcp->scopep()->modp(), Class); + } + } + if (!nodep->user3p()) nodep->user3p(new SuspendDepVtx{&m_suspGraph, nodep, classp}); + return nodep->user3u().to(); + } + DepVtx* getNeedsProcDepVtx(AstNode* const nodep) { + AstClass* classp = nullptr; + if (AstCFunc* funcp = VN_CAST(nodep, CFunc)) { + if (funcp->scopep() && funcp->scopep()->modp()) { + classp = VN_CAST(funcp->scopep()->modp(), Class); + } + } + if (!nodep->user5p()) nodep->user5p(new NeedsProcDepVtx{&m_procGraph, nodep, classp}); + return nodep->user5u().to(); } // Set timing flag of a node - bool setTimingFlag(AstNode* nodep, int flag) { - // Properties of flags with higher numbers include properties of flags with lower - // numbers, so modify nodep->user2() only if it will increase. - if (nodep->user2() < flag) { - nodep->user2(flag); + bool passFlag(const AstNode* from, AstNode* to, NodeFlag flag) { + if ((from->user2() & flag) && !(to->user2() & flag)) { + to->user2(to->user2() | flag); return true; } return false; } - // Propagate suspendable/needProcess flag to all nodes that depend on the given one - void propagateTimingFlags(TimingDependencyVertex* const vxp) { + // Propagate flag to all nodes that depend on the given one + void propagateFlags(DepVtx* const vxp, NodeFlag flag) { + auto* const parentp = vxp->nodep(); + for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep = edgep->outNextp()) { + auto* const depVxp = static_cast(edgep->top()); + AstNode* const depp = depVxp->nodep(); + if (passFlag(parentp, depp, flag)) propagateFlags(depVxp, flag); + } + } + template + void propagateFlagsReversedIf(DepVtx* const vxp, NodeFlag flag, Predicate p) { auto* const parentp = vxp->nodep(); for (V3GraphEdge* edgep = vxp->inBeginp(); edgep; edgep = edgep->inNextp()) { - auto* const depVxp = static_cast(edgep->fromp()); + auto* const depVxp = static_cast(edgep->fromp()); AstNode* const depp = depVxp->nodep(); - if (setTimingFlag(depp, parentp->user2())) propagateTimingFlags(depVxp); + if (p(edgep) && passFlag(parentp, depp, flag)) + propagateFlagsReversedIf(depVxp, flag, p); } } @@ -155,17 +230,20 @@ private: void visit(AstNodeProcedure* nodep) override { VL_RESTORER(m_procp); m_procp = nodep; + if (nodep->needProcess()) nodep->user2(T_HAS_PROC | T_CALLS_PROC_SELF); + if (VN_IS(nodep, Always)) { + UINFO(1, "Always does " << (nodep->needProcess() ? "" : "NOT ") << "need process\n"); + } iterateChildren(nodep); } void visit(AstCFunc* nodep) override { VL_RESTORER(m_procp); m_procp = nodep; iterateChildren(nodep); - TimingDependencyVertex* const vxp = getDependencyVertex(nodep); - if (nodep->needProcess()) nodep->user2(T_PROC); + if (nodep->needProcess()) nodep->user2(T_HAS_PROC | T_CALLS_PROC_SELF); + DepVtx* const sVxp = getSuspendDepVtx(nodep); + DepVtx* const pVxp = getNeedsProcDepVtx(nodep); if (!m_classp) return; - // If class method (possibly overrides another method) - if (!m_classp->user1SetOnce()) m_classp->repairCache(); // Go over overridden functions @@ -182,19 +260,15 @@ private: // actually overridden by our method. If this causes a problem, traverse to // the root of the inheritance hierarchy and check if the original method is // virtual or not. - if (!cextp->classp()->user1SetOnce()) cextp->classp()->repairCache(); if (auto* const overriddenp - = VN_CAST(cextp->classp()->findMember(nodep->name()), CFunc)) { - setTimingFlag(nodep, overriddenp->user2()); - if (nodep->user2() - < T_PROC) { // Add a vertex only if the flag can still change - // Make a dependency cycle, as being suspendable should propagate both up - // and down the inheritance tree - TimingDependencyVertex* const overriddenVxp - = getDependencyVertex(overriddenp); - new V3GraphEdge{&m_depGraph, vxp, overriddenVxp, 1}; - new V3GraphEdge{&m_depGraph, overriddenVxp, vxp, 1}; - } + = VN_CAST(memberMap.findMember(cextp->classp(), nodep->name()), CFunc)) { + // Suspendability and process affects typing, so they propagate both ways + DepVtx* const overriddenSVxp = getSuspendDepVtx(overriddenp); + DepVtx* const overriddenPVxp = getNeedsProcDepVtx(overriddenp); + new V3GraphEdge{&m_suspGraph, sVxp, overriddenSVxp, P_SIGNATURE}; + new V3GraphEdge{&m_suspGraph, overriddenSVxp, sVxp, P_SIGNATURE}; + new V3GraphEdge{&m_procGraph, pVxp, overriddenPVxp, P_SIGNATURE}; + new V3GraphEdge{&m_procGraph, overriddenPVxp, pVxp, P_SIGNATURE}; } else { AstClassExtends* more_extends = cextp->classp()->extendsp(); if (more_extends) extends.push(more_extends); @@ -203,30 +277,49 @@ private: } } void visit(AstNodeCCall* nodep) override { - setTimingFlag(m_procp, nodep->funcp()->user2()); - if (m_procp->user2() < T_PROC) { // Add a vertex only if the flag can still change - TimingDependencyVertex* const procVxp = getDependencyVertex(m_procp); - TimingDependencyVertex* const funcVxp = getDependencyVertex(nodep->funcp()); - new V3GraphEdge{&m_depGraph, procVxp, funcVxp, 1}; - iterateChildren(nodep); - } + if (!m_underFork || (m_underFork & F_MIGHT_SUSPEND)) + new V3GraphEdge{&m_suspGraph, getSuspendDepVtx(nodep->funcp()), + getSuspendDepVtx(m_procp), m_underFork ? P_FORK : P_CALL}; + + if (!m_underFork) + new V3GraphEdge{&m_procGraph, getNeedsProcDepVtx(nodep->funcp()), + getNeedsProcDepVtx(m_procp), P_CALL}; + + iterateChildren(nodep); } void visit(AstBegin* nodep) override { VL_RESTORER(m_procp); + VL_RESTORER(m_underFork); + + if (!m_underFork || (m_underFork & F_MIGHT_SUSPEND)) + new V3GraphEdge{&m_suspGraph, getSuspendDepVtx(nodep), getSuspendDepVtx(m_procp), + m_underFork ? P_FORK : P_CALL}; + + if (!m_underFork) + new V3GraphEdge{&m_procGraph, getNeedsProcDepVtx(nodep), getNeedsProcDepVtx(m_procp), + P_CALL}; + m_procp = nodep; + m_underFork = 0; iterateChildren(nodep); } void visit(AstFork* nodep) override { + VL_RESTORER(m_underFork); + v3Global.setUsesTiming(); // Even if there are no event controls, we have to set this flag // so that transformForks() in V3SchedTiming gets called and // removes all forks and begins - if (nodep->isTimingControl() && m_procp) m_procp->user2(T_SUSP); + if (nodep->isTimingControl() && m_procp) { + m_procp->user2(T_SUSPENDEE | T_SUSPENDER); + m_underFork |= F_MIGHT_SUSPEND; + } + m_underFork |= F_MIGHT_NEED_PROC; iterateChildren(nodep); } void visit(AstNode* nodep) override { if (nodep->isTimingControl()) { v3Global.setUsesTiming(); - if (m_procp) m_procp->user2(T_SUSP); + if (m_procp) m_procp->user2(T_SUSPENDEE | T_SUSPENDER); } iterateChildren(nodep); } @@ -238,12 +331,29 @@ public: // CONSTRUCTORS explicit TimingSuspendableVisitor(AstNetlist* nodep) { iterate(nodep); - m_depGraph.removeTransitiveEdges(); - for (V3GraphVertex* vxp = m_depGraph.verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { - TimingDependencyVertex* const depVxp = static_cast(vxp); - if (depVxp->nodep()->user2()) propagateTimingFlags(depVxp); + m_suspGraph.removeTransitiveEdges(); + m_procGraph.removeTransitiveEdges(); + // Propagate suspendability + for (V3GraphVertex* vxp = m_suspGraph.verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { + DepVtx* const depVxp = static_cast(vxp); + if (depVxp->nodep()->user2() & T_SUSPENDEE) propagateFlags(depVxp, T_SUSPENDEE); } - if (dumpGraphLevel() >= 6) m_depGraph.dumpDotFilePrefixed("timing_deps"); + if (dumpGraphLevel() >= 6) m_suspGraph.dumpDotFilePrefixed("timing_deps"); + // Propagate process + for (V3GraphVertex* vxp = m_procGraph.verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { + DepVtx* const depVxp = static_cast(vxp); + if (depVxp->nodep()->user2() & T_HAS_PROC) propagateFlags(depVxp, T_HAS_PROC); + } + // Propagate process downwards (from caller to callee) for suspendable calls + for (V3GraphVertex* vxp = m_suspGraph.verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { + DepVtx* const depVxp = static_cast(vxp); + if (depVxp->nodep()->user2() & T_HAS_PROC) + propagateFlagsReversedIf(depVxp, T_HAS_PROC, [&](const V3GraphEdge* e) -> bool { + return (e->weight() != P_FORK) + && (static_cast(e->top())->nodep()->user2() & T_SUSPENDEE); + }); + } + if (dumpGraphLevel() >= 6) m_procGraph.dumpDotFilePrefixed("proc_deps"); } ~TimingSuspendableVisitor() override = default; }; @@ -277,13 +387,13 @@ private: AstActive* m_activep = nullptr; // Current active AstNode* m_procp = nullptr; // NodeProcedure/CFunc/Begin we're under double m_timescaleFactor = 1.0; // Factor to scale delays by + int m_forkCnt = 0; // Number of forks inside a module // Unique names V3UniqueNames m_contAssignVarNames{"__VassignWtmp"}; // Names for temp AssignW vars V3UniqueNames m_intraValueNames{"__Vintraval"}; // Intra assign delay value var names V3UniqueNames m_intraIndexNames{"__Vintraidx"}; // Intra assign delay index var names V3UniqueNames m_intraLsbNames{"__Vintralsb"}; // Intra assign delay LSB var names - V3UniqueNames m_forkNames{"__Vfork"}; // Fork name generator V3UniqueNames m_trigSchedNames{"__VtrigSched"}; // Trigger scheduler name generator V3UniqueNames m_dynTrigNames{"__VdynTrigger"}; // Dynamic trigger name generator @@ -299,6 +409,7 @@ private: // Other SenTreeFinder m_finder{m_netlistp}; // Sentree finder and uniquifier + SenExprBuilder* m_senExprBuilderp = nullptr; // Sens expression builder for current m_scope // METHODS // Find net delay on the LHS of an assignment @@ -358,23 +469,6 @@ private: int scalePowerOfTen = timeunit.powerOfTen() - m_netlistp->timeprecision().powerOfTen(); return std::pow(10.0, scalePowerOfTen); } - // Construct SenItems from VarRefs in an expression - AstSenItem* varRefpsToSenItemsp(AstNode* const nodep) const { - AstNode* senItemsp = nullptr; - const VNUser4InUse user4InUse; - nodep->foreach([&](AstNodeVarRef* refp) { - if (refp->access().isWriteOnly()) return; - AstVarScope* const vscp = refp->varScopep(); - if (vscp->user4SetOnce()) return; - const bool isEvent = vscp->dtypep() && vscp->dtypep()->basicp() - && vscp->dtypep()->basicp()->isEvent(); - const auto edgeType = isEvent ? VEdgeType::ET_EVENT : VEdgeType::ET_CHANGED; - senItemsp = AstNode::addNext( - senItemsp, new AstSenItem{refp->fileline(), edgeType, - new AstVarRef{refp->fileline(), vscp, VAccess::READ}}); - }); - return VN_AS(senItemsp, SenItem); - } // Creates the global delay scheduler variable AstVarScope* getCreateDelayScheduler() { if (m_delaySchedp) return m_delaySchedp; @@ -488,7 +582,7 @@ private: void addProcessInfo(AstCMethodHard* const methodp) const { FileLine* const flp = methodp->fileline(); AstCExpr* const ap = new AstCExpr{ - flp, m_procp && m_procp->user2() == T_PROC ? "vlProcess" : "nullptr", 0}; + flp, m_procp && (m_procp->user2() & T_HAS_PROC) ? "vlProcess" : "nullptr", 0}; ap->dtypeSetVoid(); methodp->addPinsp(ap); } @@ -564,12 +658,19 @@ private: m_classp = VN_CAST(nodep, Class); VL_RESTORER(m_timescaleFactor); m_timescaleFactor = calculateTimescaleFactor(nodep->timeunit()); + VL_RESTORER(m_forkCnt); + m_forkCnt = 0; iterateChildren(nodep); } void visit(AstScope* nodep) override { VL_RESTORER(m_scopep); m_scopep = nodep; - iterateChildren(nodep); + SenExprBuilder senExprBuilder{m_scopep}; + { // Restore m_senExprBuilderp before destroying senExprBuilder + VL_RESTORER(m_senExprBuilderp); + m_senExprBuilderp = &senExprBuilder; + iterateChildren(nodep); + } } void visit(AstActive* nodep) override { m_activep = nodep; @@ -580,8 +681,8 @@ private: VL_RESTORER(m_procp); m_procp = nodep; iterateChildren(nodep); - if (nodep->user2() >= T_SUSP) nodep->setSuspendable(); - if (nodep->user2() >= T_PROC) nodep->setNeedProcess(); + if (nodep->user2() & T_SUSPENDEE) nodep->setSuspendable(); + if (nodep->user2() & T_HAS_PROC) nodep->setNeedProcess(); } void visit(AstInitial* nodep) override { visit(static_cast(nodep)); @@ -592,9 +693,16 @@ private: } void visit(AstAlways* nodep) override { if (nodep->user1SetOnce()) return; + VL_RESTORER(m_procp); + m_procp = nodep; + + // Workaround for killing `always` processes (doing that is pretty much UB) + // TODO: Disallow killing `always` at runtime (throw an error) + if (nodep->user2() & T_HAS_PROC) nodep->user2(nodep->user2() | T_SUSPENDEE); + iterateChildren(nodep); - if (!nodep->user2()) return; - if (nodep->user2() == T_PROC) nodep->setNeedProcess(); + if (nodep->user2() & T_HAS_PROC) nodep->setNeedProcess(); + if (!(nodep->user2() & T_SUSPENDEE)) return; nodep->setSuspendable(); FileLine* const flp = nodep->fileline(); AstSenTree* const sensesp = m_activep->sensesp(); @@ -615,7 +723,9 @@ private: VL_RESTORER(m_procp); m_procp = nodep; iterateChildren(nodep); - if (!nodep->user2()) return; + if (nodep->user2() & T_HAS_PROC) nodep->setNeedProcess(); + if (!(nodep->user2() & T_SUSPENDEE)) return; + nodep->rtnType("VlCoroutine"); // If in a class, create a shared pointer to 'this' if (m_classp) nodep->addInitsp(new AstCStmt{nodep->fileline(), "VL_KEEP_THIS;\n"}); @@ -635,10 +745,9 @@ private: firstCoStmtp->v3warn(E_UNSUPPORTED, "Unsupported: Timing controls inside DPI-exported tasks"); } - if (nodep->user2() == T_PROC) nodep->setNeedProcess(); } void visit(AstNodeCCall* nodep) override { - if (nodep->funcp()->user2() && !nodep->user1SetOnce()) { // If suspendable + if ((nodep->funcp()->user2() & T_SUSPENDEE) && !nodep->user1SetOnce()) { // If suspendable VNRelinker relinker; nodep->unlinkFrBack(&relinker); AstCAwait* const awaitp = new AstCAwait{nodep->fileline(), nodep}; @@ -723,14 +832,14 @@ private: = new AstCAwait{flp, evalMethodp, getCreateDynamicTriggerSenTree()}; awaitEvalp->dtypeSetVoid(); // Construct the sen expression for this sentree - SenExprBuilder senExprBuilder{m_scopep}; + UASSERT_OBJ(m_senExprBuilderp, nodep, "No SenExprBuilder for this scope"); auto* const assignp = new AstAssign{flp, new AstVarRef{flp, trigvscp, VAccess::WRITE}, - senExprBuilder.build(sensesp).first}; + m_senExprBuilderp->build(sensesp).first}; // Put all the locals and inits before the trigger eval loop - for (AstVar* const varp : senExprBuilder.getAndClearLocals()) { + for (AstVar* const varp : m_senExprBuilderp->getAndClearLocals()) { nodep->addHereThisAsNext(varp); } - for (AstNodeStmt* const stmtp : senExprBuilder.getAndClearInits()) { + for (AstNodeStmt* const stmtp : m_senExprBuilderp->getAndClearInits()) { nodep->addHereThisAsNext(stmtp); } // Create the trigger eval loop, which will await the evaluation step and check the @@ -739,7 +848,7 @@ private: flp, new AstLogNot{flp, new AstVarRef{flp, trigvscp, VAccess::READ}}, awaitEvalp->makeStmt()}; // Put pre updates before the trigger check and assignment - for (AstNodeStmt* const stmtp : senExprBuilder.getAndClearPreUpdates()) { + for (AstNodeStmt* const stmtp : m_senExprBuilderp->getAndClearPreUpdates()) { loopp->addStmtsp(stmtp); } // Then the trigger check and assignment @@ -752,7 +861,7 @@ private: loopp->addStmtsp(awaitPostUpdatep->makeStmt()); } // Put the post updates at the end of the loop - for (AstNodeStmt* const stmtp : senExprBuilder.getAndClearPostUpdates()) { + for (AstNodeStmt* const stmtp : m_senExprBuilderp->getAndClearPostUpdates()) { loopp->addStmtsp(stmtp); } // Finally, await the resumption step in 'act' @@ -897,11 +1006,14 @@ private: if (stmtsp) AstNode::addNext(ifp, stmtsp); nodep->replaceWith(ifp); } else { - AstSenItem* const senItemsp = varRefpsToSenItemsp(condp); - UASSERT_OBJ(senItemsp, nodep, "No varrefs in wait statement condition"); - // Put the event control in a while loop with the wait expression as condition - AstEventControl* const controlp - = new AstEventControl{flp, new AstSenTree{flp, senItemsp}, nullptr}; + // We are using a global sentree, so we cannot use ET_TRUE, as that could lead to the + // active region never converging. Because of this, we need to use ET_CHANGED in a + // loop. + AstEventControl* const controlp = new AstEventControl{ + flp, + new AstSenTree{ + flp, new AstSenItem{flp, VEdgeType::ET_CHANGED, condp->cloneTree(false)}}, + nullptr}; controlp->user2(true); // Commit immediately AstWhile* const loopp = new AstWhile{flp, new AstLogNot{flp, condp}, controlp}; if (stmtsp) AstNode::addNext(loopp, stmtsp); @@ -918,7 +1030,7 @@ private: if (nodep->user1SetOnce()) return; v3Global.setUsesTiming(); // Create a unique name for this fork - nodep->name(m_forkNames.get(nodep)); + nodep->name("__Vfork_" + cvtToStr(++m_forkCnt)); unsigned idx = 0; // Index for naming begins AstNode* stmtp = nodep->stmtsp(); // Put each statement in a begin diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index ee0eeb271..6ad090603 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -154,7 +154,7 @@ public: // ACCESSORS AstNode* nodep() const VL_MT_STABLE { return m_nodep; } const AstVar* varp() const { return VN_CAST(nodep(), Var); } - string name() const override VL_MT_STABLE { + string name() const override { return ((isTristate() ? "tri\\n" : feedsTri() ? "feed\\n" : "-\\n") @@ -672,8 +672,7 @@ class TristateVisitor final : public TristateBaseVisitor { VFlagBitPacked{}, w}; // 2-state ok; sep enable UINFO(9, " newout " << newLhsp << endl); nodep->addStmtsp(newLhsp); - refp->varp(newLhsp); // assign the new var to the varref - refp->name(newLhsp->name()); + refp->varp(newLhsp); // create a new var for this drivers enable signal AstVar* const newEnLhsp = new AstVar{varp->fileline(), VVarType::MODULETEMP, diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 334987da8..aa3ee6581 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -70,6 +70,7 @@ #include "V3Const.h" #include "V3Global.h" +#include "V3MemberMap.h" #include "V3Number.h" #include "V3Randomize.h" #include "V3String.h" @@ -223,8 +224,8 @@ private: using DTypeMap = std::map; // STATE + VMemberMap memberMap; // Member names cached for fast lookup WidthVP* m_vup = nullptr; // Current node state - AstClass* m_classp = nullptr; // Current class const AstCell* m_cellp = nullptr; // Current cell for arrayed instantiations const AstEnumItem* m_enumItemp = nullptr; // Current enum item const AstNodeFTask* m_ftaskp = nullptr; // Current function/task @@ -232,7 +233,6 @@ private: const AstWith* m_withp = nullptr; // Current 'with' statement const AstFunc* m_funcp = nullptr; // Current function const AstAttrOf* m_attrp = nullptr; // Current attribute - AstPackage* m_pkgp = nullptr; // Current package const bool m_paramsOnly; // Computing parameter value; limit operation const bool m_doGenerate; // Do errors later inside generate statement int m_dtTables = 0; // Number of created data type tables @@ -615,9 +615,11 @@ private: } if (m_vup->final()) { if (nodep->lhsp()->isString() || nodep->rhsp()->isString()) { - AstNode* const newp - = new AstConcatN{nodep->fileline(), nodep->lhsp()->unlinkFrBack(), - nodep->rhsp()->unlinkFrBack()}; + AstNodeExpr* lhsp = nodep->lhsp()->unlinkFrBack(); + AstNodeExpr* rhsp = nodep->rhsp()->unlinkFrBack(); + if (!lhsp->isString()) lhsp = new AstCvtPackString{lhsp->fileline(), lhsp}; + if (!rhsp->isString()) rhsp = new AstCvtPackString{rhsp->fileline(), rhsp}; + AstNode* const newp = new AstConcatN{nodep->fileline(), lhsp, rhsp}; nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); return; @@ -729,19 +731,12 @@ private: // width: value(LHS) * width(RHS) if (m_vup->prelim()) { iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH); - V3Const::constifyParamsEdit(nodep->rhsp()); // rhsp may change + V3Const::constifyParamsNoWarnEdit(nodep->rhsp()); // rhsp may change + + uint32_t times = 1; + const AstConst* const constp = VN_CAST(nodep->rhsp(), Const); - if (!constp) { - nodep->v3error("Replication value isn't a constant."); - return; - } - uint32_t times = constp->toUInt(); - if (times == 0 - && !VN_IS(nodep->backp(), Concat)) { // Concat Visitor will clean it up. - nodep->v3error("Replication value of 0 is only legal under a concatenation" - " (IEEE 1800-2017 11.4.12.1)"); - times = 1; - } + if (constp) times = constp->toUInt(); AstNodeDType* const vdtypep = m_vup->dtypeNullSkipRefp(); if (VN_IS(vdtypep, QueueDType) || VN_IS(vdtypep, DynArrayDType) @@ -775,7 +770,7 @@ private: << vdtypep->prettyDTypeNameQ() << " data type"); } iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); - if (nodep->lhsp()->isString()) { + if ((vdtypep && vdtypep->isString()) || nodep->lhsp()->isString()) { AstNode* const newp = new AstReplicateN{nodep->fileline(), nodep->lhsp()->unlinkFrBack(), nodep->rhsp()->unlinkFrBack()}; @@ -783,6 +778,13 @@ private: VL_DO_DANGLING(pushDeletep(nodep), nodep); return; } else { + if (!constp) nodep->v3error("Replication value isn't a constant."); + if (times == 0 + && !VN_IS(nodep->backp(), Concat)) { // Concat Visitor will clean it up. + nodep->v3error("Replication value of 0 is only legal under a concatenation" + " (IEEE 1800-2017 11.4.12.1)"); + times = 1; // Set to 1, so we can continue looking for errors + } nodep->dtypeSetLogicUnsized((nodep->lhsp()->width() * times), (nodep->lhsp()->widthMin() * times), VSigning::UNSIGNED); @@ -801,18 +803,7 @@ private: if (m_vup->prelim()) { iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH); iterateCheckSizedSelf(nodep, "RHS", nodep->rhsp(), SELF, BOTH); - V3Const::constifyParamsEdit(nodep->rhsp()); // rhsp may change - const AstConst* const constp = VN_CAST(nodep->rhsp(), Const); - if (!constp) { - nodep->v3error("Replication value isn't a constant."); - return; - } - const uint32_t times = constp->toUInt(); - if (times == 0 - && !VN_IS(nodep->backp(), Concat)) { // Concat Visitor will clean it up. - nodep->v3error("Replication value of 0 is only legal under a concatenation" - " (IEEE 1800-2017 11.4.12.1)"); - } + V3Const::constifyParamsNoWarnEdit(nodep->rhsp()); // rhsp may change nodep->dtypeSetString(); } if (m_vup->final()) { @@ -848,8 +839,14 @@ private: } else { nodep->v3error("Slice size isn't a constant or basic data type."); } - nodep->dtypeSetLogicUnsized(nodep->lhsp()->width(), nodep->lhsp()->widthMin(), - VSigning::UNSIGNED); + if (VN_IS(nodep->lhsp()->dtypep(), DynArrayDType) + || VN_IS(nodep->lhsp()->dtypep(), QueueDType) + || VN_IS(nodep->lhsp()->dtypep(), UnpackArrayDType)) { + nodep->dtypeSetStream(); + } else { + nodep->dtypeSetLogicUnsized(nodep->lhsp()->width(), nodep->lhsp()->widthMin(), + VSigning::UNSIGNED); + } } if (m_vup->final()) { if (!nodep->dtypep()->widthSized()) { @@ -1550,7 +1547,7 @@ private: nodep->v3warn(E_UNSUPPORTED, "Unsupported: $bits for queue"); break; } - default: nodep->v3error("Unhandled attribute type"); + default: nodep->v3fatalSrc("Unhandled attribute type"); } } else { const std::pair dimpair = dtypep->skipRefp()->dimensions(true); @@ -2115,6 +2112,10 @@ private: v3Global.rootp()->typeTablep()->addTypesp(newp); } } + if (AstWildcardArrayDType* const wildp + = VN_CAST(nodep->dtypeSkipRefp(), WildcardArrayDType)) { + nodep->dtypep(wildp); // Skip RefDType like for other dynamic array types + } if (VN_IS(nodep->dtypep()->skipRefToConstp(), ConstDType)) nodep->isConst(true); // Parameters if implicit untyped inherit from what they are assigned to const AstBasicDType* const bdtypep = VN_CAST(nodep->dtypep(), BasicDType); @@ -2577,7 +2578,6 @@ private: // if (debug() >= 9) nodep->dumpTree("- class-in: "); if (!nodep->packed() && v3Global.opt.structsPacked()) nodep->packed(true); userIterateChildren(nodep, nullptr); // First size all members - nodep->repairMemberCache(); nodep->dtypep(nodep); nodep->isFourstate(false); // Error checks @@ -2628,28 +2628,34 @@ private: } void visit(AstClass* nodep) override { if (nodep->didWidthAndSet()) return; - // If the package is std::process, set m_process type to VlProcessRef - if (m_pkgp && m_pkgp->name() == "std" && nodep->name() == "process") { - if (AstVar* const varp = VN_CAST(nodep->findMember("m_process"), Var)) { - AstBasicDType* const dtypep = new AstBasicDType{ - nodep->fileline(), VBasicDTypeKwd::PROCESS_REFERENCE, VSigning::UNSIGNED}; - v3Global.rootp()->typeTablep()->addTypesp(dtypep); - varp->getChildDTypep()->unlinkFrBack(); - varp->dtypep(dtypep); + + // If the class is std::process + if (nodep->name() == "process") { + AstPackage* const packagep = getItemPackage(nodep); + if (packagep && packagep->name() == "std") { + // Change type of m_process to VlProcessRef + if (AstVar* const varp = VN_CAST(memberMap.findMember(nodep, "m_process"), Var)) { + AstNodeDType* const dtypep = varp->getChildDTypep(); + if (!varp->dtypep()) { + VL_DO_DANGLING(pushDeletep(dtypep->unlinkFrBack()), dtypep); + } + AstBasicDType* const newdtypep = new AstBasicDType{ + nodep->fileline(), VBasicDTypeKwd::PROCESS_REFERENCE, VSigning::UNSIGNED}; + v3Global.rootp()->typeTablep()->addTypesp(newdtypep); + varp->dtypep(newdtypep); + } + // Mark that self requires process instance + if (AstNodeFTask* const ftaskp + = VN_CAST(memberMap.findMember(nodep, "self"), NodeFTask)) { + ftaskp->setNeedProcess(); + } } } + // Must do extends first, as we may in functions under this class // start following a tree of extends that takes us to other classes - VL_RESTORER(m_classp); - m_classp = nodep; userIterateAndNext(nodep->extendsp(), nullptr); userIterateChildren(nodep, nullptr); // First size all members - nodep->repairCache(); - } - void visit(AstPackage* nodep) override { - VL_RESTORER(m_pkgp); - m_pkgp = nodep; - userIterateChildren(nodep, nullptr); } void visit(AstThisRef* nodep) override { if (nodep->didWidthAndSet()) return; @@ -2704,31 +2710,7 @@ private: if (AstNodeUOrStructDType* const adtypep = VN_CAST(fromDtp, NodeUOrStructDType)) { if (memberSelStruct(nodep, adtypep)) return; } else if (AstClassRefDType* const adtypep = VN_CAST(fromDtp, ClassRefDType)) { - if (AstNode* const foundp = memberSelClass(nodep, adtypep)) { - if (AstVar* const varp = VN_CAST(foundp, Var)) { - if (!varp->didWidth()) userIterate(varp, nullptr); - nodep->dtypep(foundp->dtypep()); - nodep->varp(varp); - return; - } - if (AstEnumItemRef* const adfoundp = VN_CAST(foundp, EnumItemRef)) { - nodep->replaceWith(adfoundp->cloneTree(false)); - VL_DO_DANGLING(pushDeletep(nodep), nodep); - return; - } - if (AstNodeFTask* const methodp = VN_CAST(foundp, NodeFTask)) { - nodep->replaceWith(new AstMethodCall{nodep->fileline(), - nodep->fromp()->unlinkFrBack(), - nodep->name(), nullptr}); - VL_DO_DANGLING(pushDeletep(nodep), nodep); - return; - } - UINFO(1, "found object " << foundp << endl); - nodep->v3fatalSrc("MemberSel of non-variable\n" - << nodep->warnContextPrimary() << '\n' - << foundp->warnOther() << "... Location of found object\n" - << foundp->warnContextSecondary()); - } + if (memberSelClass(nodep, adtypep)) return; } else if (AstIfaceRefDType* const adtypep = VN_CAST(fromDtp, IfaceRefDType)) { if (AstNode* const foundp = memberSelIface(nodep, adtypep)) { if (AstVar* const varp = VN_CAST(foundp, Var)) { @@ -2767,15 +2749,50 @@ private: nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::BitFalse{}}); VL_DO_DANGLING(pushDeletep(nodep), nodep); } - AstNode* memberSelClass(AstMemberSel* nodep, AstClassRefDType* adtypep) { - // Returns node if ok + bool memberSelClass(AstMemberSel* nodep, AstClassRefDType* adtypep) { + // Returns true if ok // No need to width-resolve the class, as it was done when we did the child AstClass* const first_classp = adtypep->classp(); UASSERT_OBJ(first_classp, nodep, "Unlinked"); for (AstClass* classp = first_classp; classp;) { - if (AstNode* const foundp = classp->findMember(nodep->name())) return foundp; + if (AstNode* const foundp = memberMap.findMember(classp, nodep->name())) { + if (AstVar* const varp = VN_CAST(foundp, Var)) { + if (!varp->didWidth()) userIterate(varp, nullptr); + if (varp->lifetime().isStatic()) { + // Static fiels are moved outside the class, so they shouldn't be accessed + // by member select on a class object + AstVarRef* const varRefp + = new AstVarRef{nodep->fileline(), varp, nodep->access()}; + varRefp->classOrPackagep(classp); + nodep->replaceWith(varRefp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + return true; + } + nodep->dtypep(foundp->dtypep()); + nodep->varp(varp); + return true; + } + if (AstEnumItemRef* const adfoundp = VN_CAST(foundp, EnumItemRef)) { + nodep->replaceWith(adfoundp->cloneTree(false)); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + return true; + } + if (AstNodeFTask* const methodp = VN_CAST(foundp, NodeFTask)) { + nodep->replaceWith(new AstMethodCall{nodep->fileline(), + nodep->fromp()->unlinkFrBack(), + nodep->name(), nullptr}); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + return true; + } + UINFO(1, "found object " << foundp << endl); + nodep->v3fatalSrc("MemberSel of non-variable\n" + << nodep->warnContextPrimary() << '\n' + << foundp->warnOther() << "... Location of found object\n" + << foundp->warnContextSecondary()); + } classp = classp->extendsp() ? classp->extendsp()->classp() : nullptr; } + VSpellCheck speller; for (AstClass* classp = first_classp; classp;) { for (AstNode* itemp = classp->membersp(); itemp; itemp = itemp->nextp()) { @@ -2790,14 +2807,13 @@ private: "Member " << nodep->prettyNameQ() << " not found in class " << first_classp->prettyNameQ() << "\n" << (suggest.empty() ? "" : nodep->fileline()->warnMore() + suggest)); - return nullptr; // Caller handles error + return false; // Caller handles error } AstNode* memberSelIface(AstMemberSel* nodep, AstIfaceRefDType* adtypep) { // Returns node if ok // No need to width-resolve the interface, as it was done when we did the child AstNodeModule* const ifacep = adtypep->ifacep(); UASSERT_OBJ(ifacep, nodep, "Unlinked"); - // if (AstNode* const foundp = ifacep->findMember(nodep->name())) return foundp; VSpellCheck speller; for (AstNode* itemp = ifacep->stmtsp(); itemp; itemp = itemp->nextp()) { if (itemp->name() == nodep->name()) return itemp; @@ -2814,7 +2830,8 @@ private: } bool memberSelStruct(AstMemberSel* nodep, AstNodeUOrStructDType* adtypep) { // Returns true if ok - if (AstMemberDType* const memberp = adtypep->findMember(nodep->name())) { + if (AstMemberDType* const memberp + = VN_CAST(memberMap.findMember(adtypep, nodep->name()), MemberDType)) { if (m_attrp) { // Looking for the base of the attribute nodep->dtypep(memberp); UINFO(9, " MEMBERSEL(attr) -> " << nodep << endl); @@ -3202,10 +3219,12 @@ private: if (!nodep->firstAbovep()) newp->dtypeSetVoid(); } else if (nodep->name() == "min" || nodep->name() == "max" || nodep->name() == "unique" || nodep->name() == "unique_index") { + AstWith* const withp = methodWithArgument( + nodep, false, true, nullptr, nodep->findUInt32DType(), adtypep->subDTypep()); methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(), - nodep->name()}; + nodep->name(), withp}; if (nodep->name() == "unique_index") { newp->dtypep(queueDTypeIndexedBy(adtypep->keyDTypep())); } else { @@ -3477,8 +3496,10 @@ private: AstClass* const first_classp = adtypep->classp(); if (nodep->name() == "randomize") { V3Randomize::newRandomizeFunc(first_classp); + memberMap.clear(); } else if (nodep->name() == "srandom") { V3Randomize::newSRandomFunc(first_classp); + memberMap.clear(); } UASSERT_OBJ(first_classp, nodep, "Unlinked"); for (AstClass* classp = first_classp; classp;) { @@ -3501,7 +3522,7 @@ private: } } if (AstNodeFTask* const ftaskp - = VN_CAST(classp->findMember(nodep->name()), NodeFTask)) { + = VN_CAST(memberMap.findMember(classp, nodep->name()), NodeFTask)) { userIterate(ftaskp, nullptr); if (ftaskp->lifetime().isStatic()) { AstNodeExpr* argsp = nullptr; @@ -3771,7 +3792,7 @@ private: classp = refp->classp(); UASSERT_OBJ(classp, nodep, "Unlinked"); - if (AstNodeFTask* const ftaskp = VN_CAST(classp->findMember("new"), Func)) { + if (AstNodeFTask* const ftaskp = VN_CAST(memberMap.findMember(classp, "new"), Func)) { nodep->taskp(ftaskp); nodep->classOrPackagep(classp); } else { @@ -3939,7 +3960,8 @@ private: // '{member:value} or '{data_type: default_value} if (const AstText* textp = VN_CAST(patp->keyp(), Text)) { // member: value - memp = vdtypep->findMember(textp->text()); + memp = VN_CAST(memberMap.findMember(vdtypep, textp->text()), + MemberDType); if (!memp) { patp->keyp()->v3error("Assignment pattern key '" << textp->text() << "' not found as member"); @@ -5298,7 +5320,6 @@ private: nodep->didWidth(true); return; } - if (m_pkgp && m_pkgp->name() == "std") nodep->isFromStd(true); if (nodep->classMethod() && nodep->name() == "rand_mode") { nodep->v3error("The 'rand_mode' method is built-in and cannot be overridden" " (IEEE 1800-2017 18.8)"); @@ -5575,20 +5596,17 @@ private: || (!nodep->taskp() && (nodep->name() == "get_randstate" || nodep->name() == "set_randstate"))) { // TODO perhaps this should move to V3LinkDot - if (!m_classp) { - nodep->v3error("Calling implicit class method " << nodep->prettyNameQ() - << " without being under class"); - nodep->replaceWith(new AstConst{nodep->fileline(), 0}); - VL_DO_DANGLING(pushDeletep(nodep), nodep); - return; - } + AstClass* const classp = VN_CAST(nodep->classOrPackagep(), Class); + UASSERT_OBJ(classp, nodep, "Should have failed in V3LinkDot"); if (nodep->name() == "randomize") { - nodep->taskp(V3Randomize::newRandomizeFunc(m_classp)); + nodep->taskp(V3Randomize::newRandomizeFunc(classp)); + memberMap.clear(); } else if (nodep->name() == "srandom") { - nodep->taskp(V3Randomize::newSRandomFunc(m_classp)); + nodep->taskp(V3Randomize::newSRandomFunc(classp)); + memberMap.clear(); } else if (nodep->name() == "get_randstate") { methodOkArguments(nodep, 0, 0); - m_classp->baseMostClassp()->needRNG(true); + classp->baseMostClassp()->needRNG(true); v3Global.useRandomizeMethods(true); AstCExpr* const newp = new AstCExpr{nodep->fileline(), "__Vm_rng.get_randstate()", 1, true}; @@ -5601,7 +5619,7 @@ private: AstNodeExpr* const expr1p = VN_AS(nodep->pinsp(), Arg)->exprp(); // May edit iterateCheckString(nodep, "LHS", expr1p, BOTH); AstNodeExpr* const exprp = VN_AS(nodep->pinsp(), Arg)->exprp(); - m_classp->baseMostClassp()->needRNG(true); + classp->baseMostClassp()->needRNG(true); v3Global.useRandomizeMethods(true); AstCExpr* const newp = new AstCExpr{nodep->fileline(), "__Vm_rng.set_randstate(", 1, true}; @@ -5671,7 +5689,8 @@ private: } if (nodep->fileline()->timingOn()) { if (v3Global.opt.timing().isSetTrue()) { - userIterate(nodep->condp(), WidthVP{SELF, PRELIM}.p()); + iterateCheckBool(nodep, "Wait", nodep->condp(), + BOTH); // it's like an if() condition. iterateNull(nodep->stmtsp()); return; } else if (v3Global.opt.timing().isSetFalse()) { @@ -6371,7 +6390,7 @@ private: } void checkClassAssign(AstNode* nodep, const char* side, AstNode* rhsp, AstNodeDType* lhsDTypep) { - if (AstClassRefDType* const lhsClassRefp = VN_CAST(lhsDTypep, ClassRefDType)) { + if (AstClassRefDType* const lhsClassRefp = VN_CAST(lhsDTypep->skipRefp(), ClassRefDType)) { UASSERT_OBJ(rhsp->dtypep(), rhsp, "Node has no type"); AstNodeDType* const rhsDtypep = rhsp->dtypep()->skipRefp(); if (AstClassRefDType* const rhsClassRefp = VN_CAST(rhsDtypep, ClassRefDType)) { @@ -6379,7 +6398,7 @@ private: } else if (auto* const constp = VN_CAST(rhsp, Const)) { if (constp->num().isNull()) return; } - nodep->v3error(side << " expects a " << lhsDTypep->prettyTypeName() << ", got " + nodep->v3error(side << " expects a " << lhsClassRefp->prettyTypeName() << ", got " << rhsDtypep->prettyTypeName()); } } diff --git a/src/V3WidthCommit.h b/src/V3WidthCommit.h index 34cc4c689..135b559a6 100644 --- a/src/V3WidthCommit.h +++ b/src/V3WidthCommit.h @@ -110,10 +110,10 @@ private: AstBasicDType* const newp = nodep->findInsertSameDType(bdtypep); if (newp != bdtypep && debug() >= 9) { UINFO(9, "dtype replacement "); - nodep->dumpSmall(cout); - cout << " ----> "; - newp->dumpSmall(cout); - cout << endl; + nodep->dumpSmall(std::cout); + std::cout << " ----> "; + newp->dumpSmall(std::cout); + std::cout << std::endl; } return newp; } @@ -190,7 +190,6 @@ private: void visit(AstNodeUOrStructDType* nodep) override { if (nodep->user1SetOnce()) return; // Process once visitIterateNodeDType(nodep); - nodep->clearCache(); } void visit(AstParamTypeDType* nodep) override { if (nodep->user1SetOnce()) return; // Process once @@ -253,8 +252,9 @@ public: // Were changing widthMin's, so the table is now somewhat trashed nodep->typeTablep()->clearCache(); iterate(nodep); - // Don't want to repairCache, as all needed nodes have been added back in - // a repair would prevent dead nodes from being detected + // Don't want to AstTypeTable::repairCache, as all needed nodes + // have been added back in; a repair would prevent dead nodes from + // being detected } ~WidthCommitVisitor() override = default; }; diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp index c6308416b..f12893f40 100644 --- a/src/V3WidthSel.cpp +++ b/src/V3WidthSel.cpp @@ -348,8 +348,8 @@ private: UINFO(6, "SELEXTRACT " << nodep << endl); // if (debug() >= 9) nodep->dumpTree("- SELEX0: "); // Below 2 lines may change nodep->widthp() - V3Const::constifyParamsEdit(nodep->leftp()); // May relink pointed to node - V3Const::constifyParamsEdit(nodep->rightp()); // May relink pointed to node + V3Const::constifyParamsNoWarnEdit(nodep->leftp()); // May relink pointed to node + V3Const::constifyParamsNoWarnEdit(nodep->rightp()); // May relink pointed to node // if (debug() >= 9) nodep->dumpTree("- SELEX3: "); AstNodeExpr* const fromp = nodep->fromp()->unlinkFrBack(); const FromData fromdata = fromDataForArray(nodep, fromp); diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 9aeb177e1..c1654b524 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -49,6 +49,7 @@ #include "V3Expand.h" #include "V3File.h" #include "V3Force.h" +#include "V3Fork.h" #include "V3Gate.h" #include "V3Global.h" #include "V3Graph.h" @@ -221,6 +222,10 @@ static void process() { V3Inst::dearrayAll(v3Global.rootp()); V3LinkDot::linkDotArrayed(v3Global.rootp()); + // Create dedicated tasks for fork..join_any / fork_join_none processes + if (V3Fork::makeTasks(v3Global.rootp())) + V3LinkDot::linkDotPrimary(v3Global.rootp()); // Link newly created tasks + // Task inlining & pushing BEGINs names to variables/cells // Begin processing must be after Param, before module inlining V3Begin::debeginAll(v3Global.rootp()); // Flatten cell names, before inliner diff --git a/src/VlcBucket.h b/src/VlcBucket.h index 5fa253af0..cca198bde 100644 --- a/src/VlcBucket.h +++ b/src/VlcBucket.h @@ -115,11 +115,11 @@ public: } void dump() const { - cout << "# "; - for (uint64_t i = 0; i < m_dataSize; i++) { - if (hits(i)) cout << "," << i; + std::cout << "# "; + for (uint64_t i = 0; i < m_dataSize; ++i) { + if (hits(i)) std::cout << "," << i; } - cout << endl; + std::cout << std::endl; } }; diff --git a/src/VlcMain.cpp b/src/VlcMain.cpp index f6352cb03..b26753c62 100644 --- a/src/VlcMain.cpp +++ b/src/VlcMain.cpp @@ -16,8 +16,8 @@ // clang-format off #include "config_build.h" -#ifndef HAVE_CONFIG_BUILD -# error "Something failed during ./configure as config_build.h is incomplete. Perhaps you used autoreconf, don't." +#ifndef HAVE_CONFIG_PACKAGE +# error "Something failed during ./configure as config_package.h is incomplete. Perhaps you used autoreconf, don't." #endif // clang-format on @@ -48,7 +48,7 @@ static int debug() { return V3Error::debugDefault(); } void VlcOptions::addReadFile(const string& filename) { m_readFiles.insert(filename); } string VlcOptions::version() { - string ver = DTVERSION; + string ver = PACKAGE_STRING; ver += " rev " + cvtToStr(DTVERSION_rev); return ver; } @@ -98,18 +98,18 @@ void VlcOptions::parseOptsList(int argc, char** argv) { } void VlcOptions::showVersion(bool verbose) { - cout << version(); - cout << endl; + std::cout << version(); + std::cout << endl; if (!verbose) return; - cout << endl; - cout << "Copyright 2003-2023 by Wilson Snyder. Verilator is free software; you can\n"; - cout << "redistribute it and/or modify the Verilator internals under the terms of\n"; - cout << "either the GNU Lesser General Public License Version 3 or the Perl Artistic\n"; - cout << "License Version 2.0.\n"; + std::cout << endl; + std::cout << "Copyright 2003-2023 by Wilson Snyder. Verilator is free software; you can\n"; + std::cout << "redistribute it and/or modify the Verilator internals under the terms of\n"; + std::cout << "either the GNU Lesser General Public License Version 3 or the Perl Artistic\n"; + std::cout << "License Version 2.0.\n"; - cout << endl; - cout << "See https://verilator.org for documentation\n"; + std::cout << endl; + std::cout << "See https://verilator.org for documentation\n"; } //###################################################################### diff --git a/src/VlcPoint.h b/src/VlcPoint.h index f2ed5b287..81578f9b1 100644 --- a/src/VlcPoint.h +++ b/src/VlcPoint.h @@ -129,10 +129,10 @@ public: // METHODS void dump() { UINFO(2, "dumpPoints...\n"); - VlcPoint::dumpHeader(cout); + VlcPoint::dumpHeader(std::cout); for (const auto& i : *this) { const VlcPoint& point = pointNumber(i.second); - point.dump(cout); + point.dump(std::cout); } } VlcPoint& pointNumber(uint64_t num) { return m_points[num]; } diff --git a/src/VlcTest.h b/src/VlcTest.h index 3f960b9fb..0a60758ba 100644 --- a/src/VlcTest.h +++ b/src/VlcTest.h @@ -63,20 +63,21 @@ public: // METHODS static void dumpHeader() { - cout << "Tests:\n"; - // cout<<" Testrun, Computrons,"; // Currently not loaded - cout << " Covered, Rank, RankPts, Filename\n"; + std::cout << "Tests:\n"; + // std::cout<<" Testrun, Computrons,"; // Currently not loaded + std::cout << " Covered, Rank, RankPts, Filename\n"; } void dump(bool bucketsToo) { if (testrun() || computrons() != 0.0) { // currently unused // LCOV_EXCL_LINE - cout << " " << std::setw(8) << std::setfill('0') << testrun() // LCOV_EXCL_LINE - << ", " << std::setw(7) << std::setfill(' ') << computrons() // LCOV_EXCL_LINE - << ","; // LCOV_EXCL_LINE + std::cout << " " << std::setw(8) << std::setfill('0') << testrun() // LCOV_EXCL_LINE + << ", " << std::setw(7) << std::setfill(' ') + << computrons() // LCOV_EXCL_LINE + << ","; // LCOV_EXCL_LINE } - cout << " " << std::setw(7) << std::setfill(' ') << bucketsCovered(); - cout << ", " << std::setw(7) << std::setfill(' ') << rank(); - cout << ", " << std::setw(7) << std::setfill(' ') << rankPoints(); - cout << ", \"" << name() << "\"\n"; + std::cout << " " << std::setw(7) << std::setfill(' ') << bucketsCovered(); + std::cout << ", " << std::setw(7) << std::setfill(' ') << rank(); + std::cout << ", " << std::setw(7) << std::setfill(' ') << rankPoints(); + std::cout << ", \"" << name() << "\"\n"; if (bucketsToo) m_buckets.dump(); } }; diff --git a/src/VlcTop.cpp b/src/VlcTop.cpp index db60851b0..bf5038450 100644 --- a/src/VlcTop.cpp +++ b/src/VlcTop.cpp @@ -249,8 +249,8 @@ void VlcTop::annotateCalcNeeded() { } } const float pct = totCases ? (100 * totOk / totCases) : 0; - cout << "Total coverage (" << totOk << "/" << totCases << ") "; - cout << std::fixed << std::setw(3) << std::setprecision(2) << pct << "%\n"; + std::cout << "Total coverage (" << totOk << "/" << totCases << ") "; + std::cout << std::fixed << std::setw(3) << std::setprecision(2) << pct << "%\n"; if (totOk != totCases) cout << "See lines with '%00' in " << opt.annotateOut() << '\n'; } diff --git a/src/astgen b/src/astgen index e567b4c21..a7f12ef14 100755 --- a/src/astgen +++ b/src/astgen @@ -948,8 +948,8 @@ def write_ast_macros(filename): if not op: continue name, monad, kind = op - retrieve = ("VN_AS(op{n}p(), {kind})" if kind != "Node" else - "op{n}p()").format(n=n, kind=kind) + retrieve = ("VN_DBG_AS(op{n}p(), {kind})" if kind != "Node" + else "op{n}p()").format(n=n, kind=kind) if monad == "List": emitBlock('''\ Ast{kind}* {name}() const VL_MT_STABLE {{ return {retrieve}; }} diff --git a/src/config_build.h.in b/src/config_build.h similarity index 73% rename from src/config_build.h.in rename to src/config_build.h index 34cb81c45..f4204016c 100644 --- a/src/config_build.h.in +++ b/src/config_build.h @@ -19,12 +19,7 @@ //********************************************************************** //**** Version and host name -// Autoconf substitutes this with the strings from AC_INIT. -#define PACKAGE_STRING "" - -#define PACKAGE_VERSION_NUMBER_STRING "0.000" - -#define DTVERSION PACKAGE_STRING +#include "config_package.h" //********************************************************************** //**** Functions @@ -60,35 +55,20 @@ //********************************************************************** //**** Compile options -#include -#include -#include #include +#include #include -#include #include +#include + +#include // Avoid needing std:: prefixes on some very common items using string = std::string; using std::cout; using std::endl; -//********************************************************************** -//**** Configure-discovered library options - -// Define if struct stat has st_mtim.tv_nsec (from configure) -#undef HAVE_STAT_NSEC -// Define if SystemC found -// - If defined, the default search path has it, so support is always enabled. -// - If undef, not system-wide, user can set SYSTEMC_INCLUDE. -#undef HAVE_SYSTEMC -#undef HAVE_COROUTINES - //********************************************************************** //**** OS and compiler specifics #include "verilatedos.h" - -//********************************************************************** -//**** This file sometimes gets truncated, so check in consumers -#define HAVE_CONFIG_BUILD diff --git a/src/config_package.h.in b/src/config_package.h.in new file mode 100644 index 000000000..25ccf8816 --- /dev/null +++ b/src/config_package.h.in @@ -0,0 +1,38 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- + +// DESCRIPTION: Verilator: Configure source; system configuration +// +// This file is part of Verilator. +// +// Code available from: https://verilator.org +// +// Copyright 2003-2023 by Wilson Snyder. This program is free software; +// you can redistribute it and/or modify it under the terms of either +// the GNU Lesser General Public License Version 3 or +// the Perl Artistic License Version 2.0. +// +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + + +// Autoconf substitutes this with the strings from AC_INIT. +#define PACKAGE_STRING "" +#define PACKAGE_VERSION_NUMBER_STRING "0.000" +// Otherwise Autoheader generates it (with all the same macros and more) + +//********************************************************************** +//**** Configure-discovered library options + +// Define if struct stat has st_mtim.tv_nsec (from configure) +#undef HAVE_STAT_NSEC + +// Define if SystemC found +// - If defined, the default search path has it, so support is always enabled. +// - If undef, not system-wide, user can set SYSTEMC_INCLUDE. +#undef HAVE_SYSTEMC + +// Define if coroutines are supported on this platform +#undef HAVE_COROUTINES + +//********************************************************************** +//**** This file sometimes gets truncated, so check in consumers +#define HAVE_CONFIG_PACKAGE diff --git a/src/verilog.y b/src/verilog.y index c7d17f3fd..08cd48cdc 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -2251,7 +2251,7 @@ tf_variable_identifier: // IEEE: part of list_of_tf_variable_ide id variable_dimensionListE sigAttrListE exprEqE { $$ = VARDONEA($1, *$1, $2, $3); if ($4) AstNode::addNext( - $$, new AstAssign{$4->fileline(), new AstVarRef{$1, *$1, VAccess::WRITE}, $4}); } + $$, new AstAssign{$4->fileline(), new AstParseRef{$1, VParseRefExp::PX_TEXT, *$1}, $4}); } ; variable_declExpr: // IEEE: part of variable_decl_assignment - rhs of expr @@ -2753,12 +2753,14 @@ genItemBegin: // IEEE: part of generate_block { $$ = new AstBegin{$1, *$1, $4, true, false}; GRAMMARP->endLabel($6, *$1, $6); } | id yP_COLON__BEGIN yBEGIN yEND endLabelE - { $$ = nullptr; GRAMMARP->endLabel($5, *$1, $5); } + { $$ = new AstBegin{$1, *$1, nullptr, true, false}; + GRAMMARP->endLabel($5, *$1, $5); } | yBEGIN ':' idAny ~c~genItemList yEND endLabelE { $$ = new AstBegin{$3, *$3, $4, true, false}; GRAMMARP->endLabel($6, *$3, $6); } | yBEGIN ':' idAny yEND endLabelE - { $$ = nullptr; GRAMMARP->endLabel($5, *$3, $5); } + { $$ = new AstBegin{$3, *$3, nullptr, true, false}; + GRAMMARP->endLabel($5, *$3, $5); } ; c_genItemBegin: // IEEE: part of generate_block (for checkers) @@ -2993,7 +2995,7 @@ netSig: // IEEE: net_decl_assignment - one element from { $$ = VARDONEA($1, *$1, nullptr, $2); } | netId sigAttrListE '=' expr { $$ = VARDONEA($1, *$1, nullptr, $2); - auto* const assignp = new AstAssignW{$3, new AstVarRef{$1, *$1, VAccess::WRITE}, $4}; + auto* const assignp = new AstAssignW{$3, new AstParseRef{$1, VParseRefExp::PX_TEXT, *$1}, $4}; if (GRAMMARP->m_netStrengthp) assignp->strengthSpecp(GRAMMARP->m_netStrengthp->cloneTree(false)); AstNode::addNext($$, assignp); } | netId variable_dimensionList sigAttrListE @@ -3910,14 +3912,14 @@ for_initializationItem: // IEEE: variable_assignment + for_varia AstVar* const varp = VARDONEA($2, *$2, nullptr, nullptr); varp->lifetime(VLifetime::AUTOMATIC); $$ = varp; - $$->addNext(new AstAssign{$3, new AstVarRef{$2, *$2, VAccess::WRITE}, $4}); } + $$->addNext(new AstAssign{$3, new AstParseRef{$2, VParseRefExp::PX_TEXT, *$2}, $4}); } // // IEEE-2012: | yVAR data_type idAny/*new*/ '=' expr { VARRESET_NONLIST(VAR); VARDTYPE($2); AstVar* const varp = VARDONEA($3, *$3, nullptr, nullptr); varp->lifetime(VLifetime::AUTOMATIC); $$ = varp; - $$->addNext(new AstAssign{$4, new AstVarRef{$3, *$3, VAccess::WRITE}, $5}); } + $$->addNext(new AstAssign{$4, new AstParseRef{$3, VParseRefExp::PX_TEXT, *$3}, $5}); } // // IEEE: variable_assignment // // UNSUP variable_lvalue below | varRefBase '=' expr { $$ = new AstAssign{$2, $1, $3}; } @@ -5186,7 +5188,7 @@ let_port_list: // IEEE: let_port_list ; let_port_item: // IEEE: let_port_Item - // // IEEE: Expanded let_formal_type + // // IEEE: Expanded let_formal_type yUNTYPED idAny/*formal_port_identifier*/ variable_dimensionListE exprEqE { $$ = nullptr; BBUNSUP($1, "Unsupported: let untyped ports"); } | data_type id/*formal_port_identifier*/ variable_dimensionListE exprEqE @@ -5612,8 +5614,8 @@ idArrayedForeach: // IEEE: id + select (under foreach expression) ; // VarRef without any dots or vectorizaion -varRefBase: - id { $$ = new AstVarRef{$1, *$1, VAccess::READ}; } +varRefBase: + id { $$ = new AstParseRef{$1, VParseRefExp::PX_TEXT, *$1}; } ; // ParseRef @@ -5861,6 +5863,7 @@ property_declarationFront: // IEEE: part of property_declaration property_port_listE: // IEEE: [ ( [ property_port_list ] ) ] /* empty */ { $$ = nullptr; } + | '(' ')' { $$ = nullptr; } | '(' property_port_list ')' { $$ = $2; } ; @@ -7227,7 +7230,7 @@ vltOffFront: { const char *codemsg = (*$3).c_str(); if (V3ErrorCode::unusedMsg(codemsg)) {$$ = V3ErrorCode::I_UNUSED; } else {$$ = V3ErrorCode{codemsg}; } - if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown Error Code: " << *$3); } } + if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown error code: " << *$3); } } ; vltOnFront: @@ -7239,7 +7242,7 @@ vltOnFront: { const char *codemsg = (*$3).c_str(); if (V3ErrorCode::unusedMsg(codemsg)) {$$ = V3ErrorCode::I_UNUSED; } else {$$ = V3ErrorCode{codemsg}; } - if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown Error Code: " << *$3); } } + if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown error code: " << *$3); } } ; vltDModuleE: diff --git a/test_regress/.gdbinit b/test_regress/.gdbinit index e960ad760..8b63c91ae 100644 --- a/test_regress/.gdbinit +++ b/test_regress/.gdbinit @@ -1 +1 @@ -source ~/SandBox/homecvs/v4/verilator/src/.gdbinit +source ../src/.gdbinit diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 283aaa41e..76f394231 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -2229,7 +2229,7 @@ sub files_identical { && !/\+\+\+ \/tmp\// # t_difftree.pl } @l1; @l1 = map { - s/(Internal Error: [^\n]+\.(cpp|h)):[0-9]+:/$1:#:/; + while (s/(Internal Error: [^\n]+\.(cpp|h)):[0-9]+/$1:#/g) {} s/^-V\{t[0-9]+,[0-9]+\}/-V{t#,#}/; # --vlt vs --vltmt run differences $_; } @l1; diff --git a/test_regress/t/t_assert_imm_nz_bad.out b/test_regress/t/t_assert_imm_nz_bad.out new file mode 100644 index 000000000..2f81116f0 --- /dev/null +++ b/test_regress/t/t_assert_imm_nz_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_assert_imm_nz_bad.v:13:26: Deferred assertions must use '#0' (IEEE 1800-2017 16.4) + 13 | labeled_imas: assert #1 (clk); + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_assert_imm_nz_bad.pl b/test_regress/t/t_assert_imm_nz_bad.pl new file mode 100755 index 000000000..eebb17b11 --- /dev/null +++ b/test_regress/t/t_assert_imm_nz_bad.pl @@ -0,0 +1,20 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +compile( + expect_filename => $Self->{golden_filename}, + verilator_flags2 => ['--assert'], + fails => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_assert_imm_nz_bad.v b/test_regress/t/t_assert_imm_nz_bad.v new file mode 100644 index 000000000..ce0867766 --- /dev/null +++ b/test_regress/t/t_assert_imm_nz_bad.v @@ -0,0 +1,15 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + clk + ); + + input clk; + + labeled_imas: assert #1 (clk); // BAD: #1 + +endmodule diff --git a/test_regress/t/t_assert_named_property.v b/test_regress/t/t_assert_named_property.v index 36e622825..7fed4f620 100644 --- a/test_regress/t/t_assert_named_property.v +++ b/test_regress/t/t_assert_named_property.v @@ -60,12 +60,19 @@ module t (/*AUTOARG*/ logic out = 1; property prop_a; - @(posedge clk) disable iff (cyc <= 10) out; - endproperty + @(posedge clk) disable iff (cyc <= 1) out; + endproperty : prop_a + + property prop_b(); + @(posedge clk) disable iff (cyc <= 1) out; + endproperty : prop_b assert property(disable iff (cyc < 5) check_if_gt_5(cyc + 1)); assert property(@(posedge clk) pass_assertion(cyc)); assert property (prop_a) else $error($sformatf("property check failed :assert: (False)")); + assert property (prop_a()) else $error($sformatf("property check failed :assert: (False)")); + assert property (prop_b) else $error($sformatf("property check failed :assert: (False)")); + assert property (prop_b()) else $error($sformatf("property check failed :assert: (False)")); always @(posedge clk) begin if (expected_fails == 2) begin diff --git a/test_regress/t/t_assert_procedural_clk.out b/test_regress/t/t_assert_procedural_clk.out index 8d930ad07..0cd9304b0 100644 --- a/test_regress/t/t_assert_procedural_clk.out +++ b/test_regress/t/t_assert_procedural_clk.out @@ -1,8 +1,8 @@ -%Error: t/t_assert_procedural_clk.v:21:13: Unsupported: Procedural concurent assertion with clocking event inside always (IEEE 1800-2917 16.14.6) +%Error: t/t_assert_procedural_clk.v:21:13: Unsupported: Procedural concurrent assertion with clocking event inside always (IEEE 1800-2917 16.14.6) : ... In instance t 21 | assume property (@(posedge clk) cyc == 9); | ^~~~~~ -%Error: t/t_assert_procedural_clk.v:22:13: Unsupported: Procedural concurent assertion with clocking event inside always (IEEE 1800-2917 16.14.6) +%Error: t/t_assert_procedural_clk.v:22:13: Unsupported: Procedural concurrent assertion with clocking event inside always (IEEE 1800-2917 16.14.6) : ... In instance t 22 | assume property (@(negedge clk) cyc == 9); | ^~~~~~ diff --git a/test_regress/t/t_assoc.v b/test_regress/t/t_assoc.v index 9e20a7626..4f8049dcd 100644 --- a/test_regress/t/t_assoc.v +++ b/test_regress/t/t_assoc.v @@ -23,7 +23,8 @@ module t (/*AUTOARG*/ begin // Type typedef bit [3:0] nibble_t; - string a [nibble_t]; + typedef string dict_t [nibble_t]; + dict_t a; string b [nibble_t]; nibble_t k; string v; @@ -101,8 +102,11 @@ module t (/*AUTOARG*/ begin // Wide-wides - need special array container classes, ick. logic [91:2] a [ logic [65:1] ]; + int b [ bit [99:0] ]; a[~65'hfe] = ~ 90'hfee; `checkh(a[~65'hfe], ~ 90'hfee); + b[100'b1] = 1; + `checkh(b[100'b1], 1); end begin diff --git a/test_regress/t/t_assoc_method.v b/test_regress/t/t_assoc_method.v index 0bb9f707c..5d923470f 100644 --- a/test_regress/t/t_assoc_method.v +++ b/test_regress/t/t_assoc_method.v @@ -9,11 +9,14 @@ `define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); module t (/*AUTOARG*/); + typedef struct { int x, y; } point; initial begin int q[int]; int qe[int]; // Empty int qv[$]; // Value returns int qi[$]; // Index returns + point points_q[int]; + point points_qv[$]; int i; string v; @@ -37,6 +40,16 @@ module t (/*AUTOARG*/); qi = qe.unique_index; v = $sformatf("%p", qi); `checks(v, "'{}"); + points_q[0] = point'{1, 2}; + points_q[1] = point'{2, 4}; + points_q[5] = point'{1, 4}; + + points_qv = points_q.unique(p) with (p.x); + `checkh(points_qv.size, 2); + qi = points_q.unique_index(p) with (p.x + p.y); + qi.sort; + v = $sformatf("%p", qi); `checks(v, "'{'h0, 'h1, 'h5} "); + // These require an with clause or are illegal // TODO add a lint check that with clause is provided qv = q.find with (item == 2); @@ -74,13 +87,22 @@ module t (/*AUTOARG*/); qv = q.min; v = $sformatf("%p", qv); `checks(v, "'{'h1} "); + points_qv = points_q.min(p) with (p.x + p.y); + if (points_qv[0].x != 1 || points_qv[0].y != 2) $stop; + qv = q.max; v = $sformatf("%p", qv); `checks(v, "'{'h4} "); + points_qv = points_q.max(p) with (p.x + p.y); + if (points_qv[0].x != 2 || points_qv[0].y != 4) $stop; qv = qe.min; v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = qe.min(x) with (x + 1); + v = $sformatf("%p", qv); `checks(v, "'{}"); qv = qe.max; v = $sformatf("%p", qv); `checks(v, "'{}"); + qv = qe.max(x) with (x + 1); + v = $sformatf("%p", qv); `checks(v, "'{}"); // Reduction methods diff --git a/test_regress/t/t_assoc_wildcard.v b/test_regress/t/t_assoc_wildcard.v index 2d4e5c782..28fa62037 100644 --- a/test_regress/t/t_assoc_wildcard.v +++ b/test_regress/t/t_assoc_wildcard.v @@ -22,10 +22,15 @@ module t (/*AUTOARG*/ cyc <= cyc + 1; begin // Wildcard + typedef string dict_t [*]; string a [*] = '{default: "nope", "BBBBB": "fooing", 23'h434343: "baring"}; + dict_t b = '{default: "nope", "BBBBB": "fooing", 23'h434343: "baring"}; int k; string v; + v = b["CCC"]; `checks(v, "baring"); + v = b["BBBBB"]; `checks(v, "fooing"); + v = a["CCC"]; `checks(v, "baring"); v = a["BBBBB"]; `checks(v, "fooing"); diff --git a/test_regress/t/t_case_duplicated_if.pl b/test_regress/t/t_case_duplicated_if.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_case_duplicated_if.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_case_duplicated_if.v b/test_regress/t/t_case_duplicated_if.v new file mode 100644 index 000000000..822b2f884 --- /dev/null +++ b/test_regress/t/t_case_duplicated_if.v @@ -0,0 +1,57 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// bug3806 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + reg [65:0] idx /*verilator public*/; initial idx = 1; + + wire unlikely = idx > 200; + + typedef enum logic {UP, DOWN} dir_t; + + dir_t direction; + + always_comb direction = idx % 2 == 0 ? UP : DOWN; + + int ups; // Make computable + + always @(posedge clk) begin + if (idx > 100) begin +`ifdef TEST_VERBOSE + $write("ups = %0d\n", ups); +`endif + if (ups != 50049) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + + if (direction == UP) + ++ups; + else if (direction == UP) + ++ups; + else + ups += 1000; + + case (direction) + DOWN: idx = idx+3; + UP: idx = idx-1; + default: begin + // This if just gets rid of branch pred on default^ + if (unlikely == '1) begin + $write("never\n"); + end + end + endcase + end + +endmodule diff --git a/test_regress/t/t_cast_size_bad.out b/test_regress/t/t_cast_size_bad.out new file mode 100644 index 000000000..498099b69 --- /dev/null +++ b/test_regress/t/t_cast_size_bad.out @@ -0,0 +1,11 @@ +%Error: t/t_cast_size_bad.v:14:15: Size-changing cast to zero or negative size + : ... In instance t + 14 | b = (-1)'(a); + | ^ +%Warning-WIDTHEXPAND: t/t_cast_size_bad.v:14:9: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's SEL generates 1 bits. + : ... In instance t + 14 | b = (-1)'(a); + | ^ + ... For warning description see https://verilator.org/warn/WIDTHEXPAND?v=latest + ... Use "/* verilator lint_off WIDTHEXPAND */" and lint_on around source to disable this message. +%Error: Exiting due to diff --git a/test_regress/t/t_cast_size_bad.pl b/test_regress/t/t_cast_size_bad.pl new file mode 100755 index 000000000..9c9fb65a0 --- /dev/null +++ b/test_regress/t/t_cast_size_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2010 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_cast_size_bad.v b/test_regress/t/t_cast_size_bad.v new file mode 100644 index 000000000..3cf88e1da --- /dev/null +++ b/test_regress/t/t_cast_size_bad.v @@ -0,0 +1,17 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + + int a; + reg [3:0] b; + + initial begin + a = 1; + b = (-1)'(a); // Bad + end + +endmodule diff --git a/test_regress/t/t_class_assign_bad.out b/test_regress/t/t_class_assign_bad.out index 38ab6fe11..151bc48a8 100644 --- a/test_regress/t/t_class_assign_bad.out +++ b/test_regress/t/t_class_assign_bad.out @@ -1,33 +1,37 @@ -%Error: t/t_class_assign_bad.v:25:9: Assign RHS expects a CLASSREFDTYPE 'Cls', got BASICDTYPE 'logic' +%Error: t/t_class_assign_bad.v:28:9: Assign RHS expects a CLASSREFDTYPE 'Cls', got BASICDTYPE 'logic' : ... In instance t - 25 | c = 0; + 28 | c = 0; | ^ -%Error: t/t_class_assign_bad.v:26:9: Assign RHS expects a CLASSREFDTYPE 'Cls', got BASICDTYPE 'logic' +%Error: t/t_class_assign_bad.v:29:9: Assign RHS expects a CLASSREFDTYPE 'Cls', got BASICDTYPE 'logic' : ... In instance t - 26 | c = 1; + 29 | c = 1; | ^ -%Error: t/t_class_assign_bad.v:27:9: Assign RHS expects a CLASSREFDTYPE 'Cls', got CLASSREFDTYPE 'Cls2' +%Error: t/t_class_assign_bad.v:30:9: Assign RHS expects a CLASSREFDTYPE 'Cls', got CLASSREFDTYPE 'Cls2' : ... In instance t - 27 | c = c2; + 30 | c = c2; | ^ -%Error: t/t_class_assign_bad.v:28:13: Assign RHS expects a CLASSREFDTYPE 'ClsExt', got CLASSREFDTYPE 'Cls' +%Error: t/t_class_assign_bad.v:31:13: Assign RHS expects a CLASSREFDTYPE 'ClsExt', got CLASSREFDTYPE 'Cls' : ... In instance t - 28 | c_ext = c; + 31 | c_ext = c; | ^ -%Error: t/t_class_assign_bad.v:30:7: Function Argument expects a CLASSREFDTYPE 'Cls', got BASICDTYPE 'logic' +%Error: t/t_class_assign_bad.v:32:11: Assign RHS expects a CLASSREFDTYPE 'Cls2', got CLASSREFDTYPE 'Cls' + : ... In instance t + 32 | ct2 = c; + | ^ +%Error: t/t_class_assign_bad.v:34:7: Function Argument expects a CLASSREFDTYPE 'Cls', got BASICDTYPE 'logic' : ... In instance t - 30 | t(0); + 34 | t(0); | ^ -%Error: t/t_class_assign_bad.v:31:7: Function Argument expects a CLASSREFDTYPE 'Cls', got BASICDTYPE 'logic' +%Error: t/t_class_assign_bad.v:35:7: Function Argument expects a CLASSREFDTYPE 'Cls', got BASICDTYPE 'logic' : ... In instance t - 31 | t(1); + 35 | t(1); | ^ -%Error: t/t_class_assign_bad.v:32:7: Function Argument expects a CLASSREFDTYPE 'Cls', got CLASSREFDTYPE 'Cls2' +%Error: t/t_class_assign_bad.v:36:7: Function Argument expects a CLASSREFDTYPE 'Cls', got CLASSREFDTYPE 'Cls2' : ... In instance t - 32 | t(c2); + 36 | t(c2); | ^ -%Error: t/t_class_assign_bad.v:33:7: Function Argument expects a CLASSREFDTYPE 'ClsExt', got CLASSREFDTYPE 'Cls' +%Error: t/t_class_assign_bad.v:37:7: Function Argument expects a CLASSREFDTYPE 'ClsExt', got CLASSREFDTYPE 'Cls' : ... In instance t - 33 | f(c); + 37 | f(c); | ^ %Error: Exiting due to diff --git a/test_regress/t/t_class_assign_bad.v b/test_regress/t/t_class_assign_bad.v index 46045ee5c..af55db08f 100644 --- a/test_regress/t/t_class_assign_bad.v +++ b/test_regress/t/t_class_assign_bad.v @@ -13,9 +13,12 @@ endclass class ClsExt extends Cls; endclass +typedef Cls2 cls2_t; + module t (/*AUTOARG*/); Cls c; Cls2 c2; + cls2_t ct2; ClsExt c_ext; task t(Cls c); endtask @@ -26,6 +29,7 @@ module t (/*AUTOARG*/); c = 1; c = c2; c_ext = c; + ct2 = c; t(0); t(1); diff --git a/test_regress/t/t_class_compare.v b/test_regress/t/t_class_compare.v index ee4826725..bcbb1842a 100644 --- a/test_regress/t/t_class_compare.v +++ b/test_regress/t/t_class_compare.v @@ -14,13 +14,22 @@ class Cls; int i; endclass +class ExtendCls extends Cls; +endclass + module t; initial begin Cls a = new; Cls b = new; + ExtendCls ext = new; `check_ne(a, b) + `check_ne(a, ext) + `check_ne(ext, a) a = b; `check_eq(a, b) + a = ext; + `check_eq(a, ext) + `check_eq(ext, a) $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_class_member_var_virt_bad.out b/test_regress/t/t_class_member_var_virt_bad.out new file mode 100644 index 000000000..21bee5fdf --- /dev/null +++ b/test_regress/t/t_class_member_var_virt_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_class_member_var_virt_bad.v:8:16: Syntax error: 'virtual' not allowed before var declaration + 8 | virtual int member; + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_member_var_virt_bad.pl b/test_regress/t/t_class_member_var_virt_bad.pl new file mode 100755 index 000000000..376c2d2ee --- /dev/null +++ b/test_regress/t/t_class_member_var_virt_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_member_var_virt_bad.v b/test_regress/t/t_class_member_var_virt_bad.v new file mode 100644 index 000000000..492a70785 --- /dev/null +++ b/test_regress/t/t_class_member_var_virt_bad.v @@ -0,0 +1,12 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Foo; + virtual int member; +endclass + +module t; +endmodule diff --git a/test_regress/t/t_class_method_struct.pl b/test_regress/t/t_class_method_struct.pl new file mode 100755 index 000000000..aabcde63e --- /dev/null +++ b/test_regress/t/t_class_method_struct.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_method_struct.v b/test_regress/t/t_class_method_struct.v new file mode 100644 index 000000000..5282df207 --- /dev/null +++ b/test_regress/t/t_class_method_struct.v @@ -0,0 +1,34 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +typedef struct packed { + int x; + int y; + int z; +} my_struct; + +class Cls; + function my_struct get_struct; + my_struct s; + s.x = 1; + s.y = 2; + s.z = 3; + return s; + endfunction +endclass : Cls + +module t (/*AUTOARG*/); + initial begin + Cls c = new; + my_struct s = c.get_struct; + if (s.x != 1) $stop; + if (s.y != 2) $stop; + if (s.z != 3) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_param.v b/test_regress/t/t_class_param.v index d0fc116f7..e16f409a6 100644 --- a/test_regress/t/t_class_param.v +++ b/test_regress/t/t_class_param.v @@ -120,6 +120,16 @@ class Getter2 #(int T=5); endfunction endclass +class ClsParamString #(string S="abcde"); + typedef ClsParamString#(S) this_type; + static this_type m_inst; + int x = 0; + string name = S; +endclass + +typedef ClsParamString#("abcde") cls_param_string_def_t; +typedef ClsParamString#("xyz") cls_param_string_not_def_t; + module t (/*AUTOARG*/); Cls c12; @@ -137,6 +147,8 @@ module t (/*AUTOARG*/); Getter1 getter1; Getter1 #(1) getter1_param_1; Getter2 getter2; + cls_param_string_def_t cps_def; + cls_param_string_not_def_t cps_not_def; int arr [1:0] = '{1, 2}; initial begin c12 = new; @@ -217,6 +229,18 @@ module t (/*AUTOARG*/); if (Getter2#()::get_2() != 2) $stop; if (Getter2#(2)::get_2() != 2) $stop; + cls_param_string_def_t::m_inst = new; + cls_param_string_def_t::m_inst.x = 1; + cps_def = cls_param_string_def_t::m_inst; + if (cps_def.x != 1) $stop; + if (cps_def.name != "abcde") $stop; + + cls_param_string_not_def_t::m_inst = new; + cls_param_string_not_def_t::m_inst.x = 2; + cps_not_def = cls_param_string_not_def_t::m_inst; + if (cps_not_def.x != 2) $stop; + if (cps_not_def.name != "xyz") $stop; + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_class_param_typedef.v b/test_regress/t/t_class_param_typedef.v index 0218b205a..d9f9f73ce 100644 --- a/test_regress/t/t_class_param_typedef.v +++ b/test_regress/t/t_class_param_typedef.v @@ -33,14 +33,39 @@ class Cls2; typedef Bar#(Cls2) type_id; endclass +typedef int my_int; + +class ClsTypedefParam #(type T=my_int); + int x; +endclass + +class uvm_sequencer #(type REQ=int, RSP=REQ); + int x; + typedef uvm_sequencer #(REQ, RSP) this_type; +endclass + module t; initial begin Cls1::type_id bar1 = new; Cls2::type_id bar2 = new; + ClsTypedefParam #(int) cls_int = new; + ClsTypedefParam#() cls_def; + + uvm_sequencer #(int, int) uvm_seq1 = new; + uvm_sequencer #(int, int)::this_type uvm_seq2; + if (bar1.get_x() != 1) $stop; if (bar2.get_x() != 2) $stop; + cls_int.x = 1; + cls_def = cls_int; + if (cls_def.x != 1) $stop; + + uvm_seq1.x = 2; + uvm_seq2 = uvm_seq1; + if (uvm_seq2.x != 2) $stop; + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_class_static_member_sel.pl b/test_regress/t/t_class_static_member_sel.pl new file mode 100755 index 000000000..1aa73f80a --- /dev/null +++ b/test_regress/t/t_class_static_member_sel.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_static_member_sel.v b/test_regress/t/t_class_static_member_sel.v new file mode 100644 index 000000000..9e0b542c5 --- /dev/null +++ b/test_regress/t/t_class_static_member_sel.v @@ -0,0 +1,91 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Foo; + static int x = 1; +endclass + +class Bar; + Foo f; + function new; + f = new; + endfunction +endclass + +class Baz; + function static Bar get_bar; + Bar b = new; + return b; + endfunction +endclass + +class IntWrapper; + int x; +endclass + +class Cls; + static IntWrapper iw; + function new; + if (iw == null) iw = new; + endfunction +endclass + +class ExtendCls extends Cls; +endclass + +class Getter1; + function static int get_1; + return 1; + endfunction +endclass + +class uvm_root; + int x; + static uvm_root m_inst; + static function uvm_root get_inst(); + if (m_inst == null) m_inst = new; + return m_inst; + endfunction + function int get_7(); + return 7; + endfunction +endclass + +module t (/*AUTOARG*/ + ); + + initial begin + Foo foo = new; + Bar bar = new; + Baz baz = new; + ExtendCls ec = new; + Getter1 getter1 = new; + + if (foo.x != 1) $stop; + + foo.x = 2; + if (foo.x != 2) $stop; + + bar.f.x = 3; + if (bar.f.x != 3) $stop; + + baz.get_bar().f.x = 4; + if (baz.get_bar().f.x != 4) $stop; + + ec.iw.x = 5; + if (ec.iw.x != 5) $stop; + + if (getter1.get_1 != 1) $stop; + + uvm_root::get_inst().x = 6; + if (uvm_root::get_inst().x != 6) $stop; + + if (uvm_root::get_inst().get_7() != 7) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_super_new.v b/test_regress/t/t_class_super_new.v index 5cecc1ca6..58fe8bc3b 100644 --- a/test_regress/t/t_class_super_new.v +++ b/test_regress/t/t_class_super_new.v @@ -1,7 +1,7 @@ // DESCRIPTION: Verilator: Verilog Test module // // This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2022 by Antmicro Ltd. +// any use, without warranty, 2023 by Antmicro Ltd. // SPDX-License-Identifier: CC0-1.0 `define stop $stop @@ -39,6 +39,16 @@ class BarArg extends FooArg; endfunction endclass +class BarArgWithReturnInIf extends FooArg; + function new (int a); + super.new(a); + if (a < 10) begin + return; + end + this.x = 20; + endfunction +endclass + class BarExpr extends FooArg; function new (int a, string b); super.new(a + b.len()); @@ -58,6 +68,36 @@ class Bar2Args extends Foo2Args; endfunction endclass +class OptArgInNew; + int x; + function new (int y=1); + x = y; + endfunction +endclass + +class NoNew extends OptArgInNew; +endclass + +class NewWithoutSuper extends OptArgInNew; + function new; + endfunction +endclass + +class OptArgInNewParam #(parameter int P=1); + int x; + function new (int y=1); + x = y; + endfunction +endclass + +class NoNewParam#(parameter int R) extends OptArgInNewParam#(R); +endclass + +class NewWithoutSuperParam#(parameter int R) extends OptArgInNewParam#(); + function new; + endfunction +endclass + module t (/*AUTOARG*/ ); @@ -80,6 +120,11 @@ module t (/*AUTOARG*/ BarArg barArg; BarExpr barExpr; Bar2Args bar2Args; + NoNew noNew; + NewWithoutSuper newWithoutSuper; + NoNewParam#(2) noNewParam; + NewWithoutSuperParam#(1) newWithoutSuperParam; + BarArgWithReturnInIf barIf1, barIf10; initial begin bar = new; @@ -94,6 +139,18 @@ module t (/*AUTOARG*/ `checkh(barExpr.x, 16); bar2Args = new(2, 12); `checkh(bar2Args.x, 14); + noNew = new; + `checkh(noNew.x, 1); + newWithoutSuper = new; + `checkh(newWithoutSuper.x, 1); + noNewParam = new; + `checkh(noNewParam.x, 1); + newWithoutSuperParam = new; + `checkh(newWithoutSuperParam.x, 1); + barIf1 = new(1); + `checkh(barIf1.x, 1); + barIf10 = new(10); + `checkh(barIf10.x, 20); $write("*-* All Finished *-*\n"); $finish; diff --git a/test_regress/t/t_clocking_sched_timing_forkproc.out b/test_regress/t/t_clocking_sched_timing_forkproc.out new file mode 100755 index 000000000..8094d59d9 --- /dev/null +++ b/test_regress/t/t_clocking_sched_timing_forkproc.out @@ -0,0 +1,5 @@ +%Error: t/t_clocking_sched.v:11:9: Input/output/inout does not appear in port list: 'clk' + : ... In instance t + 11 | input clk; + | ^~~ +%Error: Exiting due to diff --git a/test_regress/t/t_clocking_sched_timing_forkproc.pl b/test_regress/t/t_clocking_sched_timing_forkproc.pl new file mode 100755 index 000000000..d1bb14c97 --- /dev/null +++ b/test_regress/t/t_clocking_sched_timing_forkproc.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +scenarios(linter => 1); + +top_filename("t/t_clocking_sched.v"); + +lint( + verilator_flags2 => ["--timing", "--ftaskify-all-forked"], + expect_filename => $Self->{golden_filename}, + fails => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_concat_link_bad.out b/test_regress/t/t_concat_link_bad.out index 5a1719518..ad22af64a 100644 --- a/test_regress/t/t_concat_link_bad.out +++ b/test_regress/t/t_concat_link_bad.out @@ -1,10 +1,10 @@ -%Error: t/t_concat_link_bad.v:13:20: Syntax Error: Not expecting REPLICATE under a DOT in dotted expression +%Error: t/t_concat_link_bad.v:13:20: Syntax error: Not expecting REPLICATE under a DOT in dotted expression 13 | assign bar_s = {foo_s, foo_s}.f1; | ^ -%Error: t/t_concat_link_bad.v:13:26: Syntax Error: Not expecting CONCAT under a REPLICATE in dotted expression +%Error: t/t_concat_link_bad.v:13:26: Syntax error: Not expecting CONCAT under a REPLICATE in dotted expression 13 | assign bar_s = {foo_s, foo_s}.f1; | ^ -%Error: t/t_concat_link_bad.v:13:20: Syntax Error: Not expecting CONST under a REPLICATE in dotted expression +%Error: t/t_concat_link_bad.v:13:20: Syntax error: Not expecting CONST under a REPLICATE in dotted expression 13 | assign bar_s = {foo_s, foo_s}.f1; | ^ %Warning-IMPLICIT: t/t_concat_link_bad.v:13:12: Signal definition not found, creating implicitly: 'bar_s' diff --git a/test_regress/t/t_concat_string.pl b/test_regress/t/t_concat_string.pl new file mode 100755 index 000000000..1aa73f80a --- /dev/null +++ b/test_regress/t/t_concat_string.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_concat_string.v b/test_regress/t/t_concat_string.v new file mode 100644 index 000000000..680dc8caa --- /dev/null +++ b/test_regress/t/t_concat_string.v @@ -0,0 +1,24 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +typedef enum {efgh} en; + +module t (/*AUTOARG*/); + initial begin + en e; + string s; + + s = {"a", "b"}; + if (s != "ab") $stop; + + e = efgh; + s = {"abcd", e.name(), "ijkl"}; + if (s != "abcdefghijkl") $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_dist_warn_coverage.pl b/test_regress/t/t_dist_warn_coverage.pl index bddd75ed5..2889553a5 100755 --- a/test_regress/t/t_dist_warn_coverage.pl +++ b/test_regress/t/t_dist_warn_coverage.pl @@ -26,6 +26,7 @@ foreach my $s ( 'Enum names without values only allowed on numeric types', # Hard to hit 'Enum ranges must be integral, per spec', # Hard to hit 'Return with return value isn\'t underneath a function', # Hard to hit, get other bad return messages + 'Syntax error: Range \':\', \'+:\' etc are not allowed in the instance ', # Instead get syntax error 'Syntax error parsing real: \'', # Instead can't lex the number 'Unsupported: Ranges ignored in port-lists', # Hard to hit 'dynamic new() not expected in this context (expected under an assign)', # Instead get syntax error @@ -40,12 +41,10 @@ foreach my $s ( 'Assigned pin is neither input nor output', 'Assignment pattern with no members', 'Attempted parameter setting of non-parameter: Param ', - 'Can\'t find typedef: ', 'Can\'t find varpin scope of ', 'Can\'t resolve module reference: \'', 'Cannot write preprocessor output: ', 'Circular logic when ordering code (non-cutable edge loop)', - 'Deferred assertions must use \'#0\' (IEEE 1800-2017 16.4)', 'Define or directive not defined: `', 'Exceeded limit of ', 'Extern declaration\'s scope is not a defined class', @@ -62,22 +61,16 @@ foreach my $s ( 'Modport not referenced as .', 'Modport not referenced from underneath an interface: ', 'Non-interface used as an interface: ', - 'Not marked as function return var', 'Parameter not found in sub-module: Param ', 'Parameter type pin value isn\'t a type: Param ', 'Parameter type variable isn\'t a type: Param ', 'Pattern replication value of 0 is not legal.', 'Signals inside functions/tasks cannot be marked forceable', - 'Size-changing cast to zero or negative size', 'Slice size cannot be zero.', 'Slices of arrays in assignments have different unpacked dimensions, ', 'String of ', 'Symbol matching ', - 'Syntax Error: Range \':\', \'+:\' etc are not allowed in the instance ', - 'Syntax error: \'virtual\' not allowed before var declaration', 'Unexpected connection to arrayed port', - 'Unhandled attribute type', - 'Unknown Error Code: ', 'Unknown `pragma', 'Unknown built-in event method ', 'Unsized numbers/parameters not allowed in streams.', diff --git a/test_regress/t/t_dpi_2exparg_bad.out b/test_regress/t/t_dpi_2exparg_bad.out new file mode 100644 index 000000000..47496c569 --- /dev/null +++ b/test_regress/t/t_dpi_2exparg_bad.out @@ -0,0 +1,18 @@ +%Warning-WIDTHEXPAND: t/t_dpi_2exparg_bad.v:19:56: Operator NOT expects 64 bits on the LHS, but LHS's VARREF 'i' generates 32 bits. + : ... In instance t.b + 19 | task dpix_twice(input int i, output [63:0] o); o = ~i; endtask + | ^ + ... For warning description see https://verilator.org/warn/WIDTHEXPAND?v=latest + ... Use "/* verilator lint_off WIDTHEXPAND */" and lint_on around source to disable this message. +%Warning-WIDTHTRUNC: t/t_dpi_2exparg_bad.v:12:53: Operator ASSIGN expects 3 bits on the Assign RHS, but Assign RHS's NOT generates 32 bits. + : ... In instance t.a + 12 | task dpix_twice(input int i, output [2:0] o); o = ~i; endtask + | ^ +%Error: t/t_dpi_2exparg_bad.v:19:9: Duplicate declaration of DPI function with different signature: 'dpix_twice' + 19 | task dpix_twice(input int i, output [63:0] o); o = ~i; endtask + | ^~~~~~~~~~ + : ... New signature: void dpix_twice (int, svLogicVecVal* /* logic[63:0] */ ) + t/t_dpi_2exparg_bad.v:12:9: ... Original signature: void dpix_twice (int, svLogicVecVal* /* logic[2:0] */ ) + 12 | task dpix_twice(input int i, output [2:0] o); o = ~i; endtask + | ^~~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_dpi_2exparg_bad.pl b/test_regress/t/t_dpi_2exparg_bad.pl new file mode 100755 index 000000000..59ba0d6c6 --- /dev/null +++ b/test_regress/t/t_dpi_2exparg_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_dpi_2exparg_bad.v b/test_regress/t/t_dpi_2exparg_bad.v new file mode 100644 index 000000000..cbc2f44b3 --- /dev/null +++ b/test_regress/t/t_dpi_2exparg_bad.v @@ -0,0 +1,30 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2023 by Wilson Snyder. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +module a; + import "DPI-C" task dpii_twice; // Legal + export "DPI-C" task dpix_twice; // Bad + task dpix_twice(input int i, output [2:0] o); o = ~i; endtask + initial dpii_twice(); +endmodule + +module b; + import "DPI-C" task dpii_twice; // Legal + export "DPI-C" task dpix_twice; // Bad + task dpix_twice(input int i, output [63:0] o); o = ~i; endtask + initial dpii_twice(); +endmodule + +module t; + a a(); + b b(); + + initial begin + $stop; + end +endmodule diff --git a/test_regress/t/t_dpi_accessors.cpp b/test_regress/t/t_dpi_accessors.cpp index cf13572d4..b5952071c 100644 --- a/test_regress/t/t_dpi_accessors.cpp +++ b/test_regress/t/t_dpi_accessors.cpp @@ -18,13 +18,6 @@ #include #include -using std::cout; -using std::dec; -using std::endl; -using std::hex; -using std::setfill; -using std::setw; - // Convenience function to check we didn't finish unexpectedly static void checkFinish(VerilatedContext* contextp, const char* msg) { if (contextp->gotFinish()) { @@ -37,7 +30,7 @@ static void checkFinish(VerilatedContext* contextp, const char* msg) { // mode. static void logReg(int clk, const char* desc, int val, const char* note) { #ifdef TEST_VERBOSE - cout << "clk = " << clk << ", " << desc << " = " << val << note << endl; + std::cout << "clk = " << clk << ", " << desc << " = " << val << note << std::endl; #endif } @@ -45,9 +38,9 @@ static void logReg(int clk, const char* desc, int val, const char* note) { // mode. static void logRegHex(int clk, const char* desc, int bitWidth, int val, const char* note) { #ifdef TEST_VERBOSE - cout << "clk = " << clk << ", " << desc << " = " << bitWidth << "\'h" << hex - << setw((bitWidth - 1) / 4 + 1) << setfill('0') << val << setfill(' ') << setw(0) << dec - << note << endl; + std::cout << "clk = " << clk << ", " << desc << " = " << bitWidth << "\'h" << std::hex + << std::setw((bitWidth - 1) / 4 + 1) << std::setfill('0') << val << std::setfill(' ') + << std::setw(0) << std::dec << note << std::endl; #endif } @@ -70,8 +63,8 @@ int main() { dut->eval(); #ifdef TEST_VERBOSE - cout << "Initial DPI values\n"; - cout << "==================\n"; + std::cout << "Initial DPI values\n"; + std::cout << "==================\n"; #endif int a = (int)a_read(); @@ -83,19 +76,19 @@ int main() { int f = (int)f_read(); #ifdef TEST_VERBOSE - cout << "Read a = " << a << endl; - cout << "Read b = 8'h" << hex << setw(2) << setfill('0') << b << setfill(' ') << setw(0) - << dec << endl; - cout << "Read mem32 = 8'h" << hex << setw(2) << setfill('0') << mem32 << setfill(' ') - << setw(0) << dec << endl; - cout << "Read c = " << c << endl; - cout << "Read d = 8'h" << hex << setw(2) << setfill('0') << d << setfill(' ') << setw(0) - << dec << endl; - cout << "Read e = 8'h" << hex << setw(2) << setfill('0') << e << setfill(' ') << setw(0) - << dec << endl; - cout << "Read f = 8'h" << hex << setw(2) << setfill('0') << f << setfill(' ') << setw(0) - << dec << endl; - cout << endl; + std::cout << "Read a = " << a << std::endl; + std::cout << "Read b = 8'h" << std::hex << std::setw(2) << std::setfill('0') << b + << std::setfill(' ') << std::setw(0) << std::dec << std::endl; + std::cout << "Read mem32 = 8'h" << std::hex << std::setw(2) << std::setfill('0') << mem32 + << std::setfill(' ') << std::setw(0) << std::dec << std::endl; + std::cout << "Read c = " << c << std::endl; + std::cout << "Read d = 8'h" << std::hex << std::setw(2) << std::setfill('0') << d + << std::setfill(' ') << std::setw(0) << std::dec << std::endl; + std::cout << "Read e = 8'h" << std::hex << std::setw(2) << std::setfill('0') << e + << std::setfill(' ') << std::setw(0) << std::dec << std::endl; + std::cout << "Read f = 8'h" << std::hex << std::setw(2) << std::setfill('0') << f + << std::setfill(' ') << std::setw(0) << std::dec << std::endl; + std::cout << std::endl; #endif checkResult((0 == a) && (0x00 == b) && (0x20 == mem32) && (1 == c) && (0xff == d) @@ -107,8 +100,8 @@ int main() { // Check we can read a scalar register. #ifdef TEST_VERBOSE - cout << "Test of scalar register reading\n"; - cout << "===============================\n"; + std::cout << "Test of scalar register reading\n"; + std::cout << "===============================\n"; #endif for (int i = 0; !contextp->gotFinish() && (i < 4); i++) { @@ -120,7 +113,7 @@ int main() { int a_after = (int)a_read(); logReg(dut->clk, "read a", a_after, " (after clk)"); #ifdef TEST_VERBOSE - cout << endl; + std::cout << std::endl; #endif // On a posedge, a should toggle, on a negedge it should stay the // same. @@ -133,8 +126,8 @@ int main() { // Check we can read a vector register. #ifdef TEST_VERBOSE - cout << "Test of vector register reading\n"; - cout << "===============================\n"; + std::cout << "Test of vector register reading\n"; + std::cout << "===============================\n"; #endif for (int i = 0; !contextp->gotFinish() && (i < 4); i++) { @@ -156,9 +149,9 @@ int main() { // Test we can read an array element #ifdef TEST_VERBOSE - cout << endl; - cout << "Test of array element reading\n"; - cout << "=============================\n"; + std::cout << std::endl; + std::cout << "Test of array element reading\n"; + std::cout << "=============================\n"; #endif for (int i = 0; !contextp->gotFinish() && (i < 4); i++) { @@ -180,9 +173,9 @@ int main() { // Check we can read a scalar wire #ifdef TEST_VERBOSE - cout << endl; - cout << "Test of scalar wire reading\n"; - cout << "===========================\n"; + std::cout << std::endl; + std::cout << "Test of scalar wire reading\n"; + std::cout << "===========================\n"; #endif for (int i = 0; !contextp->gotFinish() && (i < 4); i++) { @@ -209,9 +202,9 @@ int main() { // Check we can read a vector wire #ifdef TEST_VERBOSE - cout << endl; - cout << "Test of vector wire reading\n"; - cout << "===========================\n"; + std::cout << std::endl; + std::cout << "Test of vector wire reading\n"; + std::cout << "===========================\n"; #endif for (int i = 0; !contextp->gotFinish() && (i < 4); i++) { @@ -239,9 +232,9 @@ int main() { // Check we can write a scalar register #ifdef TEST_VERBOSE - cout << endl; - cout << "Test of scalar register writing\n"; - cout << "===============================\n"; + std::cout << std::endl; + std::cout << "Test of scalar register writing\n"; + std::cout << "===============================\n"; #endif for (int i = 0; !contextp->gotFinish() && (i < 4); i++) { @@ -268,9 +261,9 @@ int main() { // Check we can write a vector register #ifdef TEST_VERBOSE - cout << endl; - cout << "Test of vector register writing\n"; - cout << "===============================\n"; + std::cout << std::endl; + std::cout << "Test of vector register writing\n"; + std::cout << "===============================\n"; #endif for (int i = 0; !contextp->gotFinish() && (i < 4); i++) { @@ -297,9 +290,9 @@ int main() { // Test we can write an array element #ifdef TEST_VERBOSE - cout << endl; - cout << "Test of array element writing\n"; - cout << "=============================\n"; + std::cout << std::endl; + std::cout << "Test of array element writing\n"; + std::cout << "=============================\n"; #endif for (int i = 0; !contextp->gotFinish() && (i < 4); i++) { @@ -326,9 +319,9 @@ int main() { // Check we can read a vector register slice #ifdef TEST_VERBOSE - cout << endl; - cout << "Test of vector register slice reading\n"; - cout << "=====================================\n"; + std::cout << std::endl; + std::cout << "Test of vector register slice reading\n"; + std::cout << "=====================================\n"; #endif for (int i = 0; !contextp->gotFinish() && (i < 4); i++) { @@ -353,9 +346,9 @@ int main() { // Test we can read an array element slice #ifdef TEST_VERBOSE - cout << endl; - cout << "Test of array element slice reading\n"; - cout << "===================================\n"; + std::cout << std::endl; + std::cout << "Test of array element slice reading\n"; + std::cout << "===================================\n"; #endif for (int i = 0; !contextp->gotFinish() && (i < 4); i++) { @@ -382,9 +375,9 @@ int main() { // Check we can read a vector wire slice #ifdef TEST_VERBOSE - cout << endl; - cout << "Test of vector wire slice reading\n"; - cout << "=================================\n"; + std::cout << std::endl; + std::cout << "Test of vector wire slice reading\n"; + std::cout << "=================================\n"; #endif for (int i = 0; !contextp->gotFinish() && (i < 4); i++) { @@ -413,9 +406,9 @@ int main() { // Check we can write a vector register slice #ifdef TEST_VERBOSE - cout << endl; - cout << "Test of vector register slice writing\n"; - cout << "=====================================\n"; + std::cout << std::endl; + std::cout << "Test of vector register slice writing\n"; + std::cout << "=====================================\n"; #endif for (int i = 0; !contextp->gotFinish() && (i < 4); i++) { @@ -452,9 +445,9 @@ int main() { // Test we can write an array element slice #ifdef TEST_VERBOSE - cout << endl; - cout << "Test of array element slice writing\n"; - cout << "===================================\n"; + std::cout << std::endl; + std::cout << "Test of array element slice writing\n"; + std::cout << "===================================\n"; #endif for (int i = 0; !contextp->gotFinish() && (i < 4); i++) { @@ -497,9 +490,9 @@ int main() { // Check we can read complex registers #ifdef TEST_VERBOSE - cout << endl; - cout << "Test of complex register reading\n"; - cout << "================================\n"; + std::cout << std::endl; + std::cout << "Test of complex register reading\n"; + std::cout << "================================\n"; #endif for (int i = 0; !contextp->gotFinish() && (i < 4); i++) { @@ -536,7 +529,7 @@ int main() { } #ifdef TEST_VERBOSE - cout << endl; + std::cout << std::endl; #endif checkFinish(contextp.get(), "t_dpi_accessors unexpected finish"); @@ -577,9 +570,9 @@ int main() { // Test we can write a complex register #ifdef TEST_VERBOSE - cout << endl; - cout << "Test of complex register writing\n"; - cout << "================================\n"; + std::cout << std::endl; + std::cout << "Test of complex register writing\n"; + std::cout << "================================\n"; #endif for (int i = 0; !contextp->gotFinish() && (i < 4); i++) { @@ -628,7 +621,7 @@ int main() { } #ifdef TEST_VERBOSE - cout << endl; + std::cout << std::endl; #endif checkFinish(contextp.get(), "t_dpi_accessors unexpected finish"); @@ -674,7 +667,7 @@ int main() { // Tidy up dut->final(); - cout << "*-* All Finished *-*\n"; + std::cout << "*-* All Finished *-*\n"; } // Local Variables: diff --git a/test_regress/t/t_dpi_dup_bad.out b/test_regress/t/t_dpi_dup_bad.out index 0450a8504..9015fb25d 100644 --- a/test_regress/t/t_dpi_dup_bad.out +++ b/test_regress/t/t_dpi_dup_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_dpi_dup_bad.v:13:51: Duplicate declaration of DPI function with different signature: 't.oth_f_int2' +%Error: t/t_dpi_dup_bad.v:13:51: Duplicate declaration of DPI function with different signature: 'dpii_fa_bit' 13 | import "DPI-C" pure dpii_fa_bit = function int oth_f_int2(input int i, input int bad); | ^~~~~~~~~~ : ... New signature: pure int dpii_fa_bit (int, int) diff --git a/test_regress/t/t_fork_join_none_any_nested.pl b/test_regress/t/t_fork_join_none_any_nested.pl new file mode 100755 index 000000000..b267631e9 --- /dev/null +++ b/test_regress/t/t_fork_join_none_any_nested.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + verilator_flags2 => ["--timing"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_fork_join_none_any_nested.v b/test_regress/t/t_fork_join_none_any_nested.v new file mode 100644 index 000000000..69f043e0c --- /dev/null +++ b/test_regress/t/t_fork_join_none_any_nested.v @@ -0,0 +1,56 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +event evt1, evt2, evt3; + +class Foo; + task do_something(int cap1, int cap2); + fork + begin + $display("outer fork: %d", cap1); + fork + $display("inner fork: %d", cap2); + ->evt2; + fork + $display("innermost fork: %d", cap2); + ->evt3; + join_none + join_none + end + ->evt1; + join_any + endtask +endclass + +module t(); + reg a, b, c; + + initial begin + Foo foo; + + a = 1'b0; + b = 1'b0; + foo = new; + foo.do_something(1, 2); + end + + always @(evt1) begin + a <= 1; + end + always @(evt2) begin + b <= 1; + end + always @(evt3) begin + c <= 1; + end + + always @(a, b, c) begin + if (a & b & c) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_fork_join_none_class_cap.pl b/test_regress/t/t_fork_join_none_class_cap.pl new file mode 100755 index 000000000..b8493bd06 --- /dev/null +++ b/test_regress/t/t_fork_join_none_class_cap.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_fork_join_none_class_cap.v b/test_regress/t/t_fork_join_none_class_cap.v new file mode 100644 index 000000000..8f5fda807 --- /dev/null +++ b/test_regress/t/t_fork_join_none_class_cap.v @@ -0,0 +1,52 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +event evt1; + +class Foo; + int m_member; + + task do_something(); + fork + #20 begin + m_member++; + $display("this's m_member: ", m_member); + if (m_member != 3) + $stop; + ->evt1; + end + #10 begin + m_member++; + bar(this); + end + join_none + endtask + + static task bar(Foo foo); + fork + begin + foo.m_member++; + $display("foo's m_member: %d", foo.m_member); + if (foo.m_member != 2) + $stop; + end + join_none + endtask +endclass + +module t(); + initial begin + Foo foo; + foo = new; + foo.m_member = 0; + foo.do_something(); + end + + always @(evt1) begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_func_call_order.pl b/test_regress/t/t_func_call_order.pl new file mode 100755 index 000000000..aabcde63e --- /dev/null +++ b/test_regress/t/t_func_call_order.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_func_call_order.v b/test_regress/t/t_func_call_order.v new file mode 100644 index 000000000..7bba5a785 --- /dev/null +++ b/test_regress/t/t_func_call_order.v @@ -0,0 +1,42 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +`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); + +module t(/*AUTOARG*/); + int a; + function int assign5; + a = 5; + return 5; + endfunction + function int assign3; + a = 3; + return 3; + endfunction + function int incr; + a++; + return a; + endfunction + function int assign5_return_arg(int x); + a = 5; + return x; + endfunction + int i; + + initial begin + a = 1; + i = assign5() + assign3() + incr(); + `checkd(a, 4); `checkd(i, 12); + + a = 1; + i = assign5_return_arg(assign3()+incr()); + `checkd(a, 5); `checkd(i, 7); + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_func_defaults.v b/test_regress/t/t_func_defaults.v index 7928a0bce..3d360fa7a 100644 --- a/test_regress/t/t_func_defaults.v +++ b/test_regress/t/t_func_defaults.v @@ -19,6 +19,17 @@ function automatic logic [1:0] foo return x + y; endfunction +class Foo; + static int x; + function static int get_x; + return x; + endfunction +endclass + +function int mult2(int x = Foo::get_x()); + return 2 * x; +endfunction + module t (/*AUTOARG*/); logic [1:0] foo_val; @@ -26,6 +37,11 @@ module t (/*AUTOARG*/); foo_val = foo(); if (foo_val != 2'b10) $stop; + if (mult2(1) != 2) $stop; + if (mult2() != 0) $stop; + Foo::x = 30; + if (mult2() != 60) $stop; + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_func_modify_input.pl b/test_regress/t/t_func_modify_input.pl new file mode 100755 index 000000000..32bdf873d --- /dev/null +++ b/test_regress/t/t_func_modify_input.pl @@ -0,0 +1,16 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +compile(); + +ok(1); +1; diff --git a/test_regress/t/t_func_modify_input.v b/test_regress/t/t_func_modify_input.v new file mode 100644 index 000000000..b1005d1e9 --- /dev/null +++ b/test_regress/t/t_func_modify_input.v @@ -0,0 +1,13 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class foo; + function void g(input integer x); + f(x); + endfunction + function void f(inout integer x); + endfunction +endclass diff --git a/test_regress/t/t_func_tasknsvar_bad.out b/test_regress/t/t_func_tasknsvar_bad.out index d4c3ed0ed..9fd20faba 100644 --- a/test_regress/t/t_func_tasknsvar_bad.out +++ b/test_regress/t/t_func_tasknsvar_bad.out @@ -2,7 +2,7 @@ 16 | foo(bus_we_select_from[2]); | ^ ... For error description see https://verilator.org/warn/TASKNSVAR?v=latest -%Error: Internal Error: t/t_func_tasknsvar_bad.v:10:7: ../V3Broken.cpp:#: Broken link in node (or something without maybePointedTo): 'm_varp && !m_varp->brokeExists()' @ ../V3AstNodes.cpp:72 +%Error: Internal Error: t/t_func_tasknsvar_bad.v:10:7: ../V3Broken.cpp:#: Broken link in node (or something without maybePointedTo): 'm_varp && !m_varp->brokeExists()' @ ../V3AstNodes.cpp:# 10 | sig = '1; | ^~~ ... See the manual at https://verilator.org/verilator_doc.html for more assistance. diff --git a/test_regress/t/t_gate_basic.v b/test_regress/t/t_gate_basic.v index 326a23347..8ac9c0dab 100644 --- a/test_regress/t/t_gate_basic.v +++ b/test_regress/t/t_gate_basic.v @@ -40,12 +40,17 @@ module t (/*AUTOARG*/ buf BARRAY [BITS-1:0] (ba, a); `ifdef verilator + specparam RAW_SP = 1; + + specify + endspecify + specify specparam CDS_LIBNAME = "foobar"; (nt0 *> nt0) = (0, 0); endspecify - specify + specify // delay parameters specparam a$A1$Y = 1.0, diff --git a/test_regress/t/t_if_same_bad.pl b/test_regress/t/t_if_same_bad.pl new file mode 100755 index 000000000..fa67e585c --- /dev/null +++ b/test_regress/t/t_if_same_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +lint( + fails => 0, # bug3806 - this test should fail but does not + # expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_if_same_bad.v b/test_regress/t/t_if_same_bad.v new file mode 100644 index 000000000..276664e07 --- /dev/null +++ b/test_regress/t/t_if_same_bad.v @@ -0,0 +1,58 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// bug3806 + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc = 0; + + reg [3:0] in; + tri [3:0] bus = in; + + int never_driven; + int never_forced; + + task force_bus; + force bus[1:0] = 2'b10; + endtask + + task release_bus; + release bus; + endtask + + // Test loop + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 0) begin + in <= 4'b0101; + end + else if (cyc == 10) begin + $display("10"); + end + else if (cyc == 11) begin + $display("11"); + end + // + // bus + else if (cyc == 10) begin // Should warn + $display("10b"); + end + else if (cyc == 11) begin // Should warn + $display("11b"); + end + // + else if (cyc == 99) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule diff --git a/test_regress/t/t_lint_declfilename_bbox.v b/test_regress/t/t_lint_declfilename_bbox.v index c9bea6e23..5809d71df 100644 --- a/test_regress/t/t_lint_declfilename_bbox.v +++ b/test_regress/t/t_lint_declfilename_bbox.v @@ -6,7 +6,7 @@ module t_lint_declfilename_bbox (); parameter IN = 0; - if (IN) begin + if (IN) begin : gen_hasbbox // Should not warn, see bug2430 BLACKBOXED bboxed (); end diff --git a/test_regress/t/t_lint_genunnamed_bad.out b/test_regress/t/t_lint_genunnamed_bad.out new file mode 100644 index 000000000..2989ed1aa --- /dev/null +++ b/test_regress/t/t_lint_genunnamed_bad.out @@ -0,0 +1,21 @@ +%Warning-GENUNNAMED: t/t_lint_genunnamed_bad.v:14:6: Unnamed generate block 'genblk2' (IEEE 1800-2017 27.6) : ... Suggest assign a label with 'begin : gen_' + 14 | begin + | ^~~~~ + ... For warning description see https://verilator.org/warn/GENUNNAMED?v=latest + ... Use "/* verilator lint_off GENUNNAMED */" and lint_on around source to disable this message. +%Warning-GENUNNAMED: t/t_lint_genunnamed_bad.v:18:6: Unnamed generate block 'genblk2' (IEEE 1800-2017 27.6) : ... Suggest assign a label with 'begin : gen_' + 18 | begin + | ^~~~~ +%Warning-GENUNNAMED: t/t_lint_genunnamed_bad.v:22:4: Unnamed generate block 'genblk3' (IEEE 1800-2017 27.6) : ... Suggest assign a label with 'begin : gen_' + 22 | for (genvar v = 0; v < P; ++v) ; + | ^~~ +%Warning-GENUNNAMED: t/t_lint_genunnamed_bad.v:24:4: Unnamed generate block 'genblk4' (IEEE 1800-2017 27.6) : ... Suggest assign a label with 'begin : gen_' + 24 | for (genvar v = 0; v < P; ++v) + | ^~~ +%Warning-GENUNNAMED: t/t_lint_genunnamed_bad.v:30:9: Unnamed generate block 'genblk5' (IEEE 1800-2017 27.6) : ... Suggest assign a label with 'begin : gen_' + 30 | 1: initial begin end + | ^~~~~~~ +%Warning-GENUNNAMED: t/t_lint_genunnamed_bad.v:31:9: Unnamed generate block 'genblk5' (IEEE 1800-2017 27.6) : ... Suggest assign a label with 'begin : gen_' + 31 | 2: begin + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_lint_genunnamed_bad.pl b/test_regress/t/t_lint_genunnamed_bad.pl new file mode 100755 index 000000000..4ad25735e --- /dev/null +++ b/test_regress/t/t_lint_genunnamed_bad.pl @@ -0,0 +1,20 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +lint( + fails => 1, + verilator_flags2 => ["--lint-only -Wall -Wno-DECLFILENAME"], + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_lint_genunnamed_bad.v b/test_regress/t/t_lint_genunnamed_bad.v new file mode 100644 index 000000000..44c701abb --- /dev/null +++ b/test_regress/t/t_lint_genunnamed_bad.v @@ -0,0 +1,36 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + + parameter P = 1; + + if (P) ; + + if (P) + begin + initial $display; + end + else + begin + initial $display; + end + + for (genvar v = 0; v < P; ++v) ; + + for (genvar v = 0; v < P; ++v) + begin + initial $display; + end + + case (P) + 1: initial begin end + 2: begin + initial begin end + end + endcase + +endmodule diff --git a/test_regress/t/t_lint_misindent_bad.out b/test_regress/t/t_lint_misindent_bad.out new file mode 100644 index 000000000..145c4b9f3 --- /dev/null +++ b/test_regress/t/t_lint_misindent_bad.out @@ -0,0 +1,27 @@ +%Warning-MISINDENT: t/t_lint_misindent_bad.v:14:9: Misleading indentation + 14 | $display("bad1"); + | ^~~~~~~~ + t/t_lint_misindent_bad.v:12:7: ... Expected indentation matching this earlier statement's line: + 12 | if (0) + | ^~ + ... For warning description see https://verilator.org/warn/MISINDENT?v=latest + ... Use "/* verilator lint_off MISINDENT */" and lint_on around source to disable this message. +%Warning-MISINDENT: t/t_lint_misindent_bad.v:20:9: Misleading indentation + 20 | $display("bad2"); + | ^~~~~~~~ + t/t_lint_misindent_bad.v:16:7: ... Expected indentation matching this earlier statement's line: + 16 | if (0) + | ^~ +%Warning-MISINDENT: t/t_lint_misindent_bad.v:24:9: Misleading indentation + 24 | $display("bad3"); + | ^~~~~~~~ + t/t_lint_misindent_bad.v:22:7: ... Expected indentation matching this earlier statement's line: + 22 | for (;0;) + | ^~~ +%Warning-MISINDENT: t/t_lint_misindent_bad.v:28:9: Misleading indentation + 28 | $display("bad4"); + | ^~~~~~~~ + t/t_lint_misindent_bad.v:26:7: ... Expected indentation matching this earlier statement's line: + 26 | while (0) + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_lint_misindent_bad.pl b/test_regress/t/t_lint_misindent_bad.pl new file mode 100755 index 000000000..4ad25735e --- /dev/null +++ b/test_regress/t/t_lint_misindent_bad.pl @@ -0,0 +1,20 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +lint( + fails => 1, + verilator_flags2 => ["--lint-only -Wall -Wno-DECLFILENAME"], + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_lint_misindent_bad.v b/test_regress/t/t_lint_misindent_bad.v new file mode 100644 index 000000000..5f6b6cab8 --- /dev/null +++ b/test_regress/t/t_lint_misindent_bad.v @@ -0,0 +1,48 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// Do not reindent - spaces are critical to this test + +module t (/*AUTOARG*/); + + initial begin + if (0) + $display("ok"); + $display("bad1"); // <--- Bad + + if (0) + $display("ok"); + else + $display("ok"); + $display("bad2"); // <--- Bad + + for (;0;) + $display("ok"); + $display("bad3"); // <--- Bad + + while (0) + $display("ok"); + $display("bad4"); // <--- Bad + + // Normal styles + if (0) $display("ok"); + $display("ok"); + for (;0;) $display("ok"); + $display("ok"); + while (0) $display("ok"); + $display("ok"); + + // Questionable but pops up in some cases e.g. SweRV + // (all statements have similar indent) + if (0) + begin + $display("ok"); + end + $display("ok"); + + end + +endmodule diff --git a/test_regress/t/t_lint_unused_bad.v b/test_regress/t/t_lint_unused_bad.v index cb2908289..cc837c4ec 100644 --- a/test_regress/t/t_lint_unused_bad.v +++ b/test_regress/t/t_lint_unused_bad.v @@ -71,8 +71,11 @@ module sub; end generate - if (0) - for (ok_gv = 0; ok_gv < 1; ++ok_gv) begin end + if (0) begin : gen_gv_if0 + for (ok_gv = 0; ok_gv < 1; ++ok_gv) + begin : gen_gv_if0_for + end + end endgenerate endmodule diff --git a/test_regress/t/t_lint_wait_bad.out b/test_regress/t/t_lint_wait_bad.out index 908d043be..8cc25f02c 100644 --- a/test_regress/t/t_lint_wait_bad.out +++ b/test_regress/t/t_lint_wait_bad.out @@ -1,15 +1,15 @@ -%Warning-WAITCONST: t/t_timing_wait1.v:48:12: Wait statement condition is constant - 48 | wait(1); +%Warning-WAITCONST: t/t_timing_wait1.v:52:12: Wait statement condition is constant + 52 | wait(1); | ^ ... For warning description see https://verilator.org/warn/WAITCONST?v=latest ... Use "/* verilator lint_off WAITCONST */" and lint_on around source to disable this message. -%Warning-WAITCONST: t/t_timing_wait1.v:50:14: Wait statement condition is constant - 50 | wait(0 < 1) $write("*-* All Finished *-*\n"); +%Warning-WAITCONST: t/t_timing_wait1.v:54:14: Wait statement condition is constant + 54 | wait(0 < 1) $write("*-* All Finished *-*\n"); | ^ -%Warning-WAITCONST: t/t_timing_wait1.v:54:17: Wait statement condition is constant - 54 | initial wait(0) $stop; +%Warning-WAITCONST: t/t_timing_wait1.v:58:17: Wait statement condition is constant + 58 | initial wait(0) $stop; | ^ -%Warning-WAITCONST: t/t_timing_wait1.v:55:19: Wait statement condition is constant - 55 | initial wait(1 == 0) $stop; +%Warning-WAITCONST: t/t_timing_wait1.v:59:19: Wait statement condition is constant + 59 | initial wait(1 == 0) $stop; | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_mailbox_notiming.pl b/test_regress/t/t_mailbox_notiming.pl new file mode 100755 index 000000000..fb7f3e881 --- /dev/null +++ b/test_regress/t/t_mailbox_notiming.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + verilator_flags2 => ["--exe --main --no-timing -Wall"], + make_main => 0, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_mailbox_notiming.v b/test_regress/t/t_mailbox_notiming.v new file mode 100644 index 000000000..a4a2cc749 --- /dev/null +++ b/test_regress/t/t_mailbox_notiming.v @@ -0,0 +1,33 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// Methods defined by IEEE: +// class mailbox #(type T = dynamic_singular_type) ; +// function new(int bound = 0); +// function int num(); +// task put( T message); +// function int try_put( T message); +// task get( ref T message ); +// function int try_get( ref T message ); +// task peek( ref T message ); +// function int try_peek( ref T message ); +// endclass + +`ifndef MAILBOX_T + `define MAILBOX_T mailbox +`endif + +// verilator lint_off DECLFILENAME +module t(/*AUTOARG*/); + `MAILBOX_T #(int) m; + + initial begin + m = new(4); + if (m.num() != 0) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_math_repl_bad.out b/test_regress/t/t_math_repl_bad.out index 18193afbe..34fc9e4f8 100644 --- a/test_regress/t/t_math_repl_bad.out +++ b/test_regress/t/t_math_repl_bad.out @@ -8,15 +8,12 @@ | ^ ... For warning description see https://verilator.org/warn/WIDTHEXPAND?v=latest ... Use "/* verilator lint_off WIDTHEXPAND */" and lint_on around source to disable this message. -%Error: t/t_math_repl_bad.v:13:12: Expecting expression to be constant, but can't convert a TESTPLUSARGS to constant. - : ... In instance t - 13 | o = {$test$plusargs("NON-CONSTANT") {1'b1}}; - | ^~~~~~~~~~~~~~ %Error: t/t_math_repl_bad.v:13:43: Replication value isn't a constant. : ... In instance t 13 | o = {$test$plusargs("NON-CONSTANT") {1'b1}}; | ^ -%Error: Internal Error: t/t_math_repl_bad.v:13:9: ../V3Width.cpp:#: Node has no type - : ... In instance t +%Warning-WIDTHEXPAND: t/t_math_repl_bad.v:13:9: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's REPLICATE generates 1 bits. + : ... In instance t 13 | o = {$test$plusargs("NON-CONSTANT") {1'b1}}; | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_process_fork.v b/test_regress/t/t_process_fork.v index 1ea1c477e..b4a7a18ab 100644 --- a/test_regress/t/t_process_fork.v +++ b/test_regress/t/t_process_fork.v @@ -6,7 +6,6 @@ module t; process job[] = new [8]; - bit is_alloc = 0; initial begin foreach (job[j]) fork @@ -16,8 +15,7 @@ module t; end join_none foreach (job[j]) begin - is_alloc = !!job[j]; - wait (is_alloc); + wait (job[j]); end $write("all jobs started\n"); foreach (job[j]) begin diff --git a/test_regress/t/t_process_kill.v b/test_regress/t/t_process_kill.v index 8c0252939..a382bfcf4 100644 --- a/test_regress/t/t_process_kill.v +++ b/test_regress/t/t_process_kill.v @@ -10,10 +10,9 @@ module t (/*AUTOARG*/ ); input clk; process p; - bit s = 0; initial begin - wait (s); + wait (p); p.kill(); p.await(); $write("*-* All Finished *-*\n"); @@ -23,7 +22,6 @@ module t (/*AUTOARG*/ always @(posedge clk) begin if (!p) begin p = process::self(); - s = 1; end else begin $stop; end diff --git a/test_regress/t/t_process_propagation.pl b/test_regress/t/t_process_propagation.pl new file mode 100755 index 000000000..3364f1ed7 --- /dev/null +++ b/test_regress/t/t_process_propagation.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_process_propagation.v b/test_regress/t/t_process_propagation.v new file mode 100644 index 000000000..812b12ccb --- /dev/null +++ b/test_regress/t/t_process_propagation.v @@ -0,0 +1,68 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +event evt1, evt2; + +class Foo; + process p; + bit event_received; + + function new(); + p = process::self(); + endfunction + + virtual task ewait(); + @evt1 $display("Foo received event `evt1`"); + event_received = 1; + ->evt2; + endtask +endclass + +class Bar extends Foo; + function new(); + super.new(); + $display("Constructing Bar"); + endfunction + + virtual task ewait(); + @evt1 $display("Bar received event `evt1`"); + event_received = 1; + endtask +endclass + +module t(); + initial begin + process p; + Foo foo; + Bar bar; + + fork + begin + foo = new; + foo.ewait(); + end + begin + bar = new; + p = process::self(); + bar.ewait(); + end + join_none + + p.kill(); + + ->evt1; + + @evt2 begin + if (!foo.event_received) + $stop; + if (bar.event_received) + $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_process_task.pl b/test_regress/t/t_process_task.pl new file mode 100755 index 000000000..123e2f4fd --- /dev/null +++ b/test_regress/t/t_process_task.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + v_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_process_task.v b/test_regress/t/t_process_task.v new file mode 100644 index 000000000..5701b47b3 --- /dev/null +++ b/test_regress/t/t_process_task.v @@ -0,0 +1,33 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t(); + std::process proc; + logic clk = 0; + logic b = 0; + + always #1 clk = ~clk; + + task kill_me_after_1ns(); + fork + #1 proc.kill(); + #3 begin + $write("*-* All Finished *-*\n"); + $finish; + end + join_none + endtask + + always @(posedge clk) begin + if (!b) begin + proc = std::process::self(); + kill_me_after_1ns(); + b = 1; + end else begin + $stop; + end + end +endmodule diff --git a/test_regress/t/t_queue_method.v b/test_regress/t/t_queue_method.v index 59c4dc4a5..090ac5a9f 100644 --- a/test_regress/t/t_queue_method.v +++ b/test_regress/t/t_queue_method.v @@ -10,6 +10,13 @@ `define checkg(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%g' exp='%g'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +class Cls; + int x; + function new(int a); + x = a; + endfunction +endclass + module t (/*AUTOARG*/); typedef struct packed { int x, y; } point; typedef struct packed { point p; int z; } point_3d; @@ -25,11 +32,22 @@ module t (/*AUTOARG*/); string string_qv[$]; point_3d points_q[$]; // Same as q and qv, but complex value type point_3d points_qv[$]; + Cls cls; + Cls cls_q[$]; + Cls cls_qv[$]; points_q.push_back(point_3d'{point'{1, 2}, 3}); points_q.push_back(point_3d'{point'{2, 3}, 5}); points_q.push_back(point_3d'{point'{1, 4}, 5}); + + cls = new(1); + cls_q.push_back(cls); + cls = new(2); + cls_q.push_back(cls); + cls = new(1); + cls_q.push_back(cls); + string_q.push_back("a"); string_q.push_back("A"); string_q.push_back("b"); @@ -71,6 +89,13 @@ module t (/*AUTOARG*/); `checkh(qi.size(), 0); qi = q.unique_index(x) with (x % 3); qv.sort; `checkh(qi.size(), 3); + cls_qv = cls_q.unique with (item.x); + `checkh(cls_qv.size(), 2); + cls_qv = cls_q.unique with (item.x < 10); + `checkh(cls_qv.size(), 1); + qi = cls_q.unique_index with (item.x % 2); + qi.sort; + v = $sformatf("%p", qi); `checks(v, "'{'h0, 'h1} "); q.reverse; v = $sformatf("%p", q); `checks(v, "'{'h3, 'h1, 'h4, 'h2, 'h2} "); diff --git a/test_regress/t/t_queue_var_slice.pl b/test_regress/t/t_queue_var_slice.pl new file mode 100755 index 000000000..859050d63 --- /dev/null +++ b/test_regress/t/t_queue_var_slice.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_queue_var_slice.v b/test_regress/t/t_queue_var_slice.v new file mode 100644 index 000000000..da4e24877 --- /dev/null +++ b/test_regress/t/t_queue_var_slice.v @@ -0,0 +1,25 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer i = 0; + integer q[$] = {0, 1}; + + always @(posedge clk) begin + $display("%p", q[i:i+1]); + q.push_back(i+2); + i++; + if (i >= 3) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_randomize_method_nclass_bad.out b/test_regress/t/t_randomize_method_nclass_bad.out index 6c48315e6..a9b29ccfc 100644 --- a/test_regress/t/t_randomize_method_nclass_bad.out +++ b/test_regress/t/t_randomize_method_nclass_bad.out @@ -1,9 +1,7 @@ %Error: t/t_randomize_method_nclass_bad.v:9:7: Calling implicit class method 'randomize' without being under class - : ... In instance t 9 | randomize(1); | ^~~~~~~~~ %Error: t/t_randomize_method_nclass_bad.v:10:7: Calling implicit class method 'srandom' without being under class - : ... In instance t 10 | srandom(1); | ^~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_randstate_seed_bad.out b/test_regress/t/t_randstate_seed_bad.out index 75e3250f6..7ba1754c7 100644 --- a/test_regress/t/t_randstate_seed_bad.out +++ b/test_regress/t/t_randstate_seed_bad.out @@ -1,2 +1,3 @@ %Warning: set_randstate ignored as state string not from get_randstate +%Warning: set_randstate ignored as state string not from get_randstate *-* All Finished *-* diff --git a/test_regress/t/t_randstate_seed_bad.v b/test_regress/t/t_randstate_seed_bad.v index ebcf2c0a9..1762e72a1 100644 --- a/test_regress/t/t_randstate_seed_bad.v +++ b/test_regress/t/t_randstate_seed_bad.v @@ -13,6 +13,7 @@ class Cls; if (s[0] !== "R") $fatal(2, $sformatf("Bad get_randstate = '%s'", s)); set_randstate("000bad"); // Bad + set_randstate("Zdlffjfmkmhodjcnddlffjfmkmhodjcnd"); // Bad endfunction endclass diff --git a/test_regress/t/t_select_bad_range4.out b/test_regress/t/t_select_bad_range4.out index cff72fd9a..6646fc383 100644 --- a/test_regress/t/t_select_bad_range4.out +++ b/test_regress/t/t_select_bad_range4.out @@ -52,14 +52,6 @@ : ... In instance t 23 | sel2 = mi[nonconst]; | ^ -%Error: t/t_select_bad_range4.v:24:17: Expecting expression to be constant, but variable isn't const: 'nonconst' - : ... In instance t - 24 | sel2 = mi[nonconst : nonconst]; - | ^~~~~~~~ -%Error: t/t_select_bad_range4.v:24:28: Expecting expression to be constant, but variable isn't const: 'nonconst' - : ... In instance t - 24 | sel2 = mi[nonconst : nonconst]; - | ^~~~~~~~ %Error: t/t_select_bad_range4.v:24:17: First value of [a:b] isn't a constant, maybe you want +: or -: : ... In instance t 24 | sel2 = mi[nonconst : nonconst]; diff --git a/test_regress/t/t_srandom_class_dep.pl b/test_regress/t/t_srandom_class_dep.pl new file mode 100755 index 000000000..c74d44be5 --- /dev/null +++ b/test_regress/t/t_srandom_class_dep.pl @@ -0,0 +1,16 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile(); + +ok(1); +1; diff --git a/test_regress/t/t_srandom_class_dep.v b/test_regress/t/t_srandom_class_dep.v new file mode 100644 index 000000000..0e115dae1 --- /dev/null +++ b/test_regress/t/t_srandom_class_dep.v @@ -0,0 +1,50 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +typedef class Cls; + +class A; + extern function void method(); +endclass + +class B; + extern function void method(); +endclass + +class C; + extern function void method(); +endclass + +class D; + extern function void method(); +endclass + +function void A::method(); + B obj = new; + obj.method(); +endfunction + +function void B::method(); + this.srandom(0); +endfunction + +function void C::method(); + this.srandom(0); +endfunction + +function void D::method(); + C obj = new; + obj.method(); +endfunction + +module t; + A obj1 = new; + D obj2 = new; + initial begin + obj1.method(); + obj2.method(); + end +endmodule diff --git a/test_regress/t/t_std_process_self.pl b/test_regress/t/t_std_process_self.pl new file mode 100755 index 000000000..5b73c5ff4 --- /dev/null +++ b/test_regress/t/t_std_process_self.pl @@ -0,0 +1,24 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +lint( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + +lint( + verilator_flags2 => ["--exe --main --timing --DUSE_STD_PREFIX"], + make_main => 0, + ); + +ok(1); +1; diff --git a/test_regress/t/t_std_process_self.v b/test_regress/t/t_std_process_self.v new file mode 100644 index 000000000..ddcacedc8 --- /dev/null +++ b/test_regress/t/t_std_process_self.v @@ -0,0 +1,24 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Foo; + static task do_something(); +`ifdef USE_STD_PREFIX + std::process p; +`else + process p; +`endif + p = process::self(); + endtask +endclass + +module t(); + initial begin + Foo::do_something(); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_stream_bad.out b/test_regress/t/t_stream_bad.out index 970a91901..6b4934e46 100644 --- a/test_regress/t/t_stream_bad.out +++ b/test_regress/t/t_stream_bad.out @@ -6,10 +6,4 @@ : ... In instance t 12 | initial packed_data_32 = {<<$random{byte_in}}; | ^~ -%Warning-WIDTHEXPAND: t/t_stream_bad.v:12:27: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's STREAML generates 8 bits. - : ... In instance t - 12 | initial packed_data_32 = {<<$random{byte_in}}; - | ^ - ... For warning description see https://verilator.org/warn/WIDTHEXPAND?v=latest - ... Use "/* verilator lint_off WIDTHEXPAND */" and lint_on around source to disable this message. %Error: Exiting due to diff --git a/test_regress/t/t_stream_integer_type.out b/test_regress/t/t_stream_integer_type.out index ab803e9a1..05640a0f4 100644 --- a/test_regress/t/t_stream_integer_type.out +++ b/test_regress/t/t_stream_integer_type.out @@ -1,149 +1,3 @@ -%Warning-WIDTHEXPAND: t/t_stream_integer_type.v:118:28: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's STREAML generates 8 bits. - : ... In instance t - 118 | packed_data_32 = {<<8{byte_in}}; - | ^ - ... For warning description see https://verilator.org/warn/WIDTHEXPAND?v=latest - ... Use "/* verilator lint_off WIDTHEXPAND */" and lint_on around source to disable this message. -%Warning-WIDTHEXPAND: t/t_stream_integer_type.v:119:28: Operator ASSIGN expects 64 bits on the Assign RHS, but Assign RHS's STREAML generates 16 bits. - : ... In instance t - 119 | packed_data_64 = {<<16{shortint_in}}; - | ^ -%Warning-WIDTHEXPAND: t/t_stream_integer_type.v:120:28: Operator ASSIGN expects 128 bits on the Assign RHS, but Assign RHS's STREAML generates 32 bits. - : ... In instance t - 120 | packed_data_128 = {<<32{int_in}}; - | ^ -%Warning-WIDTHEXPAND: t/t_stream_integer_type.v:121:28: Operator ASSIGN expects 128 bits on the Assign RHS, but Assign RHS's STREAML generates 32 bits. - : ... In instance t - 121 | packed_data_128_i = {<<32{integer_in}}; - | ^ -%Warning-WIDTHEXPAND: t/t_stream_integer_type.v:122:28: Operator ASSIGN expects 256 bits on the Assign RHS, but Assign RHS's STREAML generates 64 bits. - : ... In instance t - 122 | packed_data_256 = {<<64{longint_in}}; - | ^ -%Warning-WIDTHEXPAND: t/t_stream_integer_type.v:123:28: Operator ASSIGN expects 256 bits on the Assign RHS, but Assign RHS's STREAML generates 64 bits. - : ... In instance t - 123 | packed_time_256 = {<<64{time_in}}; - | ^ -%Warning-WIDTHEXPAND: t/t_stream_integer_type.v:124:28: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's STREAML generates 8 bits. - : ... In instance t - 124 | v_packed_data_32 = {<<8{bit_in}}; - | ^ -%Warning-WIDTHEXPAND: t/t_stream_integer_type.v:125:28: Operator ASSIGN expects 64 bits on the Assign RHS, but Assign RHS's STREAML generates 16 bits. - : ... In instance t - 125 | v_packed_data_64 = {<<16{logic_in}}; - | ^ -%Warning-WIDTHEXPAND: t/t_stream_integer_type.v:126:28: Operator ASSIGN expects 128 bits on the Assign RHS, but Assign RHS's STREAML generates 32 bits. - : ... In instance t - 126 | v_packed_data_128 = {<<32{reg_in}}; - | ^ -%Warning-WIDTHTRUNC: t/t_stream_integer_type.v:128:31: Operator ASSIGN expects 8 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_32' generates 32 bits. - : ... In instance t - 128 | {<<8{byte_out}} = packed_data_32; - | ^ -%Warning-WIDTHTRUNC: t/t_stream_integer_type.v:129:31: Operator ASSIGN expects 16 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_64' generates 64 bits. - : ... In instance t - 129 | {<<16{shortint_out}} = packed_data_64; - | ^ -%Warning-WIDTHTRUNC: t/t_stream_integer_type.v:130:31: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_128' generates 128 bits. - : ... In instance t - 130 | {<<32{int_out}} = packed_data_128; - | ^ -%Warning-WIDTHTRUNC: t/t_stream_integer_type.v:131:31: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_128_i' generates 128 bits. - : ... In instance t - 131 | {<<32{integer_out}} = packed_data_128_i; - | ^ -%Warning-WIDTHTRUNC: t/t_stream_integer_type.v:132:31: Operator ASSIGN expects 64 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_256' generates 256 bits. - : ... In instance t - 132 | {<<64{longint_out}} = packed_data_256; - | ^ -%Warning-WIDTHTRUNC: t/t_stream_integer_type.v:133:31: Operator ASSIGN expects 64 bits on the Assign RHS, but Assign RHS's VARREF 'packed_time_256' generates 256 bits. - : ... In instance t - 133 | {<<64{time_out}} = packed_time_256; - | ^ -%Warning-WIDTHTRUNC: t/t_stream_integer_type.v:134:31: Operator ASSIGN expects 8 bits on the Assign RHS, but Assign RHS's VARREF 'v_packed_data_32' generates 32 bits. - : ... In instance t - 134 | {<<8{bit_out}} = v_packed_data_32; - | ^ -%Warning-WIDTHTRUNC: t/t_stream_integer_type.v:135:31: Operator ASSIGN expects 16 bits on the Assign RHS, but Assign RHS's VARREF 'v_packed_data_64' generates 64 bits. - : ... In instance t - 135 | {<<16{logic_out}} = v_packed_data_64; - | ^ -%Warning-WIDTHTRUNC: t/t_stream_integer_type.v:136:31: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's VARREF 'v_packed_data_128' generates 128 bits. - : ... In instance t - 136 | {<<32{reg_out}} = v_packed_data_128; - | ^ -%Warning-WIDTHEXPAND: t/t_stream_integer_type.v:150:28: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's STREAML generates 8 bits. - : ... In instance t - 150 | packed_data_32 = {< 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_stream_string_array.v b/test_regress/t/t_stream_string_array.v new file mode 100644 index 000000000..6e8081dd9 --- /dev/null +++ b/test_regress/t/t_stream_string_array.v @@ -0,0 +1,31 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t; + string qs[$]; + string as[]; + string s; + initial begin + s = {>>{qs}}; + if (s != "") $stop; + + s = {>>{as}}; + if (s != "") $stop; + + qs = '{"ab", "c", ""}; + s = {>>{qs}}; + if (s != "abc") $stop; + + as = new[3]; + as[0] = "abcd"; + as[2] = "ef"; + s = {>>{as}}; + if (s != "abcdef") $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_string_repl.pl b/test_regress/t/t_string_repl.pl new file mode 100755 index 000000000..1aa73f80a --- /dev/null +++ b/test_regress/t/t_string_repl.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_string_repl.v b/test_regress/t/t_string_repl.v new file mode 100644 index 000000000..327c9e9d8 --- /dev/null +++ b/test_regress/t/t_string_repl.v @@ -0,0 +1,45 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Use this file as a template for submitting bugs, etc. +// This module takes a single clock input, and should either +// $write("*-* All Finished *-*\n"); +// $finish; +// on success, or $stop. +// +// The code as shown applies a random vector to the Test +// module, then calculates a CRC on the Test module's outputs. +// +// **If you do not wish for your code to be released to the public +// please note it here, otherwise:** +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc = 0; + + string s; + + // Test loop + always @ (posedge clk) begin + cyc <= cyc + 1; + s = {cyc{"*"}}; + if (cyc != s.len()) $stop; + if (cyc == 0 && s != "") $stop; + if (cyc == 1 && s != "*") $stop; + if (cyc == 2 && s != "**") $stop; + if (cyc == 3 && s != "***") $stop; + if (cyc == 4 && s != "****") $stop; + if (cyc == 5 && s != "*****") $stop; + if (cyc == 5) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_sys_readmem.v b/test_regress/t/t_sys_readmem.v index 98a025ee8..60756207e 100644 --- a/test_regress/t/t_sys_readmem.v +++ b/test_regress/t/t_sys_readmem.v @@ -4,6 +4,9 @@ // any use, without warranty, 2003 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); + `ifdef WRITEMEM_BIN `define READMEMX $readmemb `define WRITEMEMX $writememb @@ -20,6 +23,10 @@ module t; reg [5:0] binary_start [0:15]; reg [175:0] hex [0:15]; reg [(32*6)-1:0] hex_align [0:15]; + reg [55:0] qdata [0:15]; + reg [25:0] idata [0:15]; + reg [10:0] sdata [0:15]; + reg [6:0] cdata [0:15]; string fns; `ifdef WRITEMEM_READ_BACK @@ -28,6 +35,10 @@ module t; reg [5:0] binary_start_tmp [0:15]; reg [175:0] hex_tmp [0:15]; reg [(32*6)-1:0] hex_align_tmp [0:15]; + reg [55:0] qdata_tmp [0:15]; + reg [25:0] idata_tmp [0:15]; + reg [10:0] sdata_tmp [0:15]; + reg [6:0] cdata_tmp [0:15]; string fns_tmp; `endif // verilator lint_on ASCRANGE @@ -39,13 +50,21 @@ module t; // Initialize memories to zero, // avoid differences between 2-state and 4-state. for (i=0; i<16; i=i+1) begin - binary_start[i] = 6'h0; - hex[i] = 176'h0; - hex_align[i] = {32*6{1'b0}}; + binary_start[i] = '0; + hex[i] = '0; + hex_align[i] = '0; + qdata[i] = '0; + idata[i] = '0; + sdata[i] = '0; + cdata[i] = '0; `ifdef WRITEMEM_READ_BACK - binary_start_tmp[i] = 6'h0; - hex_tmp[i] = 176'h0; - hex_align_tmp[i] = {32*6{1'b0}}; + binary_start_tmp[i] = '0; + hex_tmp[i] = '0; + hex_align_tmp[i] = '0; + qdata_tmp[i] = '0; + idata_tmp[i] = '0; + sdata_tmp[i] = '0; + cdata_tmp[i] = '0; `endif end for (i=2; i<16; i=i+1) begin @@ -161,12 +180,92 @@ module t; end begin - fns = "t/t_sys_readmem_b.mem"; `ifdef WRITEMEM_READ_BACK - fns_tmp = `OUT_TMP5; - $readmemb(fns, binary_string_tmp); + $readmemh("t/t_sys_readmem_q.mem", qdata_tmp, 0); `ifdef TEST_VERBOSE $display("-Writing %s", `OUT_TMP5); + `endif + `WRITEMEMX(`OUT_TMP5, qdata_tmp, 0); + `READMEMX(`OUT_TMP5, qdata, 0); +`else + $readmemh("t/t_sys_readmem_q.mem", qdata, 0); +`endif +`ifdef TEST_VERBOSE + for (i=0; i<16; i=i+1) $write(" @%x = %x\n", i, qdata[i]); +`endif + `checkh(qdata['h04], 56'hdcba9876540004); + `checkh(qdata['h0a], 56'hdcba987654000a); + `checkh(qdata['h0b], 56'hdcba987654000b); + `checkh(qdata['h0c], 56'hdcba987654000c); + end + + begin +`ifdef WRITEMEM_READ_BACK + $readmemh("t/t_sys_readmem_i.mem", idata_tmp, 0); + `ifdef TEST_VERBOSE + $display("-Writing %s", `OUT_TMP6); + `endif + `WRITEMEMX(`OUT_TMP6, idata_tmp, 0); + `READMEMX(`OUT_TMP6, idata, 0); +`else + $readmemh("t/t_sys_readmem_i.mem", idata, 0); +`endif +`ifdef TEST_VERBOSE + for (i=0; i<16; i=i+1) $write(" @%x = %x\n", i, idata[i]); +`endif + `checkh(idata['h04], 26'h6540004); + `checkh(idata['h0a], 26'h654000a); + `checkh(idata['h0b], 26'h654000b); + `checkh(idata['h0c], 26'h654000c); + end + + begin +`ifdef WRITEMEM_READ_BACK + $readmemh("t/t_sys_readmem_s.mem", sdata_tmp, 0); + `ifdef TEST_VERBOSE + $display("-Writing %s", `OUT_TMP7); + `endif + `WRITEMEMX(`OUT_TMP7, sdata_tmp, 0); + `READMEMX(`OUT_TMP7, sdata, 0); +`else + $readmemh("t/t_sys_readmem_s.mem", sdata, 0); +`endif +`ifdef TEST_VERBOSE + for (i=0; i<16; i=i+1) $write(" @%x = %x\n", i, sdata[i]); +`endif + `checkh(sdata['h04], 11'h654); + `checkh(sdata['h0a], 11'h65a); + `checkh(sdata['h0b], 11'h65b); + `checkh(sdata['h0c], 11'h65c); + end + + begin +`ifdef WRITEMEM_READ_BACK + $readmemh("t/t_sys_readmem_c.mem", cdata_tmp, 0); + `ifdef TEST_VERBOSE + $display("-Writing %s", `OUT_TMP8); + `endif + `WRITEMEMX(`OUT_TMP8, cdata_tmp, 0); + `READMEMX(`OUT_TMP8, cdata, 0); +`else + $readmemh("t/t_sys_readmem_c.mem", cdata, 0); +`endif +`ifdef TEST_VERBOSE + for (i=0; i<16; i=i+1) $write(" @%x = %x\n", i, cdata[i]); +`endif + `checkh(cdata['h04], 7'h14); + `checkh(cdata['h0a], 7'h1a); + `checkh(cdata['h0b], 7'h1b); + `checkh(cdata['h0c], 7'h1c); + end + + begin + fns = "t/t_sys_readmem_b.mem"; +`ifdef WRITEMEM_READ_BACK + fns_tmp = `OUT_TMP8; + $readmemb(fns, binary_string_tmp); + `ifdef TEST_VERBOSE + $display("-Writing %s", `OUT_TMP8); `endif `WRITEMEMX(fns_tmp, binary_string_tmp); `READMEMX(fns_tmp, binary_string); diff --git a/test_regress/t/t_sys_readmem_c.mem b/test_regress/t/t_sys_readmem_c.mem new file mode 100644 index 000000000..31a4308b5 --- /dev/null +++ b/test_regress/t/t_sys_readmem_c.mem @@ -0,0 +1,14 @@ +// DESCRIPTION: Verilator: Verilog Test data file +// +// Copyright 2006 by Wilson Snyder. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +@4 +14 +@a +1a +1b +1c diff --git a/test_regress/t/t_sys_readmem_i.mem b/test_regress/t/t_sys_readmem_i.mem new file mode 100644 index 000000000..6aa4b23a6 --- /dev/null +++ b/test_regress/t/t_sys_readmem_i.mem @@ -0,0 +1,14 @@ +// DESCRIPTION: Verilator: Verilog Test data file +// +// Copyright 2006 by Wilson Snyder. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +@4 +6540004 +@a +654000a +654000b +654000c diff --git a/test_regress/t/t_sys_readmem_q.mem b/test_regress/t/t_sys_readmem_q.mem new file mode 100644 index 000000000..d52d768f8 --- /dev/null +++ b/test_regress/t/t_sys_readmem_q.mem @@ -0,0 +1,14 @@ +// DESCRIPTION: Verilator: Verilog Test data file +// +// Copyright 2006 by Wilson Snyder. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +@4 +dcba9876540004 +@a +dcba987654000a +dcba987654000b +dcba987654000c diff --git a/test_regress/t/t_sys_readmem_s.mem b/test_regress/t/t_sys_readmem_s.mem new file mode 100644 index 000000000..ca7a618c0 --- /dev/null +++ b/test_regress/t/t_sys_readmem_s.mem @@ -0,0 +1,14 @@ +// DESCRIPTION: Verilator: Verilog Test data file +// +// Copyright 2006 by Wilson Snyder. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +@4 +654 +@a +65a +65b +65c diff --git a/test_regress/t/t_sys_writemem.gold5.mem b/test_regress/t/t_sys_writemem.gold5.mem index b25ae23ef..84dfbc569 100644 --- a/test_regress/t/t_sys_writemem.gold5.mem +++ b/test_regress/t/t_sys_writemem.gold5.mem @@ -1,14 +1,16 @@ -02 -03 -04 -05 -06 -07 -10 -00 -00 -00 -14 -15 -00 -00 +00000000000000 +00000000000000 +00000000000000 +00000000000000 +dcba9876540004 +00000000000000 +00000000000000 +00000000000000 +00000000000000 +00000000000000 +dcba987654000a +dcba987654000b +dcba987654000c +00000000000000 +00000000000000 +00000000000000 diff --git a/test_regress/t/t_sys_writemem.gold6.mem b/test_regress/t/t_sys_writemem.gold6.mem new file mode 100644 index 000000000..921ddb874 --- /dev/null +++ b/test_regress/t/t_sys_writemem.gold6.mem @@ -0,0 +1,16 @@ +0000000 +0000000 +0000000 +0000000 +2540004 +0000000 +0000000 +0000000 +0000000 +0000000 +254000a +254000b +254000c +0000000 +0000000 +0000000 diff --git a/test_regress/t/t_sys_writemem.gold7.mem b/test_regress/t/t_sys_writemem.gold7.mem new file mode 100644 index 000000000..dafd3a003 --- /dev/null +++ b/test_regress/t/t_sys_writemem.gold7.mem @@ -0,0 +1,16 @@ +000 +000 +000 +000 +654 +000 +000 +000 +000 +000 +65a +65b +65c +000 +000 +000 diff --git a/test_regress/t/t_sys_writemem.gold8.mem b/test_regress/t/t_sys_writemem.gold8.mem new file mode 100644 index 000000000..b25ae23ef --- /dev/null +++ b/test_regress/t/t_sys_writemem.gold8.mem @@ -0,0 +1,14 @@ +02 +03 +04 +05 +06 +07 +10 +00 +00 +00 +14 +15 +00 +00 diff --git a/test_regress/t/t_sys_writemem.pl b/test_regress/t/t_sys_writemem.pl index 431a02b0e..d06bb642f 100755 --- a/test_regress/t/t_sys_writemem.pl +++ b/test_regress/t/t_sys_writemem.pl @@ -16,6 +16,8 @@ top_filename("t/t_sys_readmem.v"); # $writememh, to avoid miscompares with X's on 4-state simulators. $Self->{verilated_randReset} = 2; # 2 == truly random +# TODO make test more generic to take the data type as a define +# then we can call test multiple times in different tests compile(v_flags2 => [ "+define+WRITEMEM_READ_BACK=1", "+define+OUT_TMP1=\\\"$Self->{obj_dir}/tmp1.mem\\\"", @@ -23,13 +25,16 @@ compile(v_flags2 => [ "+define+OUT_TMP3=\\\"$Self->{obj_dir}/tmp3.mem\\\"", "+define+OUT_TMP4=\\\"$Self->{obj_dir}/tmp4.mem\\\"", "+define+OUT_TMP5=\\\"$Self->{obj_dir}/tmp5.mem\\\"", + "+define+OUT_TMP6=\\\"$Self->{obj_dir}/tmp6.mem\\\"", + "+define+OUT_TMP7=\\\"$Self->{obj_dir}/tmp7.mem\\\"", + "+define+OUT_TMP8=\\\"$Self->{obj_dir}/tmp8.mem\\\"", ]); execute( check_finished => 1, ); -for (my $i = 1; $i <= 5; $i++) { +for (my $i = 1; $i <= 8; $i++) { my $gold = "$Self->{t_dir}/t_sys_writemem.gold${i}.mem"; my $out = "$Self->{obj_dir}/tmp${i}.mem"; files_identical($out, $gold); diff --git a/test_regress/t/t_sys_writemem_b.gold5.mem b/test_regress/t/t_sys_writemem_b.gold5.mem index 6e4fbbfe0..be643a6da 100644 --- a/test_regress/t/t_sys_writemem_b.gold5.mem +++ b/test_regress/t/t_sys_writemem_b.gold5.mem @@ -1,14 +1,16 @@ -000010 -000011 -000100 -000101 -000110 -000111 -010000 -000000 -000000 -000000 -010100 -010101 -000000 -000000 +00000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000 +11011100101110101001100001110110010101000000000000000100 +00000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000 +11011100101110101001100001110110010101000000000000001010 +11011100101110101001100001110110010101000000000000001011 +11011100101110101001100001110110010101000000000000001100 +00000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000 diff --git a/test_regress/t/t_sys_writemem_b.gold6.mem b/test_regress/t/t_sys_writemem_b.gold6.mem new file mode 100644 index 000000000..6235fb3ce --- /dev/null +++ b/test_regress/t/t_sys_writemem_b.gold6.mem @@ -0,0 +1,16 @@ +00000000000000000000000000 +00000000000000000000000000 +00000000000000000000000000 +00000000000000000000000000 +10010101000000000000000100 +00000000000000000000000000 +00000000000000000000000000 +00000000000000000000000000 +00000000000000000000000000 +00000000000000000000000000 +10010101000000000000001010 +10010101000000000000001011 +10010101000000000000001100 +00000000000000000000000000 +00000000000000000000000000 +00000000000000000000000000 diff --git a/test_regress/t/t_sys_writemem_b.gold7.mem b/test_regress/t/t_sys_writemem_b.gold7.mem new file mode 100644 index 000000000..b54eceec6 --- /dev/null +++ b/test_regress/t/t_sys_writemem_b.gold7.mem @@ -0,0 +1,16 @@ +00000000000 +00000000000 +00000000000 +00000000000 +11001010100 +00000000000 +00000000000 +00000000000 +00000000000 +00000000000 +11001011010 +11001011011 +11001011100 +00000000000 +00000000000 +00000000000 diff --git a/test_regress/t/t_sys_writemem_b.gold8.mem b/test_regress/t/t_sys_writemem_b.gold8.mem new file mode 100644 index 000000000..6e4fbbfe0 --- /dev/null +++ b/test_regress/t/t_sys_writemem_b.gold8.mem @@ -0,0 +1,14 @@ +000010 +000011 +000100 +000101 +000110 +000111 +010000 +000000 +000000 +000000 +010100 +010101 +000000 +000000 diff --git a/test_regress/t/t_sys_writemem_b.pl b/test_regress/t/t_sys_writemem_b.pl index c5b47759f..140904bcb 100755 --- a/test_regress/t/t_sys_writemem_b.pl +++ b/test_regress/t/t_sys_writemem_b.pl @@ -24,13 +24,16 @@ compile(v_flags2 => [ "+define+OUT_TMP3=\\\"$Self->{obj_dir}/tmp3.mem\\\"", "+define+OUT_TMP4=\\\"$Self->{obj_dir}/tmp4.mem\\\"", "+define+OUT_TMP5=\\\"$Self->{obj_dir}/tmp5.mem\\\"", + "+define+OUT_TMP6=\\\"$Self->{obj_dir}/tmp6.mem\\\"", + "+define+OUT_TMP7=\\\"$Self->{obj_dir}/tmp7.mem\\\"", + "+define+OUT_TMP8=\\\"$Self->{obj_dir}/tmp8.mem\\\"", ]); execute( check_finished => 1, ); -for (my $i = 1; $i <= 5; $i++) { +for (my $i = 1; $i <= 8; $i++) { my $gold = "$Self->{t_dir}/t_sys_writemem_b.gold${i}.mem"; my $out = "$Self->{obj_dir}/tmp${i}.mem"; files_identical($out, $gold); diff --git a/test_regress/t/t_timing_class.v b/test_regress/t/t_timing_class.v index fbd4136c2..27af2dc3e 100644 --- a/test_regress/t/t_timing_class.v +++ b/test_regress/t/t_timing_class.v @@ -80,9 +80,32 @@ module t; endtask endclass + class ClkClass; + logic clk; + int count; + + function new; + clk = 0; + count = 0; + endfunction + + task flip; + clk = ~clk; + endtask; + + task count_5; + @(posedge clk) count++; + @(posedge clk) count++; + @(posedge clk) count++; + @(posedge clk) count++; + @(posedge clk) count++; + endtask + endclass + EventClass ec = new; WaitClass wc = new; LocalWaitClass lc = new; + ClkClass cc = new; initial begin @ec.e; @@ -105,8 +128,13 @@ module t; `WRITE_VERBOSE(("Event in class triggered at time %0t!\n", $time)); end + always #5 cc.flip; + + initial cc.count_5; + initial begin #80 + if (cc.count != 5) $stop; if (ec.trig_count != 3) $stop; if (!wc.ok) $stop; if (!lc.ok) $stop; @@ -219,16 +247,18 @@ module t; #10 done++; `WRITE_VERBOSE(("Forked process %0d ending at time %0t\n", done, $time)); end - begin - #20 done++; - `WRITE_VERBOSE(("Forked process %0d ending at time %0t\n", done, $time)); - d = new; - end - begin - #30 d.do_delay; - done++; - `WRITE_VERBOSE(("Forked process %0d ending at time %0t\n", done, $time)); - end + fork + begin + #20 done++; + `WRITE_VERBOSE(("Forked process %0d ending at time %0t\n", done, $time)); + d = new; + end + begin + #30 d.do_delay; + done++; + `WRITE_VERBOSE(("Forked process %0d ending at time %0t\n", done, $time)); + end + join join done++; `WRITE_VERBOSE(("All forked processes ended at time %0t\n", $time)); diff --git a/test_regress/t/t_timing_class_static_delay.pl b/test_regress/t/t_timing_class_static_delay.pl new file mode 100755 index 000000000..002312d88 --- /dev/null +++ b/test_regress/t/t_timing_class_static_delay.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_timing_class_static_delay.v b/test_regress/t/t_timing_class_static_delay.v new file mode 100644 index 000000000..8e986829e --- /dev/null +++ b/test_regress/t/t_timing_class_static_delay.v @@ -0,0 +1,30 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +`define DELAY 10 + +class Foo; + task wait_dynamically(); + #`DELAY; + endtask + + static task wait_statically(); + #`DELAY; + endtask +endclass + +module t; + Foo foo = new; + + initial begin + foo.wait_dynamically(); + if ($time != `DELAY) $stop; + Foo::wait_statically(); + if ($time != 2*`DELAY) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_timing_debug1.out b/test_regress/t/t_timing_debug1.out index 3a8e37eeb..11a893850 100644 --- a/test_regress/t/t_timing_debug1.out +++ b/test_regress/t/t_timing_debug1.out @@ -26,9 +26,9 @@ -V{t#,#}+ Vt_timing_debug1___024root___stl_sequent__TOP__2 -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__2 -V{t#,#}+ Vt_timing_debug1___024root___stl_comb__TOP__1 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___stl_comb__TOP__2 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_2__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__stl -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__stl -V{t#,#} No triggers active @@ -49,9 +49,9 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_2__0 -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__2 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act @@ -91,7 +91,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -150,7 +150,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -222,7 +222,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -276,7 +276,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_2__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 5 is active: @(posedge t.clk2) @@ -344,7 +344,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -414,7 +414,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -472,7 +472,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -542,7 +542,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -594,7 +594,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_2__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -632,7 +632,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -702,7 +702,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -754,7 +754,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -826,9 +826,9 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_2__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -932,7 +932,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -1002,7 +1002,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -1060,7 +1060,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -1130,7 +1130,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_2__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -1167,7 +1167,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -1219,7 +1219,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -1289,7 +1289,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -1341,7 +1341,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -1383,7 +1383,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_2__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 5 is active: @(posedge t.clk2) @@ -1478,7 +1478,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -1536,7 +1536,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -1606,7 +1606,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -1660,9 +1660,9 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_2__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -1732,7 +1732,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -1784,7 +1784,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active @@ -1854,7 +1854,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) @@ -1906,7 +1906,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__1 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_2__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 5 is active: @(posedge t.clk2) @@ -1976,7 +1976,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 --V{t#,#}+ Vt_timing_debug1___024root____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork_1__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act -V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act -V{t#,#} No triggers active diff --git a/test_regress/t/t_timing_debug2.out b/test_regress/t/t_timing_debug2.out index fb5698b73..61e54e3b2 100644 --- a/test_regress/t/t_timing_debug2.out +++ b/test_regress/t/t_timing_debug2.out @@ -4,6 +4,7 @@ -V{t#,#}+ Vt_timing_debug2___024unit___ctor_var_reset -V{t#,#}+ Vt_timing_debug2_t___ctor_var_reset -V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass__Vclpkg___ctor_var_reset +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass__Vclpkg___ctor_var_reset -V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay10__Vclpkg___ctor_var_reset -V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay20__Vclpkg___ctor_var_reset -V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay40__Vclpkg___ctor_var_reset @@ -31,14 +32,19 @@ -V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass::_ctor_var_reset -V{t#,#}+ Vt_timing_debug2_t__03a__03aLocalWaitClass::new -V{t#,#}+ Vt_timing_debug2_t__03a__03aLocalWaitClass::_ctor_var_reset +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::new +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::_ctor_var_reset -V{t#,#}+ Vt_timing_debug2___024root___eval_initial -V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__0 --V{t#,#} Suspending process waiting for @([event] t.ec.e) at t/t_timing_class.v:88 +-V{t#,#} Suspending process waiting for @([event] t.ec.e) at t/t_timing_class.v:111 -V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__1 -V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__2 -V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__3 -V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__4 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_count_5 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:97 -V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__5 +-V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__6 -V{t#,#}+ Vt_timing_debug2_t__03a__03aDelayClass::new -V{t#,#}+ Vt_timing_debug2_t__03a__03aDelayClass::_ctor_var_reset -V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay10::new @@ -58,26 +64,32 @@ -V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass::new -V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass::_ctor_var_reset -V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay10::__VnoInFunc_do_delay --V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__6 +-V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__7 -V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::new -V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::_ctor_var_reset -V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::__VnoInFunc_do_fork --V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::__Vfork_h########__0__0 --V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::__Vfork_h########__0__1 --V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::__Vfork_h########__0__2 --V{t#,#} Awaiting join of fork at: t/t_timing_class.v:217 --V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__7 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::__Vfork_1__0 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::__Vfork_1__1 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::__Vfork_2__0 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aForkClass::__Vfork_2__1 +-V{t#,#} Awaiting join of fork at: t/t_timing_class.v:250 +-V{t#,#} Awaiting join of fork at: t/t_timing_class.v:245 +-V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__8 +-V{t#,#}+ Vt_timing_debug2_t___eval_initial__TOP__t__9 -V{t#,#}+ Vt_timing_debug2___024root___eval_settle -V{t#,#}MTask0 starting -V{t#,#}+ Eval -V{t#,#}+ Vt_timing_debug2___024root___eval -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act --V{t#,#} No suspended processes waiting for dynamic trigger evaluation +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:97 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:97 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:97 -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} No triggers active -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#} Committing processes waiting for @([event] t.ec.e): --V{t#,#} - Process waiting at t/t_timing_class.v:88 +-V{t#,#} - Process waiting at t/t_timing_class.v:111 -V{t#,#}End-of-eval cleanup -V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step -V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions @@ -85,36 +97,57 @@ -V{t#,#}+ Eval -V{t#,#}+ Vt_timing_debug2___024root___eval -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act --V{t#,#} No suspended processes waiting for dynamic trigger evaluation +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:97 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:97 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:97 -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime()) -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 10: Process waiting at t/t_timing_class.v:96 --V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:97 --V{t#,#} Awaiting time 10: Process waiting at t/t_timing_class.v:99 --V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:109 --V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:145 --V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:219 --V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:223 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:228 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:244 +-V{t#,#} Awaiting time 5: Process waiting at t/t_timing_class.v:119 +-V{t#,#} Awaiting time 10: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 10: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:173 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:247 +-V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:252 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:257 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274 +-V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:131 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:244 --V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay10::__VnoInFunc_do_sth_else --V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay20::__VnoInFunc_do_delay --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:146 --V{t#,#} Process forked at t/t_timing_class.v:218 finished +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act --V{t#,#} No suspended processes waiting for dynamic trigger evaluation +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:97 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:97 +-V{t#,#} Process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:97 awaiting resumption +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdynSched.evaluate()) +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Resuming processes: +-V{t#,#} - Process waiting at t/t_timing_class.v:97 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:97 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:98 +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:98 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:98 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:98 -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} No triggers active -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___eval_nba -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act --V{t#,#} No suspended processes waiting for dynamic trigger evaluation +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:98 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:98 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:98 -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} No triggers active -V{t#,#}+ Vt_timing_debug2___024root___timing_commit @@ -125,44 +158,169 @@ -V{t#,#}+ Eval -V{t#,#}+ Vt_timing_debug2___024root___eval -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act --V{t#,#} No suspended processes waiting for dynamic trigger evaluation +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:98 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:98 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:98 -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime()) -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:96 --V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:97 --V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:99 --V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:109 --V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:145 --V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:219 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:223 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:228 +-V{t#,#} Awaiting time 10: Process waiting at t/t_timing_class.v:119 +-V{t#,#} Awaiting time 10: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Awaiting time 10: Process waiting at t/t_timing_class.v:173 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:247 +-V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:252 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:257 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:274 +-V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:131 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:228 --V{t#,#}+ Vt_timing_debug2_t__03a__03aForkDelayClass::new --V{t#,#}+ Vt_timing_debug2_t__03a__03aForkDelayClass::_ctor_var_reset --V{t#,#} Process forked at t/t_timing_class.v:222 finished --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:223 --V{t#,#}+ Vt_timing_debug2_t__03a__03aEventClass::__VnoInFunc_wake +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Process forked at t/t_timing_class.v:246 finished +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:274 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay10::__VnoInFunc_do_sth_else +-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay20::__VnoInFunc_do_delay +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:174 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act --V{t#,#} No suspended processes waiting for dynamic trigger evaluation +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:98 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:98 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:98 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___eval_nba +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:98 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:98 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:98 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}End-of-eval cleanup +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}MTask0 starting +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:98 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:98 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:98 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 15: Process waiting at t/t_timing_class.v:119 +-V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:173 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:247 +-V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:252 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:257 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:98 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:98 +-V{t#,#} Process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:98 awaiting resumption +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdynSched.evaluate()) +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Resuming processes: +-V{t#,#} - Process waiting at t/t_timing_class.v:98 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:98 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:99 +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:99 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:99 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:99 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___eval_nba +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:99 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:99 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:99 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}End-of-eval cleanup +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}MTask0 starting +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:99 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:99 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:99 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:119 +-V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 20: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:173 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:247 +-V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:252 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:257 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aForkDelayClass::new +-V{t#,#}+ Vt_timing_debug2_t__03a__03aForkDelayClass::_ctor_var_reset +-V{t#,#} Process forked at t/t_timing_class.v:251 finished +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:257 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aEventClass::__VnoInFunc_wake +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:252 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:99 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:99 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:99 -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 0 is active: @([event] t.ec.e) -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Ready processes waiting for @([event] t.ec.e): --V{t#,#} - Process waiting at t/t_timing_class.v:88 +-V{t#,#} - Process waiting at t/t_timing_class.v:111 -V{t#,#} Resuming processes waiting for @([event] t.ec.e) --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:88 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:111 -V{t#,#}+ Vt_timing_debug2_t__03a__03aEventClass::__VnoInFunc_sleep -V{t#,#} Suspending process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:99 +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: -V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:99 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:99 -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 -V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting the post update step -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act @@ -177,7 +335,11 @@ -V{t#,#}+ Vt_timing_debug2_t__03a__03aEventClass::__VnoInFunc_inc_trig_count -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:99 +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: -V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:99 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:99 -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 -V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting the post update step -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act @@ -195,7 +357,11 @@ -V{t#,#}+ Vt_timing_debug2___024root___eval -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:99 +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: -V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:99 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:99 -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 -V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting the post update step -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act @@ -207,22 +373,119 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:96 --V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:97 --V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:99 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:109 --V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:145 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:219 +-V{t#,#} Awaiting time 25: Process waiting at t/t_timing_class.v:119 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:173 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:247 +-V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:131 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:219 --V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay20::__VnoInFunc_do_sth_else --V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay40::__VnoInFunc_do_delay --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:147 --V{t#,#}+ Vt_timing_debug2_t__03a__03aForkDelayClass::__VnoInFunc_do_delay +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:99 +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:99 +-V{t#,#} Process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:99 awaiting resumption +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting the post update step +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdynSched.evaluate()) +-V{t#,#} Doing post updates for processes: +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Suspending process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Resuming processes: +-V{t#,#} - Process waiting at t/t_timing_class.v:99 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:99 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:100 -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: -V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:100 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting the post update step +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:100 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:100 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#} Doing post updates for processes: +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Suspending process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___eval_nba +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:100 +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:100 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:100 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting the post update step +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#} Doing post updates for processes: +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Suspending process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}End-of-eval cleanup +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}MTask0 starting +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:100 +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:100 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:100 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting the post update step +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#} Doing post updates for processes: +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Suspending process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:119 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:173 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:247 +-V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay20::__VnoInFunc_do_sth_else +-V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay40::__VnoInFunc_do_delay +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:175 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aForkDelayClass::__VnoInFunc_do_delay +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:100 +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:100 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:100 -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 -V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting the post update step -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act @@ -235,7 +498,11 @@ -V{t#,#}+ Vt_timing_debug2___024root___eval_nba -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:100 +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: -V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:100 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:100 -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 -V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting the post update step -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act @@ -253,7 +520,11 @@ -V{t#,#}+ Vt_timing_debug2___024root___eval -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:100 +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: -V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:100 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:100 -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 -V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting the post update step -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act @@ -265,18 +536,115 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:96 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:97 --V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:99 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:109 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:145 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:210 +-V{t#,#} Awaiting time 35: Process waiting at t/t_timing_class.v:119 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:173 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:247 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:238 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:210 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:238 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:100 +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:100 +-V{t#,#} Process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:100 awaiting resumption +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting the post update step +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdynSched.evaluate()) +-V{t#,#} Doing post updates for processes: +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Suspending process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Resuming processes: +-V{t#,#} - Process waiting at t/t_timing_class.v:100 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:100 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:101 -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: -V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:101 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting the post update step +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:101 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:101 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#} Doing post updates for processes: +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Suspending process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___eval_nba +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:101 +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:101 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:101 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting the post update step +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#} Doing post updates for processes: +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Suspending process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}End-of-eval cleanup +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}MTask0 starting +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:101 +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:101 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:101 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting the post update step +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#} Doing post updates for processes: +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 +-V{t#,#} Suspending process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:119 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 40: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:173 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:247 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:247 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:101 +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:37 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:101 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:101 -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:37 -V{t#,#} Process waiting for @([event] t::EventClass.e) at t/t_timing_class.v:37 awaiting the post update step -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act @@ -291,7 +659,10 @@ -V{t#,#} Resuming processes waiting for @([event] t.ec.e) -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act --V{t#,#} No suspended processes waiting for dynamic trigger evaluation +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:101 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:101 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:101 -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act -V{t#,#} 'act' region trigger index 2 is active: @([true] __VdynSched.evaluate()) -V{t#,#}+ Vt_timing_debug2___024root___timing_commit @@ -305,7 +676,11 @@ -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:101 +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: -V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:101 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:101 -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 -V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act @@ -316,7 +691,11 @@ -V{t#,#}+ Vt_timing_debug2_t__03a__03aEventClass::__VnoInFunc_inc_trig_count -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:101 +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: -V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:101 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:101 -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 -V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act @@ -330,7 +709,11 @@ -V{t#,#}+ Vt_timing_debug2___024root___eval -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:101 +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: -V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:101 +-V{t#,#} Suspending process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:101 -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 -V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 -V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act @@ -338,13 +721,32 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:96 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:97 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:99 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:109 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:145 +-V{t#,#} Awaiting time 45: Process waiting at t/t_timing_class.v:119 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:173 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:131 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:145 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:101 +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:101 +-V{t#,#} Process waiting for @(posedge t::ClkClass.clk) at t/t_timing_class.v:101 awaiting resumption +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 +-V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 2 is active: @([true] __VdynSched.evaluate()) +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Resuming processes: +-V{t#,#} - Process waiting at t/t_timing_class.v:101 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:101 -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: @@ -379,13 +781,103 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 60: Process waiting at t/t_timing_class.v:96 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:97 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:99 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:109 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:100 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:119 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 50: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:173 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:131 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:100 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:123 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 +-V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___eval_nba +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 +-V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}End-of-eval cleanup +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}MTask0 starting +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 +-V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 55: Process waiting at t/t_timing_class.v:119 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 60: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:173 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 +-V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___eval_nba +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 +-V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}End-of-eval cleanup +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}MTask0 starting +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:58 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 +-V{t#,#} Suspending process waiting for @([true] ((32'sh4 == t::WaitClass.a) & (32'sh10 < t::WaitClass.b))) at t/t_timing_class.v:58 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 60: Process waiting at t/t_timing_class.v:119 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 60: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:173 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:173 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: @@ -400,9 +892,9 @@ -V{t#,#} - Process waiting at t/t_timing_class.v:58 -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:58 -V{t#,#}+ Vt_timing_debug2_t__03a__03aLocalWaitClass::__VnoInFunc_await --V{t#,#}+ Vt_timing_debug2_t__03a__03aLocalWaitClass::__Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aLocalWaitClass::__Vfork_1__0 -V{t#,#} Suspending process waiting for @([true] ((32'sh2a == t::LocalWaitClass.a) | (32'sh64 != t::LocalWaitClass.b))) at t/t_timing_class.v:75 --V{t#,#}+ Vt_timing_debug2_t__03a__03aLocalWaitClass::__Vfork_h########__0__1 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aLocalWaitClass::__Vfork_1__1 -V{t#,#} Awaiting join of fork at: t/t_timing_class.v:74 -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act @@ -438,23 +930,71 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:96 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:97 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:99 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:109 --V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:76 +-V{t#,#} Awaiting time 65: Process waiting at t/t_timing_class.v:119 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:76 -V{t#,#} Resuming delayed processes -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:76 --V{t#,#} Process forked at t/t_timing_class.v:227 finished +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:75 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:75 +-V{t#,#} Suspending process waiting for @([true] ((32'sh2a == t::LocalWaitClass.a) | (32'sh64 != t::LocalWaitClass.b))) at t/t_timing_class.v:75 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___eval_nba +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:75 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:75 +-V{t#,#} Suspending process waiting for @([true] ((32'sh2a == t::LocalWaitClass.a) | (32'sh64 != t::LocalWaitClass.b))) at t/t_timing_class.v:75 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}End-of-eval cleanup +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}MTask0 starting +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} Suspended processes waiting for dynamic trigger evaluation: +-V{t#,#} - Process waiting at t/t_timing_class.v:75 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:75 +-V{t#,#} Suspending process waiting for @([true] ((32'sh2a == t::LocalWaitClass.a) | (32'sh64 != t::LocalWaitClass.b))) at t/t_timing_class.v:75 +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:119 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:136 +-V{t#,#} Awaiting time 70: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Process forked at t/t_timing_class.v:76 finished +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Process forked at t/t_timing_class.v:256 finished -V{t#,#} Resuming: Process waiting at (null):0 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:109 +-V{t#,#} Process forked at t/t_timing_class.v:250 finished +-V{t#,#} Resuming: Process waiting at (null):0 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:136 -V{t#,#}+ Vt_timing_debug2_t__03a__03aDelay40::__VnoInFunc_do_sth_else -V{t#,#}+ Vt_timing_debug2_t__03a__03aNoDelay::__VnoInFunc_do_delay -V{t#,#}+ Vt_timing_debug2_t__03a__03aNoDelay::__VnoInFunc_do_sth_else --V{t#,#}+ Vt_timing_debug2_t____Vfork_h########__0__0 +-V{t#,#}+ Vt_timing_debug2_t____Vfork_1__0 -V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass::__VnoInFunc_do_assign --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:162 --V{t#,#} Process forked at t/t_timing_class.v:76 finished -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} Suspended processes waiting for dynamic trigger evaluation: @@ -497,12 +1037,15 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 75: Process waiting at t/t_timing_class.v:96 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:97 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:99 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:196 +-V{t#,#} Awaiting time 75: Process waiting at t/t_timing_class.v:119 +-V{t#,#} Awaiting time 75: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:224 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:190 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:196 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:190 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} No suspended processes waiting for dynamic trigger evaluation @@ -528,14 +1071,17 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:96 --V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:97 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:99 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:119 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:122 +-V{t#,#} Awaiting time 80: Process waiting at t/t_timing_class.v:224 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:99 --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:97 --V{t#,#}+ Vt_timing_debug2_t____Vfork_h########__0__0 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:224 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:122 +-V{t#,#}+ Vt_timing_debug2_t____Vfork_2__0 -V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass::__VnoInFunc_do_assign +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:230 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} No suspended processes waiting for dynamic trigger evaluation @@ -561,11 +1107,14 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 85: Process waiting at t/t_timing_class.v:96 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:162 --V{t#,#} Awaiting time 90: Process waiting at t/t_timing_class.v:202 +-V{t#,#} Awaiting time 85: Process waiting at t/t_timing_class.v:119 +-V{t#,#} Awaiting time 85: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 90: Process waiting at t/t_timing_class.v:190 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:131 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:202 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:231 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} No suspended processes waiting for dynamic trigger evaluation @@ -591,11 +1140,14 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 90: Process waiting at t/t_timing_class.v:96 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:162 --V{t#,#} Awaiting time 100: Process waiting at t/t_timing_class.v:203 +-V{t#,#} Awaiting time 90: Process waiting at t/t_timing_class.v:119 +-V{t#,#} Awaiting time 90: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:190 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_class.v:131 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:203 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:190 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} No suspended processes waiting for dynamic trigger evaluation @@ -622,11 +1174,45 @@ -V{t#,#}+ Vt_timing_debug2___024root___timing_commit -V{t#,#}+ Vt_timing_debug2___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 100: Process waiting at t/t_timing_class.v:96 --V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:162 +-V{t#,#} Awaiting time 95: Process waiting at t/t_timing_class.v:119 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_class.v:131 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_class.v:162 +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} No suspended processes waiting for dynamic trigger evaluation +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___eval_nba +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} No suspended processes waiting for dynamic trigger evaluation +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}End-of-eval cleanup +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}MTask0 starting +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#} No suspended processes waiting for dynamic trigger evaluation +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 1 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_class.v:119 +-V{t#,#} Awaiting time 101: Process waiting at t/t_timing_class.v:120 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_class.v:131 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:131 *-* All Finished *-* +-V{t#,#} Resuming: Process waiting at t/t_timing_class.v:120 +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act -V{t#,#} No suspended processes waiting for dynamic trigger evaluation @@ -649,6 +1235,7 @@ -V{t#,#}+ Vt_timing_debug2_t__03a__03aDelayClass::~ -V{t#,#}+ Vt_timing_debug2_t__03a__03aNoDelay::~ -V{t#,#}+ Vt_timing_debug2_t__03a__03aDelayClass::~ +-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::~ -V{t#,#}+ Vt_timing_debug2_t__03a__03aLocalWaitClass::~ -V{t#,#}+ Vt_timing_debug2___024unit__03a__03aBaseClass::~ -V{t#,#}+ Vt_timing_debug2_t__03a__03aWaitClass::~ diff --git a/test_regress/t/t_timing_fork_join_forkproc.out b/test_regress/t/t_timing_fork_join_forkproc.out new file mode 100644 index 000000000..46f216b1e --- /dev/null +++ b/test_regress/t/t_timing_fork_join_forkproc.out @@ -0,0 +1,25 @@ +[0] fork..join process 4 +[2] fork..join process 3 +[4] fork..join process 2 +[8] fork..join process 1 +[16] fork in fork starts +[16] fork..join process 8 +[20] fork..join process 7 +[24] fork..join process 6 +[32] fork..join process 5 +[32] fork..join in fork ends +[64] main process +fork..join_any process 2 +back in main process +fork..join_any process 1 +fork..join_any process 1 +back in main process +fork..join_any process 2 +in main process +fork..join_none process 1 +fork..join_none process 2 +fork..join_none process 3 +fork..join_none process 2 again +fork..join_none process 1 again +fork..join_none process 3 again +*-* All Finished *-* diff --git a/test_regress/t/t_timing_fork_join_forkproc.pl b/test_regress/t/t_timing_fork_join_forkproc.pl new file mode 100755 index 000000000..61664fabe --- /dev/null +++ b/test_regress/t/t_timing_fork_join_forkproc.pl @@ -0,0 +1,26 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +top_filename("t/t_timing_fork_join.v"); + +compile( + verilator_flags2 => ["--exe --main --timing --ftaskify-all-forked"], + make_main => 0, + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_timing_fork_rec_method.pl b/test_regress/t/t_timing_fork_rec_method.pl new file mode 100755 index 000000000..b8493bd06 --- /dev/null +++ b/test_regress/t/t_timing_fork_rec_method.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_timing_fork_rec_method.v b/test_regress/t/t_timing_fork_rec_method.v new file mode 100644 index 000000000..c5ddd2d72 --- /dev/null +++ b/test_regress/t/t_timing_fork_rec_method.v @@ -0,0 +1,27 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class RecFork; + int cnt = 0; + task run(int n); + if (n > 0) begin + cnt++; + fork + run(n - 1); + join + end + endtask +endclass + +module t; + initial begin + automatic RecFork rec = new; + rec.run(7); + if (rec.cnt != 7) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_timing_fork_unsup.out b/test_regress/t/t_timing_fork_unsup.out index 39713d51f..399dfd1c3 100644 --- a/test_regress/t/t_timing_fork_unsup.out +++ b/test_regress/t/t_timing_fork_unsup.out @@ -1,34 +1,17 @@ -%Error-UNSUPPORTED: t/t_timing_fork_unsup.v:12:12: Unsupported: variable local to a forking process accessed in a fork..join_any or fork..join_none - : ... In instance t::C +%Error-LIFETIME: t/t_timing_fork_unsup.v:12:12: Invalid reference: Process might outlive variable `x`. + : ... In instance t + : ... Suggest use it as read-only to initialize a local copy at the beginning of the process, or declare it as static. It is also possible to refer by reference to objects and their members. 12 | #6 x = 4; | ^ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_timing_fork_unsup.v:13:12: Unsupported: variable local to a forking process accessed in a fork..join_any or fork..join_none - : ... In instance t::C + ... For error description see https://verilator.org/warn/LIFETIME?v=latest +%Error-LIFETIME: t/t_timing_fork_unsup.v:13:12: Invalid reference: Process might outlive variable `x`. + : ... In instance t + : ... Suggest use it as read-only to initialize a local copy at the beginning of the process, or declare it as static. It is also possible to refer by reference to objects and their members. 13 | #2 x++; | ^ -%Error-UNSUPPORTED: t/t_timing_fork_unsup.v:14:16: Unsupported: variable local to a forking process accessed in a fork..join_any or fork..join_none - : ... In instance t::C - 14 | x = #4 x * 3; - | ^ -%Error-UNSUPPORTED: t/t_timing_fork_unsup.v:14:9: Unsupported: variable local to a forking process accessed in a fork..join_any or fork..join_none - : ... In instance t::C +%Error-LIFETIME: t/t_timing_fork_unsup.v:14:9: Invalid reference: Process might outlive variable `x`. + : ... In instance t + : ... Suggest use it as read-only to initialize a local copy at the beginning of the process, or declare it as static. It is also possible to refer by reference to objects and their members. 14 | x = #4 x * 3; | ^ -%Error-UNSUPPORTED: t/t_timing_fork_unsup.v:16:18: Unsupported: variable local to a forking process accessed in a fork..join_any or fork..join_none - : ... In instance t::C - 16 | #1 if (x != 1) $stop; - | ^ -%Error-UNSUPPORTED: t/t_timing_fork_unsup.v:17:18: Unsupported: variable local to a forking process accessed in a fork..join_any or fork..join_none - : ... In instance t::C - 17 | #2 if (x != 2) $stop; - | ^ -%Error-UNSUPPORTED: t/t_timing_fork_unsup.v:18:18: Unsupported: variable local to a forking process accessed in a fork..join_any or fork..join_none - : ... In instance t::C - 18 | #2 if (x != 3) $stop; - | ^ -%Error-UNSUPPORTED: t/t_timing_fork_unsup.v:19:18: Unsupported: variable local to a forking process accessed in a fork..join_any or fork..join_none - : ... In instance t::C - 19 | #2 if (x != 4) $stop; - | ^ %Error: Exiting due to diff --git a/test_regress/t/t_timing_fork_unsup.v b/test_regress/t/t_timing_fork_unsup.v index 39c141452..72a698e6d 100644 --- a/test_regress/t/t_timing_fork_unsup.v +++ b/test_regress/t/t_timing_fork_unsup.v @@ -12,13 +12,6 @@ module t; #6 x = 4; #2 x++; x = #4 x * 3; - begin - #1 if (x != 1) $stop; - #2 if (x != 2) $stop; - #2 if (x != 3) $stop; - #2 if (x != 4) $stop; - $finish; - end join_none x = 1; endtask diff --git a/test_regress/t/t_timing_split.pl b/test_regress/t/t_timing_split.pl new file mode 100755 index 000000000..2703f4761 --- /dev/null +++ b/test_regress/t/t_timing_split.pl @@ -0,0 +1,40 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt_all => 1); + +compile( + timing_loop => 1, + verilator_flags2 => ["--timing --output-split-cfuncs 1 -CFLAGS -Werror"], + ); + +execute( + check_finished => 1, + ); + +check_splits(); + +ok(1); +1; + +sub check_splits { + my $got1; + my $gotSyms1; + return if !$Self->have_coroutines; + foreach my $file (glob("$Self->{obj_dir}/*.cpp")) { + if ($file =~ /Syms__1/) { + $gotSyms1 = 1; + } elsif ($file =~ /__1/) { + $got1 = 1; + } + } + $got1 or error("No __1 split file found"); + $gotSyms1 or error("No Syms__1 split file found"); +} diff --git a/test_regress/t/t_timing_split.v b/test_regress/t/t_timing_split.v new file mode 100644 index 000000000..f7fd5d8de --- /dev/null +++ b/test_regress/t/t_timing_split.v @@ -0,0 +1,35 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Jomit626. +// SPDX-License-Identifier: CC0-1.0 + +module t (); + logic clk = 0; + logic data = 0; + + always #5 clk <= ~clk; + + task static foo(); + @(negedge clk); + data = 1; + @(negedge clk); + data = 0; + endtask + +`define foo8()\ + foo();foo();foo();foo();foo();foo();foo();foo() + +`define foo64()\ + `foo8();`foo8();`foo8();`foo8();`foo8();`foo8();`foo8();`foo8() + +`define foo512()\ + `foo64();`foo64();`foo64();`foo64();`foo64();`foo64();`foo64();`foo64() + + initial begin + `foo512(); + `foo512(); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_timing_wait1.v b/test_regress/t/t_timing_wait1.v index bcf33dcb1..7ec77a5b4 100644 --- a/test_regress/t/t_timing_wait1.v +++ b/test_regress/t/t_timing_wait1.v @@ -14,6 +14,7 @@ module t; int a = 0; int b = 0; int c = 0; + int q[$]; initial begin `WRITE_VERBOSE("start with a==0, b==0, c==0\n"); @@ -26,7 +27,8 @@ module t; #1 c = 3; `WRITE_VERBOSE("assign 3 to c\n"); #1 c = 4; `WRITE_VERBOSE("assign 4 to c\n"); // a+bc - b = 5; + b = 5; `WRITE_VERBOSE("push_back b to q\n"); + q.push_back(b); end initial begin @@ -44,6 +46,8 @@ module t; wait(a + b < c) if (a + b >= c) $stop; `WRITE_VERBOSE("waiting for ac\n"); wait(a < b && b > c) if (a >= b || b <= c) $stop; + `WRITE_VERBOSE("waiting for q.size() > 0\n"); + wait(q.size() > 0) if (q.size() <= 0) $stop; wait(1); @@ -54,5 +58,5 @@ module t; initial wait(0) $stop; initial wait(1 == 0) $stop; - initial #11 $stop; // timeout + initial #12 $stop; // timeout endmodule diff --git a/test_regress/t/t_timing_wait3.pl b/test_regress/t/t_timing_wait3.pl new file mode 100755 index 000000000..b8493bd06 --- /dev/null +++ b/test_regress/t/t_timing_wait3.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_timing_wait3.v b/test_regress/t/t_timing_wait3.v new file mode 100644 index 000000000..d898664ea --- /dev/null +++ b/test_regress/t/t_timing_wait3.v @@ -0,0 +1,43 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + + +module t; + typedef process pr; + pr p[4]; + int n = 0; + + initial begin + wait (p[1]); + p[1].await(); + p[0] = process::self(); + if (n == 3) n++; + #2 $write("*-* All Finished *-*\n"); + $finish; + end + + initial begin + wait (p[2]); + p[2].await(); + p[1] = process::self(); + if (n == 2) n++; + end + + initial begin + wait (p[3]); + p[3].await(); + p[2] = process::self(); + if (n == 1) n++; + end + + initial begin + p[3] = process::self(); + if (n == 0) n++; + end + + initial #1 if (n != 4) $stop; + initial #3 $stop; // timeout +endmodule diff --git a/test_regress/t/t_trace_open_wrong_order_bad.cpp b/test_regress/t/t_trace_open_wrong_order_bad.cpp index 91945222f..9fac96261 100644 --- a/test_regress/t/t_trace_open_wrong_order_bad.cpp +++ b/test_regress/t/t_trace_open_wrong_order_bad.cpp @@ -11,8 +11,6 @@ #include "Vt_trace_open_wrong_order_bad.h" -using namespace std; - int main(int argc, char** argv) { VerilatedContext ctx; VerilatedVcdC tfp; diff --git a/test_regress/t/t_unpacked_struct_sel.pl b/test_regress/t/t_unpacked_struct_sel.pl new file mode 100755 index 000000000..1aa73f80a --- /dev/null +++ b/test_regress/t/t_unpacked_struct_sel.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_unpacked_struct_sel.v b/test_regress/t/t_unpacked_struct_sel.v new file mode 100644 index 000000000..b9e410d5b --- /dev/null +++ b/test_regress/t/t_unpacked_struct_sel.v @@ -0,0 +1,20 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +typedef struct { + bit [3:0] byte_en; +} my_struct; + +module t (/*AUTOARG*/); + initial begin + my_struct ms; + ms.byte_en[0] = 1; + if (ms.byte_en[0] != 1) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_urandom.v b/test_regress/t/t_urandom.v index bd865b990..99285b5c8 100644 --- a/test_regress/t/t_urandom.v +++ b/test_regress/t/t_urandom.v @@ -69,6 +69,16 @@ module t(/*AUTOARG*/); v2 = $urandom(); if (v1 != v2) $stop; + // Seed stability via process.srandom + p.srandom(32'h88888888); // "Large" seed to check a VlRNG::srandom edge case + v1 = $urandom(); + p.srandom(32'h88888888); + v2 = $urandom(); + if (v1 != v2) $stop; + p.srandom(32'h88888888); + v2 = $urandom(); + if (v1 != v2) $stop; + // Seed stability via process.get_randstate s = p.get_randstate(); v1 = $urandom(); diff --git a/test_regress/t/t_var_in_fork.pl b/test_regress/t/t_var_in_fork.pl new file mode 100755 index 000000000..b267631e9 --- /dev/null +++ b/test_regress/t/t_var_in_fork.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + verilator_flags2 => ["--timing"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_var_in_fork.v b/test_regress/t/t_var_in_fork.v new file mode 100644 index 000000000..b47ef920d --- /dev/null +++ b/test_regress/t/t_var_in_fork.v @@ -0,0 +1,53 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +int static_var; + +module t(); + event evt; + task send_event(); + ->evt; + endtask + + + class Foo; + function void do_something(int captured_var); + fork + begin + int my_var; + int my_other_var; + my_var = captured_var; + my_other_var = captured_var; /* Capture the same value "twice" */ + my_var++; + static_var++; /* Write to a value with static lifetime (valid) */ + $display("Vars in forked process: %d %d", my_var, my_other_var); + if (my_var != 2) + $stop; + if (my_other_var != 1) + $stop; + send_event(); + end + join_none + $display("Leaving fork's parent"); + endfunction + endclass + + initial begin + Foo foo; + foo = new; + static_var = 0; + foo.do_something(1); + + end + + always @(evt) begin + $display("Static variable: %d", static_var); + if (static_var != 1) + $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_verilated_all.pl b/test_regress/t/t_verilated_all.pl index 4cdd44194..990e34c5d 100755 --- a/test_regress/t/t_verilated_all.pl +++ b/test_regress/t/t_verilated_all.pl @@ -56,7 +56,6 @@ foreach my $file (sort keys %hit) { if (!$hit{$file} && $file !~ /_sc/ && $file !~ /_fst/ - && $file !~ /_heavy/ && ($file !~ /_timing/ || $Self->have_coroutines) && ($file !~ /_thread/)) { error("Include file not covered by t_verilated_all test: ", $file); diff --git a/test_regress/t/t_vlt_warn_ecode_bad.out b/test_regress/t/t_vlt_warn_ecode_bad.out new file mode 100644 index 000000000..ec0e047bf --- /dev/null +++ b/test_regress/t/t_vlt_warn_ecode_bad.out @@ -0,0 +1,7 @@ +%Error: t/t_vlt_warn_ecode_bad.vlt:9:1: Unknown error code: BADRULENAME + 9 | lint_off -rule BADRULENAME -file "t/t_vlt_warn.v" + | ^~~~~~~~ +%Error: t/t_vlt_warn_ecode_bad.vlt:10:1: Unknown error code: BADRULENAME + 10 | lint_on -rule BADRULENAME -file "t/t_vlt_warn.v" + | ^~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_vlt_warn_ecode_bad.pl b/test_regress/t/t_vlt_warn_ecode_bad.pl new file mode 100755 index 000000000..ebf322c30 --- /dev/null +++ b/test_regress/t/t_vlt_warn_ecode_bad.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2008 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t/t_vlt_warn.v"); + +lint( + verilator_flags2 => ["--lint-only t/t_vlt_warn_ecode_bad.vlt"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_vlt_warn_ecode_bad.vlt b/test_regress/t/t_vlt_warn_ecode_bad.vlt new file mode 100644 index 000000000..af0780399 --- /dev/null +++ b/test_regress/t/t_vlt_warn_ecode_bad.vlt @@ -0,0 +1,10 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2010 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`verilator_config + +lint_off -rule BADRULENAME -file "t/t_vlt_warn.v" +lint_on -rule BADRULENAME -file "t/t_vlt_warn.v" diff --git a/test_regress/t/t_vpi_get.cpp b/test_regress/t/t_vpi_get.cpp index 132d2f39d..41f3df6b4 100644 --- a/test_regress/t/t_vpi_get.cpp +++ b/test_regress/t/t_vpi_get.cpp @@ -66,7 +66,7 @@ #define CHECK_RESULT_HEX(got, exp) \ if ((got) != (exp)) { \ std::cout << std::dec << "%Error: " << FILENM << ":" << __LINE__ << std::hex \ - << ": GOT = " << (got) << " EXP = " << (exp) << endl; \ + << ": GOT = " << (got) << " EXP = " << (exp) << std::endl; \ return __LINE__; \ } diff --git a/test_regress/t/t_vpi_memory.cpp b/test_regress/t/t_vpi_memory.cpp index aded57047..66014e71d 100644 --- a/test_regress/t/t_vpi_memory.cpp +++ b/test_regress/t/t_vpi_memory.cpp @@ -167,8 +167,10 @@ void _mem_check(const char* name, int size, int left, int right, int words) { // check vpiRange TestVpiHandle iter_h = vpi_iterate(vpiRange, mem_h); TEST_CHECK_NZ(iter_h); + TEST_CHECK_EQ(vpi_get(vpiType, iter_h), vpiIterator); TestVpiHandle lcl_h = vpi_scan(iter_h); TEST_CHECK_NZ(lcl_h); + TEST_CHECK_EQ(vpi_get(vpiType, lcl_h), vpiRange); { TestVpiHandle side_h = vpi_handle(vpiLeftRange, lcl_h); TEST_CHECK_NZ(side_h); diff --git a/test_regress/t/t_vpi_unimpl.cpp b/test_regress/t/t_vpi_unimpl.cpp index 7c7f17cdf..5b85a38e8 100644 --- a/test_regress/t/t_vpi_unimpl.cpp +++ b/test_regress/t/t_vpi_unimpl.cpp @@ -98,68 +98,45 @@ int _mon_check_unimpl(p_cb_data cb_data) { // now exercise unimplemented fns vpi_get_cb_info(cb, NULL); CHECK_RESULT(callback_count, 1); + vpi_register_systf(NULL); - CHECK_RESULT(callback_count, 2); vpi_get_systf_info(NULL, NULL); - CHECK_RESULT(callback_count, 3); vpi_handle_multi(0, NULL, NULL); - CHECK_RESULT(callback_count, 4); vpi_get64(0, NULL); - CHECK_RESULT(callback_count, 5); vpi_get_delays(NULL, NULL); - CHECK_RESULT(callback_count, 6); vpi_put_delays(NULL, NULL); - CHECK_RESULT(callback_count, 7); vpi_get_value_array(NULL, NULL, NULL, 0); - CHECK_RESULT(callback_count, 8); vpi_put_value_array(NULL, NULL, NULL, 0); - CHECK_RESULT(callback_count, 9); vpi_get_time(NULL, NULL); - CHECK_RESULT(callback_count, 10); vpi_mcd_name(0); - CHECK_RESULT(callback_count, 11); vpi_compare_objects(NULL, NULL); - CHECK_RESULT(callback_count, 12); vpi_get_data(0, NULL, 0); - CHECK_RESULT(callback_count, 13); vpi_put_data(0, NULL, 0); - CHECK_RESULT(callback_count, 14); vpi_get_userdata(NULL); - CHECK_RESULT(callback_count, 15); vpi_put_userdata(NULL, NULL); - CHECK_RESULT(callback_count, 16); vpi_handle_by_multi_index(NULL, 0, NULL); - CHECK_RESULT(callback_count, 17); vpi_control(0); - CHECK_RESULT(callback_count, 18); s_vpi_time time_s; time_s.type = 0; vpi_get_time(NULL, &time_s); - CHECK_RESULT(callback_count, 19); handle = vpi_put_value(NULL, NULL, NULL, 0); - CHECK_RESULT(callback_count, 20); CHECK_RESULT(handle, 0); handle = vpi_handle(0, NULL); - CHECK_RESULT(callback_count, 21); CHECK_RESULT(handle, 0); vpi_iterate(0, NULL); - CHECK_RESULT(callback_count, 22); handle = vpi_register_cb(NULL); - CHECK_RESULT(callback_count, 23); CHECK_RESULT(handle, 0); s_cb_data cb_data_s; cb_data_s.reason = 0; // Bad handle = vpi_register_cb(&cb_data_s); - CHECK_RESULT(callback_count, 24); CHECK_RESULT(handle, 0); (void)vpi_get_str(vpiRange, clk_h); // Bad type - CHECK_RESULT(callback_count, 25); // Supported but illegal tests: // Various checks that guarded passing NULL handles @@ -171,6 +148,8 @@ int _mon_check_unimpl(p_cb_data cb_data) { cp = vpi_get_str(vpiType, NULL); CHECK_RESULT_Z(cp); vpi_release_handle(NULL); + + printf("End of main test\n"); } return 0; // Ok } diff --git a/test_regress/t/t_vpi_unimpl.v b/test_regress/t/t_vpi_unimpl.v index 464fd9f3c..b7ec59af2 100644 --- a/test_regress/t/t_vpi_unimpl.v +++ b/test_regress/t/t_vpi_unimpl.v @@ -36,6 +36,10 @@ extern "C" int mon_check(); `else status = mon_check(); `endif + if (status != 0) begin + $write("%%Error: t_vpi_unimpl.cpp:%0d: C Test failed\n", status); + $stop; + end $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_vpi_var.cpp b/test_regress/t/t_vpi_var.cpp index 470af16de..0281fb367 100644 --- a/test_regress/t/t_vpi_var.cpp +++ b/test_regress/t/t_vpi_var.cpp @@ -325,6 +325,7 @@ int _mon_check_var() { CHECK_RESULT_NZ(vh10); vpi_get_value(vh10, &tmpValue); CHECK_RESULT(tmpValue.value.integer, 4); + CHECK_RESULT(vpi_get(vpiType, vh10), vpiConstant); p = vpi_get_str(vpiType, vh10); CHECK_RESULT_CSTR(p, "vpiConstant"); } @@ -386,6 +387,12 @@ int _mon_check_varlist() { TestVpiHandle vh2 = VPI_HANDLE("sub"); CHECK_RESULT_NZ(vh2); + p = vpi_get_str(vpiName, vh2); + CHECK_RESULT_CSTR(p, "sub"); + if (TestSimulator::is_verilator()) { + p = vpi_get_str(vpiDefName, vh2); + CHECK_RESULT_CSTR(p, ""); // Unsupported + } TestVpiHandle vh10 = vpi_iterate(vpiReg, vh2); CHECK_RESULT_NZ(vh10); diff --git a/test_regress/t/t_xml_debugcheck.out b/test_regress/t/t_xml_debugcheck.out index 11a9f8501..9e7447c4c 100644 --- a/test_regress/t/t_xml_debugcheck.out +++ b/test_regress/t/t_xml_debugcheck.out @@ -543,15 +543,17 @@ - - - - - - - - - + + + + + + + + + + + @@ -578,7 +580,7 @@ - + diff --git a/test_regress/t/t_xml_flat.out b/test_regress/t/t_xml_flat.out index d7ec257c2..e17361489 100644 --- a/test_regress/t/t_xml_flat.out +++ b/test_regress/t/t_xml_flat.out @@ -53,27 +53,27 @@ - + - + - + - + - + - + @@ -88,15 +88,15 @@ - + - + - + diff --git a/test_regress/t/t_xml_flat_no_inline_mod.out b/test_regress/t/t_xml_flat_no_inline_mod.out index 228c0e8f2..d39485a05 100644 --- a/test_regress/t/t_xml_flat_no_inline_mod.out +++ b/test_regress/t/t_xml_flat_no_inline_mod.out @@ -25,11 +25,11 @@ - + - + diff --git a/test_regress/t/t_xml_flat_pub_mod.out b/test_regress/t/t_xml_flat_pub_mod.out index e659f2ba4..6257a743a 100644 --- a/test_regress/t/t_xml_flat_pub_mod.out +++ b/test_regress/t/t_xml_flat_pub_mod.out @@ -25,11 +25,11 @@ - + - + diff --git a/test_regress/t/t_xml_flat_vlvbound.out b/test_regress/t/t_xml_flat_vlvbound.out index 214b2626a..006f33f89 100644 --- a/test_regress/t/t_xml_flat_vlvbound.out +++ b/test_regress/t/t_xml_flat_vlvbound.out @@ -43,19 +43,19 @@ - + - + - + - + diff --git a/verilator-config.cmake.in b/verilator-config.cmake.in index ae36b961e..35091d5b9 100644 --- a/verilator-config.cmake.in +++ b/verilator-config.cmake.in @@ -19,8 +19,7 @@ # ###################################################################### -cmake_minimum_required(VERSION 3.12) -cmake_policy(SET CMP0074 NEW) +cmake_minimum_required(VERSION 3.13) # Prefer VERILATOR_ROOT from environment if (DEFINED ENV{VERILATOR_ROOT})