diff --git a/Changes b/Changes index 710b675db..0fae642f7 100644 --- a/Changes +++ b/Changes @@ -17,6 +17,8 @@ Verilator 5.001 devel * Fully support the Active and NBA scheduling regions as defined by the SystemVerilog standard (IEEE 1800-2017 chapter 4). This means all generated clocks are now simulated correctly (#3278, #3384). [Geza Lore, Shunyao CAD] +* Support timing controls (delays, event controls in any location, wait + statements) and forks. See docs for details. [Krzysztof Bieganski, Antmicro Ltd] Verilator 4.225 devel diff --git a/bin/verilator b/bin/verilator index f2c858558..703a09ed4 100755 --- a/bin/verilator +++ b/bin/verilator @@ -341,6 +341,7 @@ detailed descriptions of these arguments. --lib-create Create a DPI library +libext++[ext]... Extensions for finding modules --lint-only Lint, but do not make output + --main Generate a main C++ file --make Generate scripts for specified build tool -MAKEFLAGS Arguments to pass to make during --build --max-num-width Maximum number width (default: 64K) @@ -393,6 +394,8 @@ detailed descriptions of these arguments. --threads Enable multithreading --threads-dpi Enable multithreaded DPI --threads-max-mtasks Tune maximum mtask partitioning + --timing Enable timing support + --no-timing Disable timing support --timescale Sets default timescale --timescale-override Overrides all timescales --top Alias of --top-module diff --git a/ci/docker/buildenv/Dockerfile b/ci/docker/buildenv/Dockerfile index 7e6682357..7adf4b3d2 100644 --- a/ci/docker/buildenv/Dockerfile +++ b/ci/docker/buildenv/Dockerfile @@ -6,7 +6,7 @@ # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -FROM ubuntu:20.04 +FROM ubuntu:22.04 RUN apt-get update \ && DEBIAN_FRONTEND=noninteractive \ diff --git a/ci/docker/buildenv/README.rst b/ci/docker/buildenv/README.rst index 5e7110c84..3ff025fc9 100644 --- a/ci/docker/buildenv/README.rst +++ b/ci/docker/buildenv/README.rst @@ -8,7 +8,7 @@ Verilator build. It uses the following parameters: - Source revision (default: master) -- Compiler (GCC 9.3.0, clang 10.0.0, default: 9.3.0) +- Compiler (GCC 10.3.0, clang 10.0.0, default: 10.3.0) The container is published as ``verilator/verilator-buildenv`` on `docker hub diff --git a/ci/docker/run/Dockerfile b/ci/docker/run/Dockerfile index 18c40483f..fa5c98519 100644 --- a/ci/docker/run/Dockerfile +++ b/ci/docker/run/Dockerfile @@ -6,7 +6,7 @@ # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -FROM ubuntu:20.04 +FROM ubuntu:22.04 RUN apt-get update \ && DEBIAN_FRONTEND=noninteractive \ diff --git a/configure.ac b/configure.ac index 281dd64cd..19d022983 100644 --- a/configure.ac +++ b/configure.ac @@ -374,6 +374,36 @@ _MY_CXX_CHECK_OPT(CFG_CXXFLAGS_WEXTRA,-Wlogical-op) _MY_CXX_CHECK_OPT(CFG_CXXFLAGS_WEXTRA,-Wthread-safety) AC_SUBST(CFG_CXXFLAGS_WEXTRA) +# Flags for coroutine support for dynamic scheduling +_MY_CXX_CHECK_IFELSE( + -fcoroutines-ts, + [CFG_CXXFLAGS_COROUTINES="-fcoroutines-ts"], + [CFG_CXXFLAGS_COROUTINES="-fcoroutines"]) +AC_SUBST(CFG_CXXFLAGS_COROUTINES) + +# HAVE_COROUTINES +# Check if coroutines are supported at all +AC_MSG_CHECKING([whether coroutines are supported by $CXX]) +ACO_SAVE_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS $CFG_CXXFLAGS_COROUTINES" +AC_LINK_IFELSE( + [AC_LANG_PROGRAM([ +#ifdef __clang__ +#define __cpp_impl_coroutine 1 +#endif +#include + ],[[]])], + [_my_result=yes + AC_DEFINE([HAVE_COROUTINES],[1],[Defined if coroutines are supported by $CXX])], + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM([#include ],[[]])], + [_my_result=yes + AC_DEFINE([HAVE_COROUTINES],[1],[Defined if coroutines are supported by $CXX])], + [_my_result=no])]) +AC_MSG_RESULT($_my_result) +CXXFLAGS="$ACO_SAVE_CXXFLAGS" +AC_SUBST(HAVE_COROUTINES) + # Flags for compiling Verilator internals including parser always _MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-Qunused-arguments) _MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-faligned-new) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 228787d5e..5f2441d2d 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -88,6 +88,7 @@ Nathan Kohagen Nathan Myers Patrick Stewart Paul Wright +Pawel Sagan Peter Horvath Peter Monsson Philipp Wagner diff --git a/docs/gen/ex_STMTDLY_msg.rst b/docs/gen/ex_STMTDLY_msg.rst index fe19fb943..3b7c7bc69 100644 --- a/docs/gen/ex_STMTDLY_msg.rst +++ b/docs/gen/ex_STMTDLY_msg.rst @@ -1,4 +1,4 @@ .. comment: generated by t_lint_stmtdly_bad .. code-block:: - %Warning-STMTDLY: example.v:1:8 Unsupported: Ignoring delay on this delayed statement. + %Warning-STMTDLY: example.v:1:8 Ignoring delay on this statement due to --no-timing diff --git a/docs/guide/connecting.rst b/docs/guide/connecting.rst index 443702c7d..beb3ad774 100644 --- a/docs/guide/connecting.rst +++ b/docs/guide/connecting.rst @@ -94,7 +94,10 @@ commented example. Top level IO signals are read and written as members of the model. You call the model's :code:`eval()` method to evaluate the model. When the simulation is complete call the model's :code:`final()` method to execute -any SystemVerilog final blocks, and complete any assertions. See +any SystemVerilog final blocks, and complete any assertions. If using +:vlopt:`--timing`, there are two additional functions for checking if +there are any events pending in the simulation due to delays, and for +retrieving the simulation time of the next delayed event. See :ref:`Evaluation Loop`. @@ -440,10 +443,24 @@ there is only a single design, you would call :code:`eval_step()` then :code:`eval_end_step()`; in fact :code:`eval()` described above is just a wrapper which calls these two functions. +3. If using delays and :vlopt:`--timing`, there are two additional methods +the user should call: + + * :code:`designp->eventsPending()`, which returns :code:`true` if there are + any delayed events penging, + * :code:`designp->nextTimeSlot()`, which returns the simulation time of the + next delayed event. This method can only be called if + :code:`designp->nextTimeSlot()` returned :code:`true`. +Call :code:`eventsPending()` to check if you should continue with the +simulation, and then :code:`nextTimeSlot()` to move simulation time forward. +:vlopt:`--main` can be used with :vlopt:`--timing` to generate a basic example +of a timing-enabled eval loop. + When :code:`eval()` (or :code:`eval_step()`) is called Verilator looks for changes in clock signals and evaluates related sequential always blocks, -such as computing always_ff @ (posedge...) outputs. Then Verilator -evaluates combinatorial logic. +such as computing always_ff @ (posedge...) outputs. With :vlopt:`--timing`, it +resumes any delayed processes awaiting the current simulation time. Then +Verilator evaluates combinational logic. Note combinatorial logic is not computed before sequential always blocks are computed (for speed reasons). Therefore it is best to set any non-clock diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index ae1d2af79..25891aa32 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -684,6 +684,16 @@ Summary: If the design is not to be completely Verilated see also the :vlopt:`--bbox-sys` and :vlopt:`--bbox-unsup` options. +.. option:: --main + + Generates a simple main C++ file. Without :vlopt:`--timing`, you need to + modify this file to provide some stimuli to the design. However, this option + is especially useful with :vlopt:`--timing` and delay-generated clocks, as + then the main file provides a timing-enabled eval loop and requires no + modification by the user. :vlopt:`--build` can then be used to build the + simulation, allowing you to use Verilator without directly invoking + the C++ toolchain. + .. option:: --make Generates a script for the specified build tool. @@ -1164,6 +1174,16 @@ Summary: module. As "1fs" is the finest time precision it may be desirable to always use a precision of "1fs". +.. option:: --timing + +.. option:: --no-timing + + Enables/disables support for timing constructs such as delays, event + controls (unless it's at the top of a process), wait statements, and joins. + When disabled, timing control constructs are ignored the same way as they + were in earlier versions of Verilator. Enabling this feature requires a C++ + compiler with coroutine support (GCC 10, Clang 5, or newer). + .. option:: --top .. option:: --top-module @@ -1747,6 +1767,19 @@ The grammar of configuration commands is as follows: Same as :option:`/*verilator&32;split_var*/` metacomment. +.. option:: timing_on [-file "" [-lines [ - ]]] + +.. option:: timing_off [-file "" [-lines [ - ]]] + + Enables/disables timing constructs for the specified file and lines. + When disabled, all timing control constructs in the specified source + code locations are ignored the same way as with the + :option:`--no-timing`, and code:`fork`/:code:`join*` blocks are + converted into :code:`begin`/:code:`end` blocks. + + Same as :option:`/*verilator&32;timing_on*/`, + :option:`/*verilator&32;timing_off*/` metacomments. + .. option:: tracing_on [-file "" [-lines [ - ]]] .. option:: tracing_off [-file "" [-lines [ - ]]] diff --git a/docs/guide/extensions.rst b/docs/guide/extensions.rst index 230bbac69..f353f6f43 100644 --- a/docs/guide/extensions.rst +++ b/docs/guide/extensions.rst @@ -505,6 +505,22 @@ or "`ifdef`"'s may break other tools. Verilator) text that should be passed through to the XML output as a tag, for use by downstream applications. +.. option:: /*verilator&32;timing_off*/ + + Ignore all timing constructs after this metacomment. All timing controls + behave as if they were not there (the same way as with + :option:`--no-timing`), and :code:`fork`/:code:`join*` blocks are + converted into :code:`begin`/:code:`end` blocks. + + Same as :option:`timing_off` configuration file option. + +.. option:: /*verilator&32;timing_on*/ + + Re-enable all timing constructs after this metacomment (only applicable + after :option:`timing_off`). + + Same as :option:`timing_on` configuration file option. + .. option:: /*verilator&32;trace_init_task*/ Attached to a DPI import to indicate that function should be called when diff --git a/docs/guide/languages.rst b/docs/guide/languages.rst index 063ebad78..e600dc314 100644 --- a/docs/guide/languages.rst +++ b/docs/guide/languages.rst @@ -95,6 +95,72 @@ keywords on case statement, as well as "unique" on if statements. However, "priority if" is currently ignored. +Time +==== + +With :vlopt:`--timing`, all timing controls are supported: + +* delay statements, +* event control statements not only at the top of a process, +* intra-assignment timing controls, +* net delays, +* :code:`wait` statements, + +as well as all flavors of :code:`fork`. + +Compiling a verilated design that makes use of these features requires a +compiler with C++20 coroutine support, e.g. Clang 5, GCC 10, or newer. + +:code:`#0` delays cause Verilator to issue the :option:`ZERODLY` warning, as +they work differently than described in the LRM. They do not schedule process +resumption in the Inactive region, though the process will get resumed in the +same time slot. + +Rising/falling/turn-off delays are currently unsupported and cause the +:option:`RISEFALLDLY` warning. + +Minimum/typical/maximum delays are currently unsupported. The typical delay is +always the one chosen. Such expressions cause the :option:`MINTYPMAX` warning. + +Another consequence of using :vlopt:`--timing` is that the :vlopt:`--main` +option generates a main file with a proper timing eval loop, eliminating the +need for writing any driving C++ code. You can then simply compile the +simulation (perhaps using :vlopt:`--build`) and run it. + +With :vlopt:`--no-timing`, all timing controls cause the :option:`NOTIMING` +error, with the exception of: + +* delay statements – they are ignored (as they are in synthesis), though they + do issue a :option:`STMTDLY` warning, +* intra-assignment timing controls – they are ignored, though they do issue an + :option:`ASSIGNDLY` warning, +* net delays – they are ignored, +* event controls at the top of the procedure, + +Forks cause this error as well, with the exception of: + +* forks with no statements, +* :code:`fork..join` or :code:`fork..join_any` with one statement, +* forks with :vlopt:`--bbox-unsup`. + +If neither :vlopt:`--timing` nor :vlopt:`--no-timing` is specified, all timing +controls cause the :option:`NEEDTIMINGOPT` error, with the exception of event +controls at the top of the process. Forks cause this error as well, with the +exception of: + +* forks with no statements, +* :code:`fork..join` or :code:`fork..join_any` with one statement, +* forks with :vlopt:`--bbox-unsup`. + +Timing controls and forks can also be ignored in specific files or parts of +files. The :option:`/*verilator&32;timing_off*/` and +:option:`/*verilator&32;timing_off*/` metacomments will make Verilator ignore +the encompassed timing controls and forks, regardless of the chosen +:vlopt:`--timing` or :vlopt:`--no-timing` option. This can also be achieved +using the :option:`timing_off` and :option:`timing_off` options in Verilator +configuration files. + + .. _Language Limitations: Language Limitations @@ -180,12 +246,6 @@ structure from blocking, and another from non-blocking assignments is unsupported. -Time ----- - -All delays (#) are ignored, as they are in synthesis. - - .. _Unknown States: Unknown States diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst index 1b7026d4f..a94898a10 100644 --- a/docs/guide/warnings.rst +++ b/docs/guide/warnings.rst @@ -112,6 +112,8 @@ List Of Warnings simulators, however at one point this was a common style so disabled by default as a code style warning. + This warning is issued only if Verilator is run with :vlopt:`--no-timing`. + .. option:: ASSIGNIN @@ -503,9 +505,10 @@ List Of Warnings constructs (e.g. always_ff and always_latch). Another way DIDNOTCONVERGE may occur is if # delays are used to generate - clocks. Verilator ignores the delays and gives an :option:`ASSIGNDLY` - or :option:`STMTDLY` warning. If these were suppressed, due to the - absence of the delay, the code may now oscillate. + clocks if Verilator is run with :vlopt:`--no-timing`. In this mode, + Verilator ignores the delays and gives an :option:`ASSIGNDLY` or + :option:`STMTDLY` warning. If these were suppressed, due to the absence of + the delay, the code may now oscillate. Finally, rare, more difficult cases can be debugged like a C++ program; either enter :command:`gdb` and use its tracing facilities, or edit the @@ -700,9 +703,9 @@ List Of Warnings Warns that a while or for statement has a condition that is always true. and thus results in an infinite loop if the statement ever executes. - This might be unintended behavior if the loop body contains statements - that in other simulators would make time pass, which Verilator is - ignoring due to e.g. ``STMTDLY`` warnings being disabled. + This might be unintended behavior if Verilator is run with + :vlopt:`--no-timing` and the loop body contains statements that would make + time pass otherwise. Ignoring this warning will only suppress the lint check, it will simulate correctly (i.e. hang due to the infinite loop). @@ -763,6 +766,16 @@ List Of Warnings simulate correctly. +.. option:: MINTYPMAX + + .. code-block:: sv + + #(3:5:8) clk = ~clk; + + Warns that minimum, typical, and maximum delay expressions are currently + unsupported. Only the typical delay value is used by Verilator. + + .. option:: MODDUP .. TODO better example @@ -833,6 +846,13 @@ List Of Warnings input. +.. option:: NEEDTIMINGOPT + + Error when a timing-related construct, such as an event control or delay, + has been encountered, without specifying how Verilator should handle it + (neither :vlopt:`--timing` nor :vlopt:`--no-timing` option was provided). + + .. option:: NOLATCH .. TODO better example @@ -845,6 +865,13 @@ List Of Warnings simulate correctly. +.. option:: NOTIMING + + Error when a timing-related construct that requires :vlopt:`--timing` has + been encountered. Issued only if Verilator is run with the + :vlopt:`--no-timing` option. + + .. option:: NULLPORT Warns that a null port was detected in the module definition port @@ -1082,6 +1109,16 @@ List Of Warnings "Duplicate macro arguments with name". +.. option:: RISEFALLDLY + + .. code-block:: sv + + and #(1,2,3) AND (out, a, b); + + Warns that rising, falling, and turn-off delays are currently unsupported. + The first (rising) delay is used for all cases. + + .. option:: SELRANGE Warns that a selection index will go out of bounds. @@ -1181,11 +1218,11 @@ List Of Warnings .. include:: ../../docs/gen/ex_STMTDLY_msg.rst - This is a warning because Verilator does not support delayed statements. - It will ignore all such delays. In many cases ignoring a delay might be - harmless, but if the delayed statement is, as in this example, used to - cause some important action at a later time, it might be an important - difference. + This warning is issued only if Verilator is run with :vlopt:`--no-timing`. + All delays on statements are ignored in this mode. In many cases ignoring a + delay might be harmless, but if the delayed statement is, as in this + example, used to cause some important action at a later time, it might be an + important difference. Some possible workarounds: @@ -1195,6 +1232,8 @@ List Of Warnings * Convert the statement into a FSM, or other statement that tests against $time. + * Run Verilator with :vlopt:`--timing`. + .. option:: SYMRSVDWORD @@ -1576,6 +1615,16 @@ List Of Warnings To resolve, rename the variable to a unique name. +.. option:: WAITCONST + + .. code-block:: sv + + wait(0); // Blocks forever + + Warns that a `wait` statement awaits a constant condition, which means it + either blocks forever or never blocks. + + .. option:: WIDTH Warns that based on width rules of Verilog: @@ -1645,6 +1694,14 @@ List Of Warnings width to the parameter usage (:code:`{PAR[31:0], PAR[31:0]}`). +.. option:: ZERODLY + + Warns that `#0` delays do not schedule the process to be resumed in the + Inactive region. Such processes do get resumed in the same time slot + somewhere in the Active region. Issued only if Verilator is run with the + :vlopt:`--timing` option. + + Historical Warnings =================== diff --git a/docs/internals.rst b/docs/internals.rst index 104f18503..09a88bc5b 100644 --- a/docs/internals.rst +++ b/docs/internals.rst @@ -504,6 +504,189 @@ the top level `_eval` function, which on the high level has the form: } +Timing +------ + +Timing support in Verilator utilizes C++ coroutines, which is a new feature in +C++20. The basic idea is to represent processes and tasks that await a certain +event or simulation time as coroutines. These coroutines get suspended at the +await, and resumed whenever the triggering event occurs, or at the expected +simulation time. + +There are several runtime classes used for managing such coroutines defined in +``verilated_timing.h`` and ``verilated_timing.cpp``. + +``VlCoroutineHandle`` +^^^^^^^^^^^^^^^^^^^^^ + +A thin wrapper around an ``std::coroutine_handle<>``. It forces move semantics, +destroys the coroutine if it remains suspended at the end of the design's +lifetime, and prevents multiple ``resume`` calls in the case of +``fork..join_any``. + +``VlCoroutine`` +^^^^^^^^^^^^^^^ + +Return value of all coroutines. Together with the promise type contained +within, it allows for chaining coroutines – resuming coroutines from up the +call stack. The calling coroutine's handle is saved in the promise object as a +continuation, that is, the coroutine that must be resumed after the promise's +coroutine finishes. This is necessary as C++ coroutines are stackless, meaning +each one is suspended independently of others in the call graph. + +``VlDelayScheduler`` +^^^^^^^^^^^^^^^^^^^^ + +This class manages processes suspended by delays. There is one instance of this +class per design. Coroutines ``co_await`` this object's ``delay`` function. +Internally, they are stored in a heap structure sorted by simulation time in +ascending order. When ``resume`` is called on the delay scheduler, all +coroutines awaiting the current simulation time are resumed. The current +simulation time is retrieved from a ``VerilatedContext`` object. + +``VlTriggerScheduler`` +^^^^^^^^^^^^^^^^^^^^^^ + +This class manages processes that await events (triggers). There is one such +object per each trigger awaited by coroutines. Coroutines ``co_await`` this +object's ``trigger`` function. They are stored in two stages – `uncommitted` +and `ready`. First, they land in the `uncommitted` stage, and cannot be +resumed. The ``resume`` function resumes all coroutines from the `ready` stage +and moves `uncommitted` coroutines into `ready`. The ``commit`` function only +moves `uncommitted` coroutines into `ready`. + +This split is done to avoid self-triggering and triggering coroutines multiple +times. See the `Scheduling with timing` section for details on how this is +used. + +``VlForkSync`` +^^^^^^^^^^^^^^ + +Used for synchronizing ``fork..join`` and ``fork..join_any``. Forking +coroutines ``co_await`` its ``join`` function, and forked ones call ``done`` +when they're finished. Once the required number of coroutines (set using +``setCounter``) finish execution, the forking coroutine is resumed. + +Awaitable utilities +^^^^^^^^^^^^^^^^^^^ + +There are also two small utility awaitable types: + +* ``VlNow`` is an awaitable that suspends and immediately resumes coroutines. + It is used for forcing a coroutine to be moved onto the heap. See the `Forks` + section for more detail. +* ``VlForever`` is used for blocking a coroutine forever. See the `Timing pass` + section for more detail. + +Timing pass +^^^^^^^^^^^ + +The visitor in ``V3Timing.cpp`` transforms each timing control into a ``co_await``. + +* event controls are turned into ``co_await`` on a trigger scheduler's + ``trigger`` method. The awaited trigger scheduler is the one corresponding to + the sentree referenced by the event control. This sentree is also referenced + by the ``AstCAwait`` node, to be used later by the static scheduling code. +* delays are turned into ``co_await`` on a delay scheduler's ``delay`` method. + The created ``AstCAwait`` nodes also reference a special sentree related to + delays, to be used later by the static scheduling code. +* ``join`` and ``join_any`` are turned into ``co_await`` on a ``VlForkSync``'s + ``join`` method. Each forked process gets a ``VlForkSync::done`` call at the + end. + +Assignments with intra-assignment timing controls are simplified into +assignments after those timing controls, with the LHS and RHS values evaluated +before them and stored in temporary variables. + +``wait`` statements are transformed into while loops that check the condition +and then await changes in variables used in the condition. If the condition is +always false, the ``wait`` statement is replaced by a ``co_await`` on a +``VlForever``. This is done instead of a return in case the ``wait`` is deep in +a call stack (otherwise the coroutine's caller would continue execution). + +Each sub-statement of a ``fork`` is put in an ``AstBegin`` node for easier +grouping. In a later step, each of these gets transformed into a new, separate +function. See the `Forks` section for more detail. + +Processes that use awaits are marked as suspendable. Later, during ``V3Sched``, +they are transformed into coroutines. Functions that use awaits get the return +type of ``VlCoroutine``. This immediately makes them coroutines. Note that if a +process calls a function that is a coroutine, the call gets wrapped in an +await, which means the process itself will be marked as suspendable. A virtual +function is a coroutine if any of its overriding or overridden functions are +coroutines. The visitor keeps a dependency graph of functions and processes to +handle such cases. + +Scheduling with timing +^^^^^^^^^^^^^^^^^^^^^^ + +Timing features in Verilator are built on top of the static scheduler. Triggers +are used for determining which delay or trigger schedulers should resume. A +special trigger is used for the delay scheduler. This trigger is set if there +are any coroutines awaiting the current simulation time +(``VlDelayScheduler::awaitingCurrentTime()``). + +All triggers used by a suspendable process are mapped to variables written in +that process. When ordering code using ``V3Order``, these triggers are provided +as external domains of these variables. This ensures that the necessary +combinational logic is triggered after a coroutine resumption. + +There are two functions for managing timing logic called by ``_eval()``: + +* ``_timing_commit()``, which commits all coroutines whose triggers were not set + in the current iteration, +* ``_timing_resume()``, which calls `resume()` on all trigger and delay + schedulers whose triggers were set in the current iteration. + +Thanks to this separation, a coroutine awaiting a trigger cannot be suspended +and resumed in the same iteration, and it cannot be resumed before it suspends. + +All coroutines are committed and resumed in the 'act' eval loop. With timing +features enabled, the ``_eval()`` function takes this form: + +:: + void _eval() { + while (true) { + _eval__triggers__ico(); + if (!ico_triggers.any()) break; + _eval_ico(); + } + + while (true) { + while (true) { + _eval__triggers__act(); + + // Commit all non-triggered coroutines + _timing_commit(); + + if (!act_triggers.any()) break; + latch_act_triggers_for_nba(); + + // Resume all triggered coroutines + _timing_resume(); + + _eval_act(); + } + if (!nba_triggers.any()) break; + _eval_nba(); + } + } + +Forks +^^^^^ + +After the scheduling step, forks sub-statements are transformed into separate +functions, and these functions are called in place of the sub-statements. These +calls must be without ``co_await``, so that suspension of a forked process +doesn't suspend the forking process. + +In forked processes, references to local variables are only allowed in +``fork..join``, as this is the only case that ensures the lifetime of these +locals is at least as long as the execution of the forked processes. This is +where ``VlNow`` is used, to ensure the locals are moved to the heap before they +are passed by reference to the forked processes. + + Multithreaded Mode ------------------ diff --git a/include/verilated.mk.in b/include/verilated.mk.in index c86e93676..b01799dfb 100644 --- a/include/verilated.mk.in +++ b/include/verilated.mk.in @@ -27,6 +27,8 @@ CFG_CXXFLAGS_STD_NEWEST = @CFG_CXXFLAGS_STD_NEWEST@ CFG_CXXFLAGS_NO_UNUSED = @CFG_CXXFLAGS_NO_UNUSED@ # Compiler flags that turn on extra warnings CFG_CXXFLAGS_WEXTRA = @CFG_CXXFLAGS_WEXTRA@ +# Compiler flags that enable coroutine support +CFG_CXXFLAGS_COROUTINES = @CFG_CXXFLAGS_COROUTINES@ # Linker libraries for multithreading CFG_LDLIBS_THREADS = @CFG_LDLIBS_THREADS@ @@ -142,6 +144,12 @@ ifneq ($(VM_THREADS),0) endif endif +ifneq ($(VM_TIMING),0) + ifneq ($(VM_TIMING),) + CPPFLAGS += $(CFG_CXXFLAGS_COROUTINES) + endif +endif + ifneq ($(VK_C11),0) ifneq ($(VK_C11),) # Need C++11 at least, so always default to newest diff --git a/include/verilated_timing.cpp b/include/verilated_timing.cpp new file mode 100644 index 000000000..8c0da322e --- /dev/null +++ b/include/verilated_timing.cpp @@ -0,0 +1,180 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Code available from: https://verilator.org +// +// 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 +// +//========================================================================= +/// +/// \file +/// \brief Verilated timing implementation code +/// +/// This file must be compiled and linked against all Verilated objects +/// that use timing features. +/// +/// See the internals documentation docs/internals.rst for details. +/// +//========================================================================= + +#include "verilated_timing.h" + +//====================================================================== +// VlCoroutineHandle:: Methods + +void VlCoroutineHandle::resume() { + // Only null if we have a fork..join_any and one of the other child processes resumed the + // main process + if (VL_LIKELY(m_coro)) { + VL_DEBUG_IF(VL_DBG_MSGF(" Resuming: "); dump();); + m_coro(); + m_coro = nullptr; + } +} + +#ifdef VL_DEBUG +void VlCoroutineHandle::dump() { + VL_DEBUG_IF(VL_PRINTF("Process waiting at %s:%d\n", m_filename, m_linenum);); +} +#endif + +//====================================================================== +// VlDelayScheduler:: Methods + +#ifdef VL_DEBUG +void VlDelayScheduler::VlDelayedCoroutine::dump() { + VL_DEBUG_IF(VL_DBG_MSGF(" Awaiting time %lu: ", m_timestep);); + m_handle.dump(); +} +#endif + +void VlDelayScheduler::resume() { +#ifdef VL_DEBUG + dump(); + VL_DEBUG_IF(VL_DBG_MSGF(" Resuming delayed processes\n");); +#endif + while (awaitingCurrentTime()) { + if (m_queue.front().m_timestep != m_context.time()) { + VL_FATAL_MT(__FILE__, __LINE__, "", + "%Error: Encountered process that should've been resumed at an " + "earlier simulation time. Missed a time slot?"); + } + // Move max element in the heap to the end + std::pop_heap(m_queue.begin(), m_queue.end()); + VlCoroutineHandle handle = std::move(m_queue.back().m_handle); + m_queue.pop_back(); + handle.resume(); + } +} + +uint64_t VlDelayScheduler::nextTimeSlot() { + if (empty()) { + VL_FATAL_MT(__FILE__, __LINE__, "", "%Error: There is no next time slot scheduled"); + } + return m_queue.front().m_timestep; +} + +#ifdef VL_DEBUG +void VlDelayScheduler::dump() { + if (m_queue.empty()) { + VL_DEBUG_IF(VL_DBG_MSGF(" No delayed processes:\n");); + } else { + VL_DEBUG_IF(VL_DBG_MSGF(" Delayed processes:\n");); + for (auto& susp : m_queue) susp.dump(); + } +} +#endif + +//====================================================================== +// VlTriggerScheduler:: Methods + +void VlTriggerScheduler::resume(const char* eventDescription) { +#ifdef VL_DEBUG + dump(eventDescription); + VL_DEBUG_IF(VL_DBG_MSGF(" Resuming processes waiting for %s\n", eventDescription);); +#endif + for (auto& susp : m_ready) susp.resume(); + m_ready.clear(); + commit(eventDescription); +} + +void VlTriggerScheduler::commit(const char* eventDescription) { +#ifdef VL_DEBUG + if (!m_uncommitted.empty()) { + VL_DEBUG_IF( + VL_DBG_MSGF(" Committing processes waiting for %s:\n", eventDescription); + for (auto& susp + : m_uncommitted) { + VL_DBG_MSGF(" - "); + susp.dump(); + }); + } +#endif + m_ready.reserve(m_ready.size() + m_uncommitted.size()); + m_ready.insert(m_ready.end(), std::make_move_iterator(m_uncommitted.begin()), + std::make_move_iterator(m_uncommitted.end())); + m_uncommitted.clear(); +} + +#ifdef VL_DEBUG +void VlTriggerScheduler::dump(const char* eventDescription) { + if (m_ready.empty()) { + VL_DEBUG_IF( + VL_DBG_MSGF(" No ready processes waiting for %s\n", eventDescription);); + } else { + VL_DEBUG_IF(for (auto& susp + : m_ready) { + VL_DBG_MSGF(" Ready processes waiting for %s:\n", eventDescription); + VL_DBG_MSGF(" - "); + susp.dump(); + }); + } + if (!m_uncommitted.empty()) { + VL_DEBUG_IF( + VL_DBG_MSGF(" Uncommitted processes waiting for %s:\n", eventDescription); + for (auto& susp + : m_uncommitted) { + VL_DBG_MSGF(" - "); + susp.dump(); + }); + } +} +#endif + +//====================================================================== +// VlForkSync:: Methods + +void VlForkSync::done(const char* filename, int linenum) { + VL_DEBUG_IF(VL_DBG_MSGF(" Process forked at %s:%d finished", filename, linenum);); + if (m_join->m_counter > 0) m_join->m_counter--; + if (m_join->m_counter == 0) m_join->m_susp.resume(); +} + +//====================================================================== +// VlCoroutine:: Methods + +VlCoroutine::VlPromise::~VlPromise() { + // Indicate to the return object that the coroutine has finished or been destroyed + if (m_corop) m_corop->m_promisep = nullptr; + // If there is a continuation, destroy it + if (m_continuation) m_continuation.destroy(); +} + +std::suspend_never VlCoroutine::VlPromise::final_suspend() noexcept { + // Indicate to the return object that the coroutine has finished + if (m_corop) { + m_corop->m_promisep = nullptr; + // Forget the return value, we won't need it and it won't be able to let us know if + // it's destroyed + m_corop = nullptr; + } + // If there is a continuation, resume it + if (m_continuation) { + m_continuation(); + m_continuation = nullptr; + } + return {}; +} diff --git a/include/verilated_timing.h b/include/verilated_timing.h new file mode 100644 index 000000000..f7fd2ae3f --- /dev/null +++ b/include/verilated_timing.h @@ -0,0 +1,354 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Code available from: https://verilator.org +// +// 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 +// +//************************************************************************* +/// +/// \file +/// \brief Verilated timing header +/// +/// This file is included automatically by Verilator in some of the C++ files +/// it generates if timing features are used. +/// +/// This file is not part of the Verilated public-facing API. +/// It is only for internal use. +/// +/// See the internals documentation docs/internals.rst for details. +/// +//************************************************************************* +#ifndef VERILATOR_VERILATED_TIMING_H_ +#define VERILATOR_VERILATED_TIMING_H_ + +#include "verilated.h" + +// clang-format off +// Some preprocessor magic to support both Clang and GCC coroutines with both libc++ and libstdc++ +#ifdef __clang__ +# if __clang_major__ < 14 +# ifdef __GLIBCXX__ // Using stdlibc++ +# define __cpp_impl_coroutine 1 // Clang doesn't define this, but it's needed for libstdc++ +# include + namespace std { // Bring coroutine library into std::experimental, as Clang < 14 expects it to be there + namespace experimental { + using namespace std; + } + } +# else // Using libc++ +# include // Clang older than 14, coroutines are under experimental + namespace std { + using namespace experimental; // Bring std::experimental into the std namespace + } +# endif +# else // Clang >= 14 +# if __GLIBCXX__ // Using stdlibc++ +# define __cpp_impl_coroutine 1 // Clang doesn't define this, but it's needed for libstdc++ +# endif +# include +# endif +#else // Not Clang +# include +#endif +// clang-format on + +//============================================================================= +// 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 +// suspended, another VlCoroutineHandle was created to manage it. + +class VlCoroutineHandle final { + VL_UNCOPYABLE(VlCoroutineHandle); + + // MEMBERS + std::coroutine_handle<> m_coro; // The wrapped coroutine handle +#ifdef VL_DEBUG + const char* m_filename; + int m_linenum; +#endif + +public: + // CONSTRUCTORS + // Construct + VlCoroutineHandle(std::coroutine_handle<> coro = nullptr, const char* filename = nullptr, + int linenum = 0) + : m_coro { + coro + } +#ifdef VL_DEBUG + , m_filename{filename}, m_linenum { linenum } +#endif + {} + // Move the handle, leaving a nullptr + VlCoroutineHandle(VlCoroutineHandle&& moved) + : m_coro { + std::exchange(moved.m_coro, nullptr) + } +#ifdef VL_DEBUG + , m_filename{moved.m_filename}, m_linenum { moved.m_linenum } +#endif + {} + // Destroy if the handle isn't null + ~VlCoroutineHandle() { + // Usually these coroutines should get resumed; we only need to clean up if we destroy a + // model with some coroutines suspended + if (VL_UNLIKELY(m_coro)) m_coro.destroy(); + } + // METHODS + // Move the handle, leaving a null handle + auto& operator=(VlCoroutineHandle&& moved) { + m_coro = std::exchange(moved.m_coro, nullptr); + return *this; + } + // Resume the coroutine if the handle isn't null + void resume(); +#ifdef VL_DEBUG + void dump(); +#endif +}; + +//============================================================================= +// VlDelayScheduler stores coroutines to be resumed at a certain simulation time. If the current +// time is equal to a coroutine's resume time, the coroutine gets resumed. + +class VlDelayScheduler final { + // TYPES + struct VlDelayedCoroutine { + uint64_t m_timestep; // Simulation time when the coroutine should be resumed + VlCoroutineHandle m_handle; // The suspended coroutine to be resumed + + // Comparison operator for std::push_heap(), std::pop_heap() + bool operator<(const VlDelayedCoroutine& other) const { + return m_timestep > other.m_timestep; + } +#ifdef VL_DEBUG + void dump(); +#endif + }; + using VlDelayedCoroutineQueue = std::vector; + + // MEMBERS + VerilatedContext& m_context; + VlDelayedCoroutineQueue m_queue; // Coroutines to be restored at a certain simulation time + +public: + // CONSTRUCTORS + VlDelayScheduler(VerilatedContext& context) + : m_context{context} {} + // METHODS + // Resume coroutines waiting for the current simulation time + void resume(); + // Returns the simulation time of the next time slot (aborts if there are no delayed + // coroutines) + uint64_t nextTimeSlot(); + // Are there no delayed coroutines awaiting? + bool empty() { return m_queue.empty(); } + // Are there coroutines to resume at the current simulation time? + bool awaitingCurrentTime() { + return !empty() && m_queue.front().m_timestep <= m_context.time(); + } +#ifdef VL_DEBUG + void dump(); +#endif + // Used by coroutines for co_awaiting a certain simulation time + auto delay(uint64_t delay, const char* filename, int linenum) { + struct Awaitable { + VlDelayedCoroutineQueue& queue; + uint64_t delay; +#ifdef VL_DEBUG + const char* filename; + int linenum; +#endif + bool await_ready() { return false; } // Always suspend + void await_suspend(std::coroutine_handle<> coro) { +#ifdef VL_DEBUG + queue.push_back({delay, VlCoroutineHandle{coro, filename, linenum}}); +#else + queue.push_back({delay, coro}); +#endif + // Move last element to the proper place in the max-heap + std::push_heap(queue.begin(), queue.end()); + } + void await_resume() {} + }; +#ifdef VL_DEBUG + return Awaitable{m_queue, m_context.time() + delay, filename, linenum}; +#else + return Awaitable{m_queue, m_context.time() + delay}; +#endif + } +}; + +//============================================================================= +// VlTriggerScheduler stores coroutines to be resumed by a trigger. It does not keep track of its +// trigger, relying on calling code to resume when appropriate. Coroutines are kept in two stages +// - 'uncommitted' and 'ready'. Whenever a coroutine is suspended, it lands in the 'uncommited' +// stage. Only when commit() is called, these coroutines get moved to the 'ready' stage. That's +// when they can be resumed. This is done to avoid resuming processes before they start waiting. + +class VlTriggerScheduler final { + // TYPES + using VlCoroutineVec = std::vector; + + // MEMBERS + VlCoroutineVec m_uncommitted; // Coroutines suspended before commit() was called + // (not resumable) + VlCoroutineVec m_ready; // Coroutines that can be resumed (all coros from m_uncommitted are + // moved here in commit()) + +public: + // METHODS + // Resumes all coroutines from the 'ready' stage + void resume(const char* eventDescription); + // Moves all coroutines from m_uncommitted to m_ready + void commit(const char* eventDescription); + // Are there no coroutines awaiting? + bool empty() { return m_ready.empty() && m_uncommitted.empty(); } +#ifdef VL_DEBUG + void dump(const char* eventDescription); +#endif + // Used by coroutines for co_awaiting a certain trigger + auto trigger(const char* eventDescription, const char* filename, int linenum) { + VL_DEBUG_IF(VL_DBG_MSGF(" Suspending process waiting for %s at %s:%d\n", + eventDescription, filename, linenum);); + struct Awaitable { + VlCoroutineVec& suspended; // Coros waiting on trigger +#ifdef VL_DEBUG + const char* filename; + int linenum; +#endif + bool await_ready() { return false; } // Always suspend + void await_suspend(std::coroutine_handle<> coro) { +#ifdef VL_DEBUG + suspended.emplace_back(coro, filename, linenum); +#else + suspended.emplace_back(coro); +#endif + } + void await_resume() {} + }; +#ifdef VL_DEBUG + return Awaitable{m_uncommitted, filename, linenum}; +#else + return Awaitable{m_uncommitted}; +#endif + } +}; + +//============================================================================= +// VlNow is a helper awaitable type that always suspends, and then immediately resumes a coroutine. +// Allows forcing the move of coroutine locals to the heap. + +struct VlNow { + bool await_ready() { return false; } // Always suspend + bool await_suspend(std::coroutine_handle<>) { return false; } // Resume immediately + void await_resume() {} +}; + +//============================================================================= +// VlForever is a helper awaitable type for suspending coroutines forever. Used for constant +// wait statements. + +struct VlForever { + bool await_ready() { return false; } // Always suspend + void await_suspend(std::coroutine_handle<> coro) { coro.destroy(); } + void await_resume() {} +}; + +//============================================================================= +// VlForkSync is used to manage fork..join and fork..join_any constructs. + +class VlForkSync final { + // VlJoin stores the handle of a suspended coroutine that did a fork..join or fork..join_any. + // If the counter reaches 0, the suspended coroutine shall be resumed. + struct VlJoin { + size_t m_counter = 0; // When reaches 0, resume suspended coroutine + VlCoroutineHandle m_susp; // Coroutine to resume + }; + + // The join info is shared among all forked processes + std::shared_ptr m_join; + +public: + // Create the join object and set the counter to the specified number + void init(size_t count) { m_join.reset(new VlJoin{count, {}}); } + // Called whenever any of the forked processes finishes. If the join counter reaches 0, the + // main process gets resumed + void done(const char* filename, int linenum); + // Used by coroutines for co_awaiting a join + auto join(const char* filename, int linenum) { + assert(m_join); + VL_DEBUG_IF( + VL_DBG_MSGF(" Awaiting join of fork at: %s:%d", filename, linenum);); + struct Awaitable { + const std::shared_ptr join; // Join to await on + bool await_ready() { return join->m_counter == 0; } // Suspend if join still exists + void await_suspend(std::coroutine_handle<> coro) { join->m_susp = coro; } + void await_resume() {} + }; + return Awaitable{m_join}; + } +}; + +//============================================================================= +// VlCoroutine +// Return value of a coroutine. Used for chaining coroutine suspension/resumption. + +class VlCoroutine final { +private: + // TYPES + struct VlPromise { + std::coroutine_handle<> m_continuation; // Coroutine to resume after this one finishes + VlCoroutine* m_corop = nullptr; // Pointer to the coroutine return object + + ~VlPromise(); + + VlCoroutine get_return_object() { return {this}; } + + // Never suspend at the start of the coroutine + std::suspend_never initial_suspend() { return {}; } + + // Never suspend at the end of the coroutine (thanks to this, the coroutine will clean up + // after itself) + std::suspend_never final_suspend() noexcept; + + void unhandled_exception() { std::abort(); } + void return_void() const {} + }; + + // MEMBERS + VlPromise* m_promisep; // The promise created for this coroutine + +public: + // TYPES + using promise_type = VlPromise; // promise_type has to be public + + // CONSTRUCTORS + // Construct + VlCoroutine(VlPromise* p) + : m_promisep{p} { + m_promisep->m_corop = this; + } + // Move. Update the pointers each time the return object is moved + VlCoroutine(VlCoroutine&& other) + : m_promisep{std::exchange(other.m_promisep, nullptr)} { + if (m_promisep) m_promisep->m_corop = this; + } + ~VlCoroutine() { + // Indicate to the promise that the return object is gone + if (m_promisep) m_promisep->m_corop = nullptr; + } + + // METHODS + // Suspend the awaiter if the coroutine is suspended (the promise exists) + bool await_ready() const noexcept { return !m_promisep; } + // Set the awaiting coroutine as the continuation of the current coroutine + void await_suspend(std::coroutine_handle<> coro) { m_promisep->m_continuation = coro; } + void await_resume() const noexcept {} +}; + +#endif // Guard diff --git a/include/verilated_types.h b/include/verilated_types.h index 76126e3a1..6a9b7d074 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -133,6 +133,10 @@ public: void clearTriggered() { m_triggered = false; } }; +inline std::string VL_TO_STRING(const VlEvent& e) { + return std::string("triggered=") + (e.isTriggered() ? "true" : "false"); +} + //=================================================================== // Shuffle RNG diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 97acb8090..4d4f12ef1 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -181,6 +181,7 @@ RAW_OBJS = \ V3DepthBlock.o \ V3Descope.o \ V3DupFinder.o \ + V3Timing.o \ V3EmitCBase.o \ V3EmitCConstPool.o \ V3EmitCFunc.o \ @@ -241,6 +242,7 @@ RAW_OBJS = \ V3SchedAcyclic.o \ V3SchedPartition.o \ V3SchedReplicate.o \ + V3SchedTiming.o \ V3Scope.o \ V3Scoreboard.o \ V3Slice.o \ diff --git a/src/V3Active.cpp b/src/V3Active.cpp index f9defceb2..4cedf73e2 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -373,9 +373,11 @@ private: } // Convert to blocking assignment - nodep->replaceWith(new AstAssign{nodep->fileline(), // - nodep->lhsp()->unlinkFrBack(), // - nodep->rhsp()->unlinkFrBack()}); + nodep->replaceWith(new AstAssign{ + nodep->fileline(), // + nodep->lhsp()->unlinkFrBack(), // + nodep->rhsp()->unlinkFrBack(), // + nodep->timingControlp() ? nodep->timingControlp()->unlinkFrBack() : nullptr}); VL_DO_DANGLING(nodep->deleteTree(), nodep); } @@ -473,8 +475,9 @@ private: } AstActive* const wantactivep - = m_clockedProcess ? m_namer.getActive(nodep->fileline(), oldsensesp) - : m_namer.getSpecialActive(nodep->fileline()); + = !m_clockedProcess ? m_namer.getSpecialActive(nodep->fileline()) + : oldsensesp ? m_namer.getActive(nodep->fileline(), oldsensesp) + : m_namer.getSpecialActive(nodep->fileline()); // Delete sensitivity list if (oldsensesp) VL_DO_DANGLING(oldsensesp->deleteTree(), oldsensesp); @@ -495,6 +498,12 @@ private: } } + void visitSenItems(AstNode* nodep) { + if (v3Global.opt.timing().isSetTrue()) { + nodep->foreach([this](AstSenItem* senItemp) { visit(senItemp); }); + } + } + // VISITORS virtual void visit(AstScope* nodep) override { m_namer.main(nodep); // Clear last scope's names, and collect this scope's existing names @@ -509,6 +518,7 @@ private: } virtual void visit(AstInitial* nodep) override { const ActiveDlyVisitor dlyvisitor{nodep, ActiveDlyVisitor::CT_INITIAL}; + visitSenItems(nodep); moveUnderSpecial(nodep); } virtual void visit(AstFinal* nodep) override { @@ -529,6 +539,7 @@ private: VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); return; } + visitSenItems(nodep); visitAlways(nodep, nodep->sensesp(), nodep->keyword()); } virtual void visit(AstAlwaysPostponed* nodep) override { @@ -540,16 +551,18 @@ private: virtual void visit(AstAlwaysPublic* nodep) override { visitAlways(nodep, nodep->sensesp(), VAlwaysKwd::ALWAYS); } + virtual void visit(AstCFunc* nodep) override { visitSenItems(nodep); } virtual void visit(AstSenItem* nodep) override { - UASSERT_OBJ(!m_walkingBody, nodep, "Should not reach here when walking body"); + UASSERT_OBJ(!m_walkingBody, nodep, + "Should not reach here when walking body without --timing"); if (!nodep->sensp()) return; // Ignore sequential items (e.g.: initial, comb, etc.) m_clockedProcess = true; if (nodep->edgeType() != VEdgeType::ET_CHANGED) m_allChanged = false; - if (nodep->varrefp()) { - if (const AstBasicDType* const basicp = nodep->varrefp()->dtypep()->basicp()) { + if (const auto* const dtypep = nodep->sensp()->dtypep()) { + if (const auto* const basicp = dtypep->basicp()) { if (basicp->isEvent()) nodep->edgeType(VEdgeType::ET_EVENT); } } @@ -573,6 +586,7 @@ private: } virtual void visit(AstAssignDly* nodep) override { m_canBeComb = false; + if (nodep->isTimingControl()) m_clockedProcess = true; iterateChildrenConst(nodep); } virtual void visit(AstFireEvent* nodep) override { @@ -587,13 +601,27 @@ private: m_canBeComb = false; iterateChildrenConst(nodep); } + virtual void visit(AstFork* nodep) override { + if (nodep->isTimingControl()) { + m_canBeComb = false; + m_clockedProcess = true; + } + // Do not iterate children, technically not part of this process + } //-------------------- virtual void visit(AstVar*) override {} // Accelerate virtual void visit(AstVarScope*) override {} // Accelerate virtual void visit(AstNode* nodep) override { - if (m_walkingBody && !m_canBeComb) return; // Accelerate + if (!v3Global.opt.timing().isSetTrue() && m_walkingBody && !m_canBeComb) { + return; // Accelerate + } if (!nodep->isPure()) m_canBeComb = false; + if (nodep->isTimingControl()) { + m_canBeComb = false; + m_clockedProcess = true; + return; + } iterateChildren(nodep); } diff --git a/src/V3Ast.h b/src/V3Ast.h index ed8b8bc93..6964cdce6 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -450,6 +450,9 @@ public: CHARPTR, MTASKSTATE, TRIGGERVEC, + DELAY_SCHEDULER, + TRIGGER_SCHEDULER, + FORK_SYNC, // Unsigned and two state; fundamental types UINT32, UINT64, @@ -460,21 +463,57 @@ public: }; enum en m_e; const char* ascii() const { - static const char* const names[] - = {"%E-unk", "bit", "byte", "chandle", "event", - "int", "integer", "logic", "longint", "real", - "shortint", "time", "string", "VerilatedScope*", "char*", - "VlMTaskState", "VlTriggerVec", "IData", "QData", "LOGIC_IMPLICIT", - " MAX"}; + static const char* const names[] = {"%E-unk", + "bit", + "byte", + "chandle", + "event", + "int", + "integer", + "logic", + "longint", + "real", + "shortint", + "time", + "string", + "VerilatedScope*", + "char*", + "VlMTaskState", + "VlTriggerVec", + "VlDelayScheduler", + "VlTriggerScheduler", + "VlFork", + "IData", + "QData", + "LOGIC_IMPLICIT", + " MAX"}; return names[m_e]; } const char* dpiType() const { - static const char* const names[] - = {"%E-unk", "svBit", "char", "void*", "char", - "int", "%E-integer", "svLogic", "long long", "double", - "short", "%E-time", "const char*", "dpiScope", "const char*", - "%E-mtaskstate", "%E-triggervec", "IData", "QData", "%E-logic-implct", - " MAX"}; + static const char* const names[] = {"%E-unk", + "svBit", + "char", + "void*", + "char", + "int", + "%E-integer", + "svLogic", + "long long", + "double", + "short", + "%E-time", + "const char*", + "dpiScope", + "const char*", + "%E-mtaskstate", + "%E-triggervec", + "%E-dly-sched", + "%E-trig-sched", + "%E-fork", + "IData", + "QData", + "%E-logic-implct", + " MAX"}; return names[m_e]; } static void selfTest() { @@ -508,6 +547,9 @@ public: case CHARPTR: return 0; // opaque case MTASKSTATE: return 0; // opaque case TRIGGERVEC: return 0; // opaque + case DELAY_SCHEDULER: return 0; // opaque + case TRIGGER_SCHEDULER: return 0; // opaque + case FORK_SYNC: return 0; // opaque case UINT32: return 32; case UINT64: return 64; default: return 0; @@ -544,7 +586,8 @@ public: } bool isOpaque() const { // IE not a simple number we can bit optimize return (m_e == EVENT || m_e == STRING || m_e == SCOPEPTR || m_e == CHARPTR - || m_e == MTASKSTATE || m_e == TRIGGERVEC || m_e == DOUBLE); + || m_e == MTASKSTATE || m_e == TRIGGERVEC || m_e == DELAY_SCHEDULER + || m_e == TRIGGER_SCHEDULER || m_e == FORK_SYNC || m_e == DOUBLE); } bool isDouble() const { return m_e == DOUBLE; } bool isEvent() const { return m_e == EVENT; } @@ -1825,17 +1868,19 @@ public: // Changes control flow, disable some optimizations virtual bool isBrancher() const { return false; } // Else a AstTime etc that can't be pushed out - virtual bool isGateOptimizable() const { return true; } + virtual bool isGateOptimizable() const { return !isTimingControl(); } // GateDedupable is a slightly larger superset of GateOptimzable (eg, AstNodeIf) virtual bool isGateDedupable() const { return isGateOptimizable(); } // Else creates output or exits, etc, not unconsumed virtual bool isOutputter() const { return false; } // Else a AstTime etc which output can't be predicted from input - virtual bool isPredictOptimizable() const { return true; } + virtual bool isPredictOptimizable() const { return !isTimingControl(); } // Else a $display, etc, that must be ordered with other displays virtual bool isPure() const { return true; } // Else a AstTime etc that can't be substituted out virtual bool isSubstOptimizable() const { return true; } + // An event control, delay, wait, etc. + virtual bool isTimingControl() const { return false; } // isUnlikely handles $stop or similar statement which means an above IF // statement is unlikely to be taken virtual bool isUnlikely() const { return false; } @@ -2628,6 +2673,8 @@ public: class AstNodeProcedure VL_NOT_FINAL : public AstNode { // IEEE procedure: initial, final, always + bool m_suspendable = false; // Is suspendable by a Delay, EventControl, etc. + protected: AstNodeProcedure(VNType t, FileLine* fl, AstNode* bodysp) : AstNode{t, fl} { @@ -2641,6 +2688,8 @@ public: AstNode* bodysp() const { return op2p(); } // op2 = Statements to evaluate void addStmtp(AstNode* nodep) { addOp2p(nodep); } bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); } + bool isSuspendable() const { return m_suspendable; } + void setSuspendable() { m_suspendable = true; } }; class AstNodeStmt VL_NOT_FINAL : public AstNode { @@ -2670,7 +2719,7 @@ protected: : AstNodeStmt{t, fl} { setOp1p(rhsp); setOp2p(lhsp); - addNOp3p(timingControlp); + setNOp3p(timingControlp); dtypeFrom(lhsp); } @@ -2683,7 +2732,7 @@ public: AstNode* lhsp() const { return op2p(); } // op2 = Assign to // op3 = Timing controls (delays, event controls) AstNode* timingControlp() const { return op3p(); } - void addTimingControlp(AstNode* const np) { addNOp3p(np); } + void timingControlp(AstNode* const np) { setNOp3p(np); } void rhsp(AstNode* np) { setOp1p(np); } void lhsp(AstNode* np) { setOp2p(np); } virtual bool hasDType() const override { return true; } @@ -2691,6 +2740,7 @@ public: virtual int instrCount() const override { return widthInstrs(); } virtual bool same(const AstNode*) const override { return true; } virtual string verilogKwd() const override { return "="; } + virtual bool isTimingControl() const override { return timingControlp(); } virtual bool brokeLhsMustBeLvalue() const = 0; }; diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index d60fee66d..5b35b2dcf 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -711,6 +711,12 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const { info.m_type = "VlMTaskVertex"; } else if (bdtypep->isTriggerVec()) { info.m_type = "VlTriggerVec<" + cvtToStr(dtypep->width()) + ">"; + } else if (bdtypep->isDelayScheduler()) { + info.m_type = "VlDelayScheduler"; + } else if (bdtypep->isTriggerScheduler()) { + info.m_type = "VlTriggerScheduler"; + } else if (bdtypep->isForkSync()) { + info.m_type = "VlForkSync"; } else if (bdtypep->isEvent()) { info.m_type = "VlEvent"; } else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width @@ -1296,7 +1302,10 @@ void AstNode::dump(std::ostream& str) const { } } -void AstNodeProcedure::dump(std::ostream& str) const { this->AstNode::dump(str); } +void AstNodeProcedure::dump(std::ostream& str) const { + this->AstNode::dump(str); + if (isSuspendable()) str << " [SUSP]"; +} void AstAlways::dump(std::ostream& str) const { this->AstNodeProcedure::dump(str); @@ -1954,8 +1963,34 @@ void AstCFunc::dump(std::ostream& str) const { if (isConstructor()) str << " [CTOR]"; if (isDestructor()) str << " [DTOR]"; if (isVirtual()) str << " [VIRT]"; + if (isCoroutine()) str << " [CORO]"; +} +void AstCAwait::dump(std::ostream& str) const { + this->AstNodeStmt::dump(str); + if (sensesp()) { + str << " => "; + sensesp()->dump(str); + } } void AstCUse::dump(std::ostream& str) const { this->AstNode::dump(str); str << " [" << useType() << "]"; } + +AstAlways* AstAssignW::convertToAlways() { + AstNode* const lhs1p = lhsp()->unlinkFrBack(); + AstNode* const rhs1p = rhsp()->unlinkFrBack(); + AstNode* const controlp = timingControlp() ? timingControlp()->unlinkFrBack() : nullptr; + FileLine* const flp = fileline(); + AstNode* bodysp = new AstAssign{flp, lhs1p, rhs1p, controlp}; + if (controlp) { + // If there's a timing control, put the assignment in a fork..join_none. This process won't + // get marked as suspendable and thus will be scheduled normally + auto* forkp = new AstFork{flp, "", bodysp}; + forkp->joinType(VJoinType::JOIN_NONE); + bodysp = forkp; + } + AstAlways* const newp = new AstAlways{flp, VAlwaysKwd::ALWAYS, nullptr, bodysp}; + replaceWith(newp); // User expected to then deleteTree(); + return newp; +} diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 0316ce921..c8edf7702 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -1004,6 +1004,9 @@ public: bool isDouble() const { return keyword().isDouble(); } bool isEvent() const { return keyword() == VBasicDTypeKwd::EVENT; } bool isTriggerVec() const { return keyword() == VBasicDTypeKwd::TRIGGERVEC; } + bool isForkSync() const { return keyword() == VBasicDTypeKwd::FORK_SYNC; } + bool isDelayScheduler() const { return keyword() == VBasicDTypeKwd::DELAY_SCHEDULER; } + bool isTriggerScheduler() const { return keyword() == VBasicDTypeKwd::TRIGGER_SCHEDULER; } bool isOpaque() const { return keyword().isOpaque(); } bool isString() const { return keyword().isString(); } bool isZeroInit() const { return keyword().isZeroInit(); } @@ -1930,6 +1933,7 @@ public: return op1p(); } // op1 = Extracting what (nullptr=TBD during parsing) AstNode* lsbp() const { return op2p(); } // op2 = Msb selection expression + void lsbp(AstNode* const lsbp) { setOp2p(lsbp); } AstNode* widthp() const { return op3p(); } // op3 = Width int widthConst() const { return VN_AS(widthp(), Const)->toSInt(); } int lsbConst() const { return VN_AS(lsbp(), Const)->toSInt(); } @@ -2108,6 +2112,7 @@ private: bool m_isLatched : 1; // Not assigned in all control paths of combo always bool m_isForceable : 1; // May be forced/released externally from user C code bool m_isWrittenByDpi : 1; // This variable can be written by a DPI Export + bool m_isWrittenBySuspendable : 1; // This variable can be written by a suspendable process void init() { m_ansi = false; @@ -2148,6 +2153,7 @@ private: m_isLatched = false; m_isForceable = false; m_isWrittenByDpi = false; + m_isWrittenBySuspendable = false; m_attrClocker = VVarAttrClocker::CLOCKER_UNKNOWN; } @@ -2315,6 +2321,8 @@ public: void setForceable() { m_isForceable = true; } bool isWrittenByDpi() const { return m_isWrittenByDpi; } void setWrittenByDpi() { m_isWrittenByDpi = true; } + bool isWrittenBySuspendable() const { return m_isWrittenBySuspendable; } + void setWrittenBySuspendable() { m_isWrittenBySuspendable = true; } // METHODS virtual void name(const string& name) override { m_name = name; } virtual void tag(const string& text) override { m_tag = text; } @@ -3468,6 +3476,7 @@ public: } // op1 = Expression sensitized, if any AstNode* sensp() const { return op1p(); } + void sensp(AstNode* const nodep) { setOp1p(nodep); } AstNodeVarRef* varrefp() const { return VN_CAST(op1p(), NodeVarRef); } // bool isClocked() const { return edgeType().clockedStmt(); } @@ -3604,7 +3613,8 @@ public: } ASTNODE_NODE_FUNCS(Assign) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAssign(this->fileline(), lhsp, rhsp); + AstNode* const controlp = timingControlp() ? timingControlp()->cloneTree(false) : nullptr; + return new AstAssign(this->fileline(), lhsp, rhsp, controlp); } virtual bool brokeLhsMustBeLvalue() const override { return true; } }; @@ -3628,7 +3638,8 @@ public: : ASTGEN_SUPER_AssignDly(fl, lhsp, rhsp, timingControlp) {} ASTNODE_NODE_FUNCS(AssignDly) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAssignDly(this->fileline(), lhsp, rhsp); + AstNode* const controlp = timingControlp() ? timingControlp()->cloneTree(false) : nullptr; + return new AstAssignDly(this->fileline(), lhsp, rhsp, controlp); } virtual bool isGateOptimizable() const override { return false; } virtual string verilogKwd() const override { return "<="; } @@ -3638,21 +3649,15 @@ public: class AstAssignW final : public AstNodeAssign { // Like assign, but wire/assign's in verilog, the only setting of the specified variable public: - AstAssignW(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER_AssignW(fl, lhsp, rhsp) {} + AstAssignW(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* timingControlp = nullptr) + : ASTGEN_SUPER_AssignW(fl, lhsp, rhsp, timingControlp) {} ASTNODE_NODE_FUNCS(AssignW) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { - return new AstAssignW(this->fileline(), lhsp, rhsp); + AstNode* const controlp = timingControlp() ? timingControlp()->cloneTree(false) : nullptr; + return new AstAssignW(this->fileline(), lhsp, rhsp, controlp); } virtual bool brokeLhsMustBeLvalue() const override { return true; } - AstAlways* convertToAlways() { - AstNode* const lhs1p = lhsp()->unlinkFrBack(); - AstNode* const rhs1p = rhsp()->unlinkFrBack(); - AstAlways* const newp = new AstAlways(fileline(), VAlwaysKwd::ALWAYS, nullptr, - new AstAssign(fileline(), lhs1p, rhs1p)); - replaceWith(newp); // User expected to then deleteTree(); - return newp; - } + AstAlways* convertToAlways(); }; class AstAssignVarScope final : public AstNodeAssign { @@ -3722,7 +3727,7 @@ public: } ASTNODE_NODE_FUNCS(FireEvent); AstNode* operandp() const { return op1p(); } - bool isDeleyed() const { return m_delayed; } + bool isDelayed() const { return m_delayed; } }; class AstAssignPre final : public AstNodeAssign { @@ -3943,6 +3948,7 @@ public: setNOp2p(stmtsp); } ASTNODE_NODE_FUNCS(Delay) + virtual bool isTimingControl() const override { return true; } virtual bool same(const AstNode* /*samep*/) const override { return true; } // AstNode* lhsp() const { return op1p(); } // op1 = delay value @@ -4735,8 +4741,10 @@ public: addNOp3p(bodysp); } ASTNODE_NODE_FUNCS(Wait) - AstNode* bodysp() const { return op3p(); } // op3 = body of loop + AstNode* condp() const { return op2p(); } // op2 = condition + AstNode* bodysp() const { return op3p(); } // op3 = statements after wait bool isFirstInMyListOfStatements(AstNode* n) const override { return n == bodysp(); } + virtual bool isTimingControl() const override { return true; } }; class AstWhile final : public AstNodeStmt { @@ -5110,6 +5118,7 @@ public: AstFork(FileLine* fl, const string& name, AstNode* stmtsp) : ASTGEN_SUPER_Fork(fl, name, stmtsp) {} ASTNODE_NODE_FUNCS(Fork) + virtual bool isTimingControl() const override { return !joinType().joinNone(); } virtual void dump(std::ostream& str) const override; VJoinType joinType() const { return m_joinType; } void joinType(const VJoinType& flag) { m_joinType = flag; } @@ -5391,21 +5400,20 @@ public: class AstEventControl final : public AstNodeStmt { // Parents: stmtlist + // Children: sentree, stmtlist public: AstEventControl(FileLine* fl, AstSenTree* sensesp, AstNode* stmtsp) : ASTGEN_SUPER_EventControl(fl) { setNOp1p(sensesp); - setNOp2p(stmtsp); + addNOp2p(stmtsp); } ASTNODE_NODE_FUNCS(EventControl) virtual string verilogKwd() const override { return "@(%l) %r"; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual bool isPure() const override { return false; } - virtual bool isOutputter() const override { return false; } + virtual bool isTimingControl() const override { return true; } virtual int instrCount() const override { return 0; } AstSenTree* sensesp() const { return VN_AS(op1p(), SenTree); } AstNode* stmtsp() const { return op2p(); } + void stmtsp(AstNode* stmtsp) { setNOp2p(stmtsp); } }; class AstTimeFormat final : public AstNodeStmt { @@ -9109,6 +9117,7 @@ public: AstScope* scopep() const { return m_scopep; } void scopep(AstScope* nodep) { m_scopep = nodep; } string rtnTypeVoid() const { return ((m_rtnType == "") ? "void" : m_rtnType); } + void rtnType(const string& rtnType) { m_rtnType = rtnType; } bool dontCombine() const { return m_dontCombine || isTrace() || entryPoint(); } void dontCombine(bool flag) { m_dontCombine = flag; } bool dontInline() const { return dontCombine() || slow() || funcPublic(); } @@ -9153,6 +9162,7 @@ public: void dpiImportWrapper(bool flag) { m_dpiImportWrapper = flag; } void dpiTraceInit(bool flag) { m_dpiTraceInit = flag; } bool dpiTraceInit() const { return m_dpiTraceInit; } + bool isCoroutine() const { return m_rtnType == "VlCoroutine"; } // // If adding node accessors, see below emptyBody AstNode* argsp() const { return op1p(); } @@ -9321,6 +9331,32 @@ public: VUseType useType() const { return m_useType; } }; +class AstCAwait final : public AstNodeStmt { + // Emit C++'s co_await statement + // Children: expression + AstSenTree* m_sensesp; // Sentree related to this await +public: + AstCAwait(FileLine* fl, AstNode* exprsp, AstSenTree* sensesp = nullptr) + : ASTGEN_SUPER_CAwait(fl) + , m_sensesp{sensesp} { + setNOp1p(exprsp); + } + ASTNODE_NODE_FUNCS(CAwait) + virtual bool isTimingControl() const override { return true; } + virtual const char* broken() const override { + BROKEN_RTN(m_sensesp && !m_sensesp->brokeExists()); + return nullptr; + } + virtual void cloneRelink() override { + if (m_sensesp && m_sensesp->clonep()) m_sensesp = m_sensesp->clonep(); + } + virtual void dump(std::ostream& str) const override; + AstNode* exprp() const { return op1p(); } // op1 = awaited expression + void exprp(AstNode* const nodep) { setNOp1p(nodep); } + AstSenTree* sensesp() const { return m_sensesp; } + void clearSensesp() { m_sensesp = nullptr; } +}; + class AstMTaskBody final : public AstNode { // Hold statements for each MTask private: @@ -9475,6 +9511,7 @@ private: AstCFunc* m_evalp = nullptr; // The '_eval' function AstCFunc* m_evalNbap = nullptr; // The '_eval__nba' function AstVarScope* m_dpiExportTriggerp = nullptr; // The DPI export trigger variable + AstVar* m_delaySchedulerp = nullptr; // The delay scheduler variable AstTopScope* m_topScopep = nullptr; // The singleton AstTopScope under the top module VTimescale m_timeunit; // Global time unit VTimescale m_timeprecision; // Global time precision @@ -9492,6 +9529,7 @@ public: BROKEN_RTN(m_evalp && !m_evalp->brokeExists()); BROKEN_RTN(m_dpiExportTriggerp && !m_dpiExportTriggerp->brokeExists()); BROKEN_RTN(m_topScopep && !m_topScopep->brokeExists()); + BROKEN_RTN(m_delaySchedulerp && !m_delaySchedulerp->brokeExists()); return nullptr; } virtual void cloneRelink() override { V3ERROR_NA; } @@ -9528,6 +9566,8 @@ public: void evalNbap(AstCFunc* funcp) { m_evalNbap = funcp; } AstVarScope* dpiExportTriggerp() const { return m_dpiExportTriggerp; } void dpiExportTriggerp(AstVarScope* varScopep) { m_dpiExportTriggerp = varScopep; } + AstVar* delaySchedulerp() const { return m_delaySchedulerp; } + void delaySchedulerp(AstVar* const varScopep) { m_delaySchedulerp = varScopep; } AstTopScope* topScopep() const { return m_topScopep; } void createTopScope(AstScope* scopep) { UASSERT(scopep, "Must not be nullptr"); diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index 0e4176739..d2e9e66d7 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -68,6 +68,7 @@ private: string m_namedScope; // Name of begin blocks above us string m_unnamedScope; // Name of begin blocks, including unnamed blocks int m_ifDepth = 0; // Current if depth + bool m_underFork = false; // True if the current statement is directly under a fork // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -120,6 +121,12 @@ private: } // VISITORS + virtual void visit(AstFork* nodep) override { + VL_RESTORER(m_underFork); + m_underFork = true; + dotNames(nodep, "__FORK__"); + nodep->name(""); + } virtual void visit(AstNodeModule* nodep) override { VL_RESTORER(m_modp); { @@ -169,11 +176,19 @@ private: VL_RESTORER(m_namedScope); VL_RESTORER(m_unnamedScope); { - dotNames(nodep, "__BEGIN__"); - + { + VL_RESTORER(m_underFork); + m_underFork = false; + dotNames(nodep, "__BEGIN__"); + } UASSERT_OBJ(!nodep->genforp(), nodep, "GENFORs should have been expanded earlier"); // Cleanup + if (m_underFork) { + // If we're under a fork, keep this begin to group its statements together + nodep->name(""); + return; + } AstNode* addsp = nullptr; if (AstNode* const stmtsp = nodep->stmtsp()) { stmtsp->unlinkFrBackWithNext(); @@ -251,6 +266,8 @@ private: } // VISITORS - LINT CHECK virtual void visit(AstIf* nodep) override { // not AstNodeIf; other types not covered + VL_RESTORER(m_underFork); + m_underFork = false; // Check IFDEPTH warning - could be in other transform files if desire VL_RESTORER(m_ifDepth); if (m_ifDepth == -1 || v3Global.opt.ifDepth() < 1) { // Turned off @@ -264,7 +281,11 @@ private: } iterateChildren(nodep); } - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + virtual void visit(AstNode* nodep) override { + VL_RESTORER(m_underFork); + m_underFork = false; + iterateChildren(nodep); + } public: // CONSTRUCTORS diff --git a/src/V3Cast.cpp b/src/V3Cast.cpp index baea49588..ad8c66572 100644 --- a/src/V3Cast.cpp +++ b/src/V3Cast.cpp @@ -159,7 +159,8 @@ private: const AstNode* const backp = nodep->backp(); if (nodep->access().isReadOnly() && !VN_IS(backp, CCast) && VN_IS(backp, NodeMath) && !VN_IS(backp, ArraySel) && !VN_IS(backp, RedXor) - && (nodep->varp()->basicp() && !nodep->varp()->basicp()->isTriggerVec()) + && (nodep->varp()->basicp() && !nodep->varp()->basicp()->isTriggerVec() + && !nodep->varp()->basicp()->isForkSync()) && backp->width() && castSize(nodep) != castSize(nodep->varp())) { // Cast vars to IData first, else below has upper bits wrongly set // CData x=3; out = (QData)(x<<30); diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 52334947a..6458d1106 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -2853,6 +2853,7 @@ private: // Zero elimination virtual void visit(AstNodeAssign* nodep) override { iterateChildren(nodep); + if (nodep->timingControlp()) m_hasJumpDelay = true; if (m_doNConst && replaceNodeAssign(nodep)) return; } virtual void visit(AstAssignAlias* nodep) override { @@ -3164,10 +3165,6 @@ private: //----- // Jump elimination - virtual void visit(AstDelay* nodep) override { - iterateChildren(nodep); - m_hasJumpDelay = true; - } virtual void visit(AstJumpGo* nodep) override { iterateChildren(nodep); // Jump to label where label immediately follows label is not useful @@ -3563,6 +3560,7 @@ private: << nodep->prettyTypeName() << " to constant."); } } else { + if (nodep->isTimingControl()) m_hasJumpDelay = true; // Calculate the width of this operation if (m_params && !nodep->width()) nodep = V3Width::widthParamsEdit(nodep); iterateChildren(nodep); diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index 8cc905958..e72d4ab21 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -280,6 +280,7 @@ private: } else { // Track like any other statement iterateAndNextNull(nodep->lhsp()); } + iterateNull(nodep->timingControlp()); } } diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index db5024cbf..6a85328c9 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -71,6 +71,8 @@ private: // AstVarScope::user1p() -> AstVarScope*. Points to temp var created. // AstVarScope::user2p() -> AstActive*. Points to activity block of signal // (valid when AstVarScope::user1p is valid) + // AstVarScope::user3p() -> AstAlwaysPost*. Post block for this variable used for + // AssignDlys in suspendable processes // AstVarScope::user4p() -> AstAlwaysPost*. Post block for this variable // AstVarScope::user5p() -> AstVarRef*. Last blocking or non-blocking reference // AstVar::user2() -> bool. Set true if already made warning @@ -92,6 +94,8 @@ private: AstActive* m_activep = nullptr; // Current activate const AstCFunc* m_cfuncp = nullptr; // Current public C Function AstAssignDly* m_nextDlyp = nullptr; // Next delayed assignment in a list of assignments + AstNodeProcedure* m_procp = nullptr; // Current process + std::set m_timingDomains; // Timing resume domains bool m_inDly = false; // True in delayed assignments bool m_inLoop = false; // True in for loops bool m_inInitial = false; // True in static initializers and initial blocks @@ -203,7 +207,7 @@ private: } } - AstNode* createDlyArray(AstAssignDly* nodep, AstNode* lhsp) { + AstNode* createDlyOnSet(AstAssignDly* nodep, AstNode* lhsp) { // Create delayed assignment // See top of this file for transformation // Return the new LHS for the assignment, Null = unlink @@ -211,17 +215,24 @@ private: AstNode* newlhsp = nullptr; // nullptr = unlink old assign const AstSel* bitselp = nullptr; AstArraySel* arrayselp = nullptr; + AstVarRef* varrefp = nullptr; if (VN_IS(lhsp, Sel)) { bitselp = VN_AS(lhsp, Sel); - arrayselp = VN_AS(bitselp->fromp(), ArraySel); - } else { + arrayselp = VN_CAST(bitselp->fromp(), ArraySel); + if (!arrayselp) varrefp = VN_AS(bitselp->fromp(), VarRef); + } else if (VN_IS(lhsp, ArraySel)) { arrayselp = VN_AS(lhsp, ArraySel); + } else { + varrefp = VN_AS(lhsp, VarRef); + } + if (arrayselp) { + UASSERT_OBJ(!VN_IS(arrayselp->dtypep()->skipRefp(), UnpackArrayDType), nodep, + "ArraySel with unpacked arrays should have been removed in V3Slice"); + UINFO(4, "AssignDlyArray: " << nodep << endl); + } else { + UASSERT_OBJ(varrefp, nodep, "No arraysel nor varref"); + UINFO(4, "AssignDlyOnSet: " << nodep << endl); } - UASSERT_OBJ(arrayselp, nodep, "No arraysel under bitsel?"); - UASSERT_OBJ(!VN_IS(arrayselp->dtypep()->skipRefp(), UnpackArrayDType), nodep, - "ArraySel with unpacked arrays should have been removed in V3Slice"); - UINFO(4, "AssignDlyArray: " << nodep << endl); - // //=== Dimensions: __Vdlyvdim__ std::deque dimvalp; // Assignment value for each dimension of assignment AstNode* dimselp = arrayselp; @@ -229,7 +240,7 @@ private: AstNode* const valp = VN_AS(dimselp, ArraySel)->bitp()->unlinkFrBack(); dimvalp.push_front(valp); } - AstVarRef* const varrefp = VN_AS(dimselp, VarRef); + if (dimselp) varrefp = VN_AS(dimselp, VarRef); UASSERT_OBJ(varrefp, nodep, "No var underneath arraysels"); UASSERT_OBJ(varrefp->varScopep(), varrefp, "Var didn't get varscoped in V3Scope.cpp"); varrefp->unlinkFrBack(); @@ -292,7 +303,7 @@ private: AstVarScope* setvscp; AstAssignPre* setinitp = nullptr; - if (nodep->user3p()) { + if (!m_procp->isSuspendable() && nodep->user3p()) { // Simplistic optimization. If the previous statement in same scope was also a =>, // then we told this nodep->user3 we can use its Vdlyvset rather than making a new one. // This is good for code like: @@ -303,9 +314,12 @@ private: const string setvarname = (string("__Vdlyvset__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum)); setvscp = createVarSc(varrefp->varScopep(), setvarname, 1, nullptr); - setinitp = new AstAssignPre(nodep->fileline(), - new AstVarRef(nodep->fileline(), setvscp, VAccess::WRITE), - new AstConst(nodep->fileline(), 0)); + if (!m_procp->isSuspendable()) { + // Suspendables reset __Vdlyvset__ in the AstAlwaysPost + setinitp = new AstAssignPre{ + nodep->fileline(), new AstVarRef{nodep->fileline(), setvscp, VAccess::WRITE}, + new AstConst{nodep->fileline(), 0}}; + } AstAssign* const setassignp = new AstAssign( nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, VAccess::WRITE), new AstConst(nodep->fileline(), AstConst::BitTrue())); @@ -331,19 +345,36 @@ private: // Build "IF (changeit) ... UINFO(9, " For " << setvscp << endl); UINFO(9, " & " << varrefp << endl); - AstAlwaysPost* finalp = VN_AS(varrefp->varScopep()->user4p(), AlwaysPost); - if (finalp) { - AstActive* const oldactivep = VN_AS(finalp->user2p(), Active); - checkActivePost(varrefp, oldactivep); - if (setinitp) oldactivep->addStmtsp(setinitp); - } else { // first time we've dealt with this memory - finalp = new AstAlwaysPost(nodep->fileline(), nullptr /*sens*/, nullptr /*body*/); - UINFO(9, " Created " << finalp << endl); - AstActive* const newactp = createActive(varrefp); - newactp->addStmtsp(finalp); - varrefp->varScopep()->user4p(finalp); - finalp->user2p(newactp); - if (setinitp) newactp->addStmtsp(setinitp); + AstAlwaysPost* finalp = nullptr; + if (m_procp->isSuspendable()) { + finalp = VN_AS(varrefp->varScopep()->user3p(), AlwaysPost); + if (!finalp) { + FileLine* const flp = nodep->fileline(); + finalp = new AstAlwaysPost{flp, nullptr, nullptr}; + UINFO(9, " Created " << finalp << endl); + if (!m_procp->user3p()) { + AstActive* const newactp = createActive(varrefp); + m_procp->user3p(newactp); + varrefp->varScopep()->user3p(finalp); + } + AstActive* const actp = VN_AS(m_procp->user3p(), Active); + actp->addStmtsp(finalp); + } + } else { + finalp = VN_AS(varrefp->varScopep()->user4p(), AlwaysPost); + if (finalp) { + AstActive* const oldactivep = VN_AS(finalp->user2p(), Active); + checkActivePost(varrefp, oldactivep); + if (setinitp) oldactivep->addStmtsp(setinitp); + } else { // first time we've dealt with this memory + finalp = new AstAlwaysPost{nodep->fileline(), nullptr /*sens*/, nullptr /*body*/}; + UINFO(9, " Created " << finalp << endl); + AstActive* const newactp = createActive(varrefp); + newactp->addStmtsp(finalp); + varrefp->varScopep()->user4p(finalp); + finalp->user2p(newactp); + if (setinitp) newactp->addStmtsp(setinitp); + } } AstIf* postLogicp; if (finalp->user3p() == setvscp) { @@ -361,6 +392,11 @@ private: finalp->user4p(postLogicp); // and the associated IF, as we may be able to reuse it } postLogicp->addIfsp(new AstAssign(nodep->fileline(), selectsp, valreadp)); + if (m_procp->isSuspendable()) { + FileLine* const flp = nodep->fileline(); + postLogicp->addIfsp(new AstAssign{flp, new AstVarRef{flp, setvscp, VAccess::WRITE}, + new AstConst{flp, 0}}); + } return newlhsp; } @@ -393,10 +429,38 @@ private: iterateChildren(nodep); } } + virtual void visit(AstNodeProcedure* nodep) override { + m_procp = nodep; + m_timingDomains.clear(); + iterateChildren(nodep); + m_procp = nullptr; + if (m_timingDomains.empty()) return; + if (auto* const actp = VN_AS(nodep->user3p(), Active)) { + // Merge all timing domains (and possibly the active's domain) to create a sentree for + // the post logic + // TODO: allow multiple sentrees per active, so we don't have to merge them and create + // a new trigger + auto* clockedDomain + = actp->sensesp()->hasClocked() ? actp->sensesp()->cloneTree(false) : nullptr; + for (auto* const domainp : m_timingDomains) { + if (!clockedDomain) { + clockedDomain = domainp->cloneTree(false); + } else { + clockedDomain->addSensesp(domainp->sensesp()->cloneTree(true)); + clockedDomain->multi(true); // Comment that it was made from multiple domains + } + } + // We cannot constify the sentree using V3Const as user1-5 is already taken up by + // V3Delayed + actp->sensesp(clockedDomain); + actp->sensesStorep(clockedDomain); + } + } + virtual void visit(AstCAwait* nodep) override { m_timingDomains.insert(nodep->sensesp()); } virtual void visit(AstFireEvent* nodep) override { UASSERT_OBJ(v3Global.hasEvents(), nodep, "Inconsistent"); FileLine* const flp = nodep->fileline(); - if (nodep->isDeleyed()) { + if (nodep->isDelayed()) { AstVarRef* const vrefp = VN_AS(nodep->operandp(), VarRef); vrefp->unlinkFrBack(); const string newvarname = (string("__Vdly__") + vrefp->varp()->shortName()); @@ -442,12 +506,14 @@ private: nodep->v3warn(E_UNSUPPORTED, "Unsupported: Delayed assignment inside public function/task"); } - if (VN_IS(nodep->lhsp(), ArraySel) - || (VN_IS(nodep->lhsp(), Sel) - && VN_IS(VN_AS(nodep->lhsp(), Sel)->fromp(), ArraySel))) { - AstNode* const lhsp = nodep->lhsp()->unlinkFrBack(); - AstNode* const newlhsp = createDlyArray(nodep, lhsp); - if (m_inLoop) { + UASSERT_OBJ(m_procp, nodep, "Delayed assignment not under process"); + const bool isArray = VN_IS(nodep->lhsp(), ArraySel) + || (VN_IS(nodep->lhsp(), Sel) + && VN_IS(VN_AS(nodep->lhsp(), Sel)->fromp(), ArraySel)); + if (m_procp->isSuspendable() || isArray) { + AstNode* const lhsp = nodep->lhsp(); + AstNode* const newlhsp = createDlyOnSet(nodep, lhsp); + if (m_inLoop && isArray) { nodep->v3warn(BLKLOOPINIT, "Unsupported: Delayed assignment to array inside for " "loops (non-delayed is ok - see docs)"); } @@ -456,11 +522,12 @@ private: nodep->v3warn(E_UNSUPPORTED, "Unsupported: event arrays"); } if (newlhsp) { + if (nodep->lhsp()) nodep->lhsp()->unlinkFrBack(); nodep->lhsp(newlhsp); } else { VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); } - VL_DO_DANGLING(pushDeletep(lhsp), lhsp); + if (!lhsp->backp()) VL_DO_DANGLING(pushDeletep(lhsp), lhsp); } else { iterateChildren(nodep); } diff --git a/src/V3EmitCFunc.cpp b/src/V3EmitCFunc.cpp index 7e0e0e8fe..ba64a897e 100644 --- a/src/V3EmitCFunc.cpp +++ b/src/V3EmitCFunc.cpp @@ -684,6 +684,12 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, const string& varNameP } else if (basicp && basicp->keyword() == VBasicDTypeKwd::STRING) { // String's constructor deals with it return ""; + } else if (basicp && basicp->isForkSync()) { + return ""; + } else if (basicp && basicp->isDelayScheduler()) { + return ""; + } else if (basicp && basicp->isTriggerScheduler()) { + return ""; } else if (basicp) { const bool zeroit = (varp->attrFileDescr() // Zero so we don't do file IO if never $fopen diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index aba15163b..43d016c3f 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -413,6 +413,11 @@ public: puts(funcp->nameProtect()); emitCCallArgs(nodep, ""); } + virtual void visit(AstCAwait* nodep) override { + puts("co_await "); + iterate(nodep->exprp()); + if (nodep->isStatement()) puts(";\n"); + } virtual void visit(AstCNew* nodep) override { bool comma = false; puts("std::make_shared<" + prefixNameProtect(nodep->dtypep()) + ">("); diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp index a32f261d0..474964b26 100644 --- a/src/V3EmitCHeaders.cpp +++ b/src/V3EmitCHeaders.cpp @@ -313,6 +313,7 @@ class EmitCHeader final : public EmitCConstInit { if (v3Global.opt.mtasks()) puts("#include \"verilated_threads.h\"\n"); if (v3Global.opt.savable()) puts("#include \"verilated_save.h\"\n"); if (v3Global.opt.coverage()) puts("#include \"verilated_cov.h\"\n"); + if (v3Global.usesTiming()) puts("#include \"verilated_timing.h\"\n"); emitAll(modp); diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index a90b7fbbc..4791d25e5 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -254,6 +254,10 @@ class EmitCImp final : EmitCFunc { puts("("); putsQuoted(varp->nameProtect()); puts(")\n"); + } else if (dtypep->isDelayScheduler()) { + puts(", "); + puts(varp->nameProtect()); + puts("{*symsp->_vm_contextp__}\n"); } } } diff --git a/src/V3EmitCMain.cpp b/src/V3EmitCMain.cpp index c717b7751..776186b2c 100644 --- a/src/V3EmitCMain.cpp +++ b/src/V3EmitCMain.cpp @@ -80,7 +80,12 @@ private: puts(/**/ "// Evaluate model\n"); puts(/**/ "topp->eval();\n"); puts(/**/ "// Advance time\n"); - puts(/**/ "contextp->timeInc(1);\n"); + if (v3Global.rootp()->delaySchedulerp()) { + puts("if (!topp->eventsPending()) break;\n"); + puts("contextp->time(topp->nextTimeSlot());\n"); + } else { + puts("contextp->timeInc(1);\n"); + } puts("}\n"); puts("\n"); diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp index c053cc45a..48d0e628f 100644 --- a/src/V3EmitCMake.cpp +++ b/src/V3EmitCMake.cpp @@ -113,6 +113,8 @@ class CMakeEmitter final { cmake_set_raw(*of, name + "_SC", v3Global.opt.systemC() ? "1" : "0"); *of << "# Coverage output mode? 0/1 (from --coverage)\n"; cmake_set_raw(*of, name + "_COVERAGE", v3Global.opt.coverage() ? "1" : "0"); + *of << "# Timing mode? 0/1\n"; + cmake_set_raw(*of, name + "_TIMING", v3Global.usesTiming() ? "1" : "0"); *of << "# Threaded output mode? 0/1/N threads (from --threads)\n"; cmake_set_raw(*of, name + "_THREADS", cvtToStr(v3Global.opt.threads())); *of << "# VCD Tracing output mode? 0/1 (from --trace)\n"; @@ -169,6 +171,9 @@ class CMakeEmitter final { + ".cpp"); } } + if (v3Global.usesTiming()) { + global.emplace_back("${VERILATOR_ROOT}/include/verilated_timing.cpp"); + } if (v3Global.opt.threads()) { global.emplace_back("${VERILATOR_ROOT}/include/verilated_threads.cpp"); } diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp index 15919bfcb..443e4f3f8 100644 --- a/src/V3EmitCModel.cpp +++ b/src/V3EmitCModel.cpp @@ -114,6 +114,7 @@ class EmitCModel final : public EmitCFunc { } } } + if (optSystemC() && v3Global.usesTiming()) puts("sc_event trigger_eval;\n"); // Cells instantiated by the top level (for access to /* verilator public */) puts("\n// CELLS\n" @@ -162,7 +163,12 @@ class EmitCModel final : public EmitCFunc { if (!optSystemC()) { puts("/// Evaluate the model. Application must call when inputs change.\n"); } - puts("void eval() { eval_step(); " + callEvalEndStep + "}\n"); + if (optSystemC() && v3Global.usesTiming()) { + puts("void eval();\n"); + puts("void eval_sens();\n"); + } else { + puts("void eval() { eval_step(); " + callEvalEndStep + "}\n"); + } if (!optSystemC()) { puts("/// Evaluate when calling multiple units/models per time step.\n"); } @@ -184,6 +190,11 @@ class EmitCModel final : public EmitCFunc { ofp()->putsPrivate(false); // public: puts("void final();\n"); + puts("/// Are there scheduled events to handle?\n"); + puts("bool eventsPending();\n"); + puts("/// Returns time at next time slot. Aborts if !eventsPending()\n"); + puts("uint64_t nextTimeSlot();\n"); + if (v3Global.opt.trace()) { puts("/// Trace signals in the model; called by application code\n"); puts("void trace(" + v3Global.opt.traceClassBase() @@ -278,6 +289,7 @@ class EmitCModel final : public EmitCFunc { // Create sensitivity list for when to evaluate the model. putsDecoration("// Sensitivities on all clocks and combinational inputs\n"); puts("SC_METHOD(eval);\n"); + if (v3Global.usesTiming()) puts("SC_METHOD(eval_sens);\n"); for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { if (const AstVar* const varp = VN_CAST(nodep, Var)) { if (varp->isNonOutput() && (varp->isScSensitive() || varp->isUsedClock())) { @@ -343,6 +355,24 @@ class EmitCModel final : public EmitCFunc { puts("void " + topModNameProtected + "__" + protect("_eval_settle") + selfDecl + ";\n"); puts("void " + topModNameProtected + "__" + protect("_eval") + selfDecl + ";\n"); + if (optSystemC() && v3Global.usesTiming()) { + // ::eval + puts("\nvoid " + topClassName() + "::eval() {\n"); + puts("eval_step();\n"); + puts("if (eventsPending()) {\n"); + puts("sc_time dt = sc_time::from_value(nextTimeSlot() - contextp()->time());\n"); + puts("next_trigger(dt, trigger_eval);\n"); + puts("} else {\n"); + puts("next_trigger(trigger_eval);\n"); + puts("}\n"); + puts("}\n"); + + // ::eval_sens + puts("\nvoid " + topClassName() + "::eval_sens() {\n"); + puts("trigger_eval.notify();\n"); + puts("}\n"); + } + // ::eval_step puts("\nvoid " + topClassName() + "::eval_step() {\n"); puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+++++TOP Evaluate " + topClassName() @@ -408,6 +438,24 @@ class EmitCModel final : public EmitCFunc { puts("}\n"); } + if (v3Global.usesTiming()) { + putSectionDelimiter("Events and timing"); + if (auto* const delaySchedp = v3Global.rootp()->delaySchedulerp()) { + puts("bool " + topClassName() + "::eventsPending() { return !vlSymsp->TOP."); + puts(delaySchedp->nameProtect()); + puts(".empty(); }\n\n"); + puts("uint64_t " + topClassName() + "::nextTimeSlot() { return vlSymsp->TOP."); + puts(delaySchedp->nameProtect()); + puts(".nextTimeSlot(); }\n"); + } else { + puts("bool " + topClassName() + "::eventsPending() { return false; }\n\n"); + puts("uint64_t " + topClassName() + "::nextTimeSlot() {\n"); + puts("VL_FATAL_MT(__FILE__, __LINE__, \"\", \"%Error: No delays in the " + "design\");\n"); + puts("return 0;\n}\n"); + } + } + putSectionDelimiter("Utilities"); if (!optSystemC()) { diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index e4db53ede..f16bb959a 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -50,6 +50,10 @@ public: of.puts("\n### Switches...\n"); of.puts("# C11 constructs required? 0/1 (always on now)\n"); of.puts("VM_C11 = 1\n"); + of.puts("# Timing enabled? 0/1\n"); + of.puts("VM_TIMING = "); + of.puts(v3Global.usesTiming() ? "1" : "0"); + of.puts("\n"); of.puts("# Coverage output mode? 0/1 (from --coverage)\n"); of.puts("VM_COVERAGE = "); of.puts(v3Global.opt.coverage() ? "1" : "0"); @@ -108,6 +112,7 @@ public: putMakeClassEntry(of, v3Global.opt.traceSourceLang() + ".cpp"); } } + if (v3Global.usesTiming()) putMakeClassEntry(of, "verilated_timing.cpp"); if (v3Global.opt.threads()) putMakeClassEntry(of, "verilated_threads.cpp"); if (v3Global.opt.usesProfiler()) { putMakeClassEntry(of, "verilated_profiler.cpp"); diff --git a/src/V3Error.h b/src/V3Error.h index ab7177d34..1283ed785 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -51,12 +51,15 @@ public: I_TRACING, // Tracing is on/off from /*verilator tracing_on/off*/ I_LINT, // All lint messages I_DEF_NETTYPE_WIRE, // `default_nettype is WIRE (false=NONE) + I_TIMING, // Enable timing from /*verilator timing_on/off*/ // Error codes: E_DETECTARRAY, // Error: Unsupported: Can't detect changes on arrayed variable E_ENCAPSULATED, // Error: local/protected violation E_PORTSHORT, // Error: Output port is connected to a constant, electrical short E_UNSUPPORTED, // Error: Unsupported (generally) E_TASKNSVAR, // Error: Task I/O not simple + E_NEEDTIMINGOPT, // Error: --timing/--no-timing option not specified + E_NOTIMING, // Timing control encountered with --no-timing // // Warning codes: EC_FIRST_WARN, // Just a code so the program knows where to start warnings @@ -83,6 +86,8 @@ public: DEFPARAM, // Style: Defparam DECLFILENAME, // Declaration doesn't match filename DEPRECATED, // Feature will be deprecated + RISEFALLDLY, // Unsupported: rise/fall/turn-off delays + MINTYPMAXDLY, // Unsupported: min/typ/max delay expressions ENDLABEL, // End lable name mismatch EOFNEWLINE, // End-of-file missing newline GENCLK, // Generated Clock. Historical, never issued. @@ -135,8 +140,10 @@ public: USERINFO, // Elaboration time $info USERWARN, // Elaboration time $warning VARHIDDEN, // Hiding variable + WAITCONST, // Wait condition is constant WIDTH, // Width mismatch WIDTHCONCAT, // Unsized numbers/parameters in concatenations + ZERODLY, // #0 delay _ENUM_MAX // ***Add new elements below also*** }; @@ -157,16 +164,16 @@ public: // Leading spaces indicate it can't be disabled. " MIN", " INFO", " FATAL", " FATALEXIT", " FATALSRC", " ERROR", " FIRST_NAMED", // Boolean - " I_CELLDEFINE", " I_COVERAGE", " I_TRACING", " I_LINT", " I_DEF_NETTYPE_WIRE", + " I_CELLDEFINE", " I_COVERAGE", " I_TRACING", " I_LINT", " I_DEF_NETTYPE_WIRE", " I_TIMING", // Errors - "DETECTARRAY", "ENCAPSULATED", "PORTSHORT", "UNSUPPORTED", "TASKNSVAR", + "DETECTARRAY", "ENCAPSULATED", "PORTSHORT", "UNSUPPORTED", "TASKNSVAR", "NEEDTIMINGOPT", "NOTIMING", // Warnings " EC_FIRST_WARN", "ALWCOMBORDER", "ASSIGNDLY", "ASSIGNIN", "BADSTDPRAGMA", "BLKANDNBLK", "BLKLOOPINIT", "BLKSEQ", "BSSPACE", "CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CASTCONST", "CDCRSTLOGIC", "CLKDATA", "CMPCONST", "COLONPLUS", "COMBDLY", "CONTASSREG", - "DEFPARAM", "DECLFILENAME", "DEPRECATED", + "DEFPARAM", "DECLFILENAME", "DEPRECATED", "RISEFALLDLY", "MINTYPMAXDLY", "ENDLABEL", "EOFNEWLINE", "GENCLK", "HIERBLOCK", "IFDEPTH", "IGNOREDRETURN", "IMPERFECTSCH", "IMPLICIT", "IMPORTSTAR", "IMPURE", @@ -180,7 +187,7 @@ public: "UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS", "UNPACKED", "UNSIGNED", "UNUSED", "USERERROR", "USERFATAL", "USERINFO", "USERWARN", - "VARHIDDEN", "WIDTH", "WIDTHCONCAT", + "VARHIDDEN", "WAITCONST", "WIDTH", "WIDTHCONCAT", "ZERODLY", " MAX" }; // clang-format on @@ -197,7 +204,8 @@ public: bool pretendError() const { return (m_e == ASSIGNIN || m_e == BADSTDPRAGMA || m_e == BLKANDNBLK || m_e == BLKLOOPINIT || m_e == CONTASSREG || m_e == IMPURE || m_e == PINNOTFOUND || m_e == PKGNODECL - || m_e == PROCASSWIRE); // Says IEEE + || m_e == PROCASSWIRE // Says IEEE + || m_e == ZERODLY); } // Warnings to mention manual bool mentionManual() const { diff --git a/src/V3FileLine.h b/src/V3FileLine.h index f16bc5bca..078b5cafc 100644 --- a/src/V3FileLine.h +++ b/src/V3FileLine.h @@ -222,6 +222,8 @@ public: void coverageOn(bool flag) { warnOn(V3ErrorCode::I_COVERAGE, flag); } bool tracingOn() const { return m_warnOn.test(V3ErrorCode::I_TRACING); } void tracingOn(bool flag) { warnOn(V3ErrorCode::I_TRACING, flag); } + bool timingOn() const { return m_warnOn.test(V3ErrorCode::I_TIMING); } + void timingOn(bool flag) { warnOn(V3ErrorCode::I_TIMING, flag); } // METHODS - Global // and match what GCC outputs diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 88a9332d4..578d00dfe 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -247,6 +247,8 @@ private: m_substTreep = nodep->rhsp(); if (!VN_IS(nodep->lhsp(), NodeVarRef)) { clearSimple("ASSIGN(non-VARREF)"); + } else if (nodep->isTimingControl()) { + clearSimple("Timing control"); } else { iterateChildren(nodep); } @@ -343,6 +345,13 @@ private: VDouble0 m_statAssignMerged; // Statistic tracking // METHODS + void checkTimingControl(AstNode* nodep) { + if (nodep->isTimingControl() && m_logicVertexp) { + m_logicVertexp->clearReducibleAndDedupable("TimingControl"); + m_logicVertexp->setConsumed("TimingControl"); + } + } + void iterateNewStmt(AstNode* nodep, const char* nonReducibleReason, const char* consumeReason) { if (m_scopep) { @@ -357,6 +366,7 @@ private: } if (consumeReason) m_logicVertexp->setConsumed(consumeReason); if (VN_IS(nodep, SenItem)) m_logicVertexp->setConsumed("senItem"); + checkTimingControl(nodep); iterateChildren(nodep); m_logicVertexp = nullptr; } @@ -555,6 +565,7 @@ private: virtual void visit(AstNode* nodep) override { iterateChildren(nodep); if (nodep->isOutputter() && m_logicVertexp) m_logicVertexp->setConsumed("outputter"); + checkTimingControl(nodep); } public: diff --git a/src/V3Global.h b/src/V3Global.h index a8a051aa4..3addcf4ec 100644 --- a/src/V3Global.h +++ b/src/V3Global.h @@ -106,6 +106,7 @@ class V3Global final { bool m_needTraceDumper = false; // Need __Vm_dumperp in symbols bool m_dpi = false; // Need __Dpi include files bool m_hasEvents = false; // Design uses SystemVerilog named events + bool m_usesTiming = false; // Design uses timing constructs bool m_hasForceableSignals = false; // Need to apply V3Force pass bool m_hasSCTextSections = false; // Has `systemc_* sections that need to be emitted bool m_useParallelBuild = false; // Use parallel build for model @@ -148,6 +149,8 @@ public: void dpi(bool flag) { m_dpi = flag; } bool hasEvents() const { return m_hasEvents; } void setHasEvents() { m_hasEvents = true; } + bool usesTiming() const { return m_usesTiming; } + void setUsesTiming() { m_usesTiming = true; } bool hasForceableSignals() const { return m_hasForceableSignals; } void setHasForceableSignals() { m_hasForceableSignals = true; } bool hasSCTextSections() const { return m_hasSCTextSections; } diff --git a/src/V3Hasher.cpp b/src/V3Hasher.cpp index 53a276c89..bd6417414 100644 --- a/src/V3Hasher.cpp +++ b/src/V3Hasher.cpp @@ -262,6 +262,11 @@ private: m_hash += nodep->name(); }); } + virtual void visit(AstCAwait* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + iterateNull(nodep->sensesp()); + }); + } virtual void visit(AstCoverInc* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // iterateNull(nodep->declp()); diff --git a/src/V3InstrCount.cpp b/src/V3InstrCount.cpp index d0ec37562..e07db1461 100644 --- a/src/V3InstrCount.cpp +++ b/src/V3InstrCount.cpp @@ -42,6 +42,7 @@ private: const AstNode* const m_startNodep; // Start node of count bool m_tracingCall = false; // Iterating into a CCall to a CFunc bool m_inCFunc = false; // Inside AstCFunc + bool m_ignoreRemaining = false; // Ignore remaining statements in the block const bool m_assertNoDups; // Check for duplicates const std::ostream* const m_osp; // Dump file @@ -81,7 +82,12 @@ public: uint32_t instrCount() const { return m_instrCount; } private: + void reset() { + m_instrCount = 0; + m_ignoreRemaining = false; + } uint32_t startVisitBase(AstNode* nodep) { + UASSERT_OBJ(!m_ignoreRemaining, nodep, "Should not reach here if ignoring"); if (m_assertNoDups && !m_inCFunc) { // Ensure we don't count the same node twice // @@ -110,7 +116,7 @@ private: void endVisitBase(uint32_t savedCount, AstNode* nodep) { UINFO(8, "cost " << std::setw(6) << std::left << m_instrCount << " " << nodep << endl); markCost(nodep); - m_instrCount += savedCount; + if (!m_ignoreRemaining) m_instrCount += savedCount; } void markCost(AstNode* nodep) { if (m_osp) nodep->user4(m_instrCount + 1); // Else don't mark to avoid writeback @@ -118,6 +124,7 @@ private: // VISITORS virtual void visit(AstNodeSel* nodep) override { + if (m_ignoreRemaining) return; // This covers both AstArraySel and AstWordSel // // If some vector is a bazillion dwords long, and we're selecting 1 @@ -129,6 +136,7 @@ private: iterateAndNextNull(nodep->bitp()); } virtual void visit(AstSel* nodep) override { + if (m_ignoreRemaining) return; // Similar to AstNodeSel above, a small select into a large vector // is not expensive. Count the cost of the AstSel itself (scales with // its width) and the cost of the lsbp() and widthp() nodes, but not @@ -144,6 +152,7 @@ private: nodep->v3fatalSrc("AstMemberSel unhandled"); } virtual void visit(AstConcat* nodep) override { + if (m_ignoreRemaining) return; // Nop. // // Ignore concat. The problem with counting concat is that when we @@ -164,22 +173,24 @@ private: markCost(nodep); } virtual void visit(AstNodeIf* nodep) override { + if (m_ignoreRemaining) return; const VisitBase vb{this, nodep}; iterateAndNextNull(nodep->condp()); const uint32_t savedCount = m_instrCount; UINFO(8, "ifsp:\n"); - m_instrCount = 0; + reset(); iterateAndNextNull(nodep->ifsp()); uint32_t ifCount = m_instrCount; if (nodep->branchPred().unlikely()) ifCount = 0; UINFO(8, "elsesp:\n"); - m_instrCount = 0; + reset(); iterateAndNextNull(nodep->elsesp()); uint32_t elseCount = m_instrCount; if (nodep->branchPred().likely()) elseCount = 0; + reset(); if (ifCount >= elseCount) { m_instrCount = savedCount + ifCount; if (nodep->elsesp()) nodep->elsesp()->user4(0); // Don't dump it @@ -189,6 +200,7 @@ private: } } virtual void visit(AstNodeCond* nodep) override { + if (m_ignoreRemaining) return; // Just like if/else above, the ternary operator only evaluates // one of the two expressions, so only count the max. const VisitBase vb{this, nodep}; @@ -196,15 +208,16 @@ private: const uint32_t savedCount = m_instrCount; UINFO(8, "?\n"); - m_instrCount = 0; + reset(); iterateAndNextNull(nodep->expr1p()); const uint32_t ifCount = m_instrCount; UINFO(8, ":\n"); - m_instrCount = 0; + reset(); iterateAndNextNull(nodep->expr2p()); const uint32_t elseCount = m_instrCount; + reset(); if (ifCount < elseCount) { m_instrCount = savedCount + elseCount; if (nodep->expr1p()) nodep->expr1p()->user4(0); // Don't dump it @@ -213,6 +226,25 @@ private: if (nodep->expr2p()) nodep->expr2p()->user4(0); // Don't dump it } } + virtual void visit(AstCAwait* nodep) override { + if (m_ignoreRemaining) return; + iterateChildren(nodep); + // Anything past a co_await is irrelevant + m_ignoreRemaining = true; + } + virtual void visit(AstFork* nodep) override { + if (m_ignoreRemaining) return; + const VisitBase vb{this, nodep}; + uint32_t totalCount = m_instrCount; + // Sum counts in each statement until the first await + for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { + reset(); + iterate(stmtp); + totalCount += m_instrCount; + } + m_instrCount = totalCount; + m_ignoreRemaining = false; + } virtual void visit(AstActive* nodep) override { // You'd think that the OrderLogicVertex's would be disjoint trees // of stuff in the AST, but it isn't so: V3Order makes an @@ -230,6 +262,7 @@ private: UASSERT_OBJ(nodep == m_startNodep, nodep, "Multiple actives, or not start node"); } virtual void visit(AstNodeCCall* nodep) override { + if (m_ignoreRemaining) return; const VisitBase vb{this, nodep}; iterateChildren(nodep); m_tracingCall = true; @@ -241,6 +274,7 @@ private: // from the root UASSERT_OBJ(m_tracingCall || nodep == m_startNodep, nodep, "AstCFunc not under AstCCall, or not start node"); + UASSERT_OBJ(!m_ignoreRemaining, nodep, "Should not be ignoring at the start of a CFunc"); m_tracingCall = false; VL_RESTORER(m_inCFunc); { @@ -248,8 +282,10 @@ private: const VisitBase vb{this, nodep}; iterateChildren(nodep); } + m_ignoreRemaining = false; } virtual void visit(AstNode* nodep) override { + if (m_ignoreRemaining) return; const VisitBase vb{this, nodep}; iterateChildren(nodep); } diff --git a/src/V3Life.cpp b/src/V3Life.cpp index 112c3920e..6a704b5ae 100644 --- a/src/V3Life.cpp +++ b/src/V3Life.cpp @@ -306,6 +306,12 @@ private: } } virtual void visit(AstNodeAssign* nodep) override { + if (nodep->isTimingControl()) { + // V3Life doesn't understand time sense - don't optimize + setNoopt(); + iterateChildren(nodep); + return; + } // Collect any used variables first, as lhs may also be on rhs // Similar code in V3Dead const uint64_t lastEdit = AstNode::editCountGbl(); // When it was last edited @@ -326,7 +332,12 @@ private: } } virtual void visit(AstAssignDly* nodep) override { - // Don't treat as normal assign; V3Life doesn't understand time sense + // V3Life doesn't understand time sense + if (nodep->isTimingControl()) { + // Don't optimize + setNoopt(); + } + // Don't treat as normal assign iterateChildren(nodep); } @@ -433,7 +444,13 @@ private: } virtual void visit(AstVar*) override {} // Don't want varrefs under it - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + virtual void visit(AstNode* nodep) override { + if (nodep->isTimingControl()) { + // V3Life doesn't understand time sense - don't optimize + setNoopt(); + } + iterateChildren(nodep); + } public: // CONSTRUCTORS diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp index 66dcbf8e1..a74bda289 100644 --- a/src/V3LinkInc.cpp +++ b/src/V3LinkInc.cpp @@ -149,6 +149,25 @@ private: nodep->v3fatalSrc( "For statements should have been converted to while statements in V3Begin.cpp"); } + virtual void visit(AstDelay* nodep) override { + m_insStmtp = nodep; + iterateAndNextNull(nodep->lhsp()); + m_insStmtp = nullptr; + iterateAndNextNull(nodep->stmtsp()); + m_insStmtp = nullptr; + } + virtual void visit(AstEventControl* nodep) override { + m_insStmtp = nullptr; + iterateAndNextNull(nodep->stmtsp()); + m_insStmtp = nullptr; + } + virtual void visit(AstWait* nodep) override { + m_insStmtp = nodep; + iterateAndNextNull(nodep->condp()); + m_insStmtp = nullptr; + iterateAndNextNull(nodep->bodysp()); + m_insStmtp = nullptr; + } virtual void visit(AstNodeStmt* nodep) override { if (!nodep->isStatement()) { iterateChildren(nodep); diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp index 9b85ac6f6..db3429fdb 100644 --- a/src/V3LinkJump.cpp +++ b/src/V3LinkJump.cpp @@ -175,17 +175,6 @@ private: nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } - virtual void visit(AstWait* nodep) override { - nodep->v3warn(E_UNSUPPORTED, "Unsupported: wait statements"); - // Statements we'll just execute immediately; equivalent to if they followed this - if (AstNode* const bodysp = nodep->bodysp()) { - bodysp->unlinkFrBackWithNext(); - nodep->replaceWith(bodysp); - } else { - nodep->unlinkFrBack(); - } - VL_DO_DANGLING(nodep->deleteTree(), nodep); - } virtual void visit(AstWhile* nodep) override { // Don't need to track AstRepeat/AstFor as they have already been converted VL_RESTORER(m_loopp); diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 705c40828..4558190df 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -593,9 +593,7 @@ private: << nodep->warnMore() << "... Suggest use a normal 'always'"); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } else if (alwaysp && !alwaysp->sensesp()) { - // Verilator is still ony supporting SenTrees under an always, - // so allow the parser to handle everything and shim to - // historical AST here + // If the event control is at the top, move the sentree to the always if (AstSenTree* const sensesp = nodep->sensesp()) { sensesp->unlinkFrBackWithNext(); alwaysp->sensesp(sensesp); diff --git a/src/V3Options.cpp b/src/V3Options.cpp index ed192262b..cac9b2312 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -715,6 +715,14 @@ bool V3Options::systemCFound() { || (!getenvSYSTEMC_INCLUDE().empty() && !getenvSYSTEMC_LIBDIR().empty())); } +bool V3Options::coroutineSupport() { +#ifdef HAVE_COROUTINES + return true; +#else + return false; +#endif +} + //###################################################################### // V3 Options notification methods @@ -1370,6 +1378,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char m_timeOverridePrec = prec; } }); + DECL_OPTION("-timing", OnOff, &m_timing); DECL_OPTION("-top-module", Set, &m_topModule); DECL_OPTION("-top", Set, &m_topModule); DECL_OPTION("-trace", OnOff, &m_trace); @@ -1748,6 +1757,7 @@ void V3Options::showVersion(bool verbose) { cout << endl; cout << "Features (based on environment or compiled-in support):\n"; cout << " SystemC found = " << cvtToStr(systemCFound()) << endl; + cout << " Coroutine support = " << cvtToStr(coroutineSupport()) << endl; } //====================================================================== diff --git a/src/V3Options.h b/src/V3Options.h index 6ebfe19a9..4b1b7a016 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -271,6 +271,7 @@ private: bool m_threadsCoarsen = true; // main switch: --threads-coarsen bool m_threadsDpiPure = true; // main switch: --threads-dpi all/pure bool m_threadsDpiUnpure = false; // main switch: --threads-dpi all + VOptionBool m_timing; // main switch: --timing bool m_trace = false; // main switch: --trace bool m_traceCoverage = false; // main switch: --trace-coverage bool m_traceParams = true; // main switch: --trace-params @@ -456,6 +457,7 @@ public: bool threadsDpiPure() const { return m_threadsDpiPure; } bool threadsDpiUnpure() const { return m_threadsDpiUnpure; } bool threadsCoarsen() const { return m_threadsCoarsen; } + VOptionBool timing() const { return m_timing; } bool trace() const { return m_trace; } bool traceCoverage() const { return m_traceCoverage; } bool traceParams() const { return m_traceParams; } @@ -647,6 +649,7 @@ public: static string getenvVERILATOR_ROOT(); static bool systemCSystemWide(); static bool systemCFound(); // SystemC installed, or environment points to it + static bool coroutineSupport(); // Compiler supports coroutines // METHODS (file utilities using these options) string fileExists(const string& filename); diff --git a/src/V3Order.cpp b/src/V3Order.cpp index c335553c6..bb133e8b8 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -1276,17 +1276,24 @@ AstActive* OrderProcess::processMoveOneLogic(const OrderLogicVertex* lvertexp, // Process procedures per statement (unless profCFuncs), so we can split CFuncs within // procedures. Everything else is handled in one go + bool suspendable = false; + bool slow = m_slow; if (AstNodeProcedure* const procp = VN_CAST(nodep, NodeProcedure)) { + suspendable = procp->isSuspendable(); + if (suspendable) slow = slow && !VN_IS(procp, Always); nodep = procp->bodysp(); pushDeletep(procp); } + // Put suspendable processes into individual functions on their own + if (suspendable) newFuncpr = nullptr; + // When profCFuncs, create a new function for all logic block if (v3Global.opt.profCFuncs()) newFuncpr = nullptr; while (nodep) { // Split the CFunc if too large (but not when profCFuncs) - if (!v3Global.opt.profCFuncs() + if (!suspendable && !v3Global.opt.profCFuncs() && (v3Global.opt.outputSplitCFuncs() && v3Global.opt.outputSplitCFuncs() < newStmtsr)) { // Put every statement into a unique function to ease profiling or reduce function @@ -1295,10 +1302,11 @@ AstActive* OrderProcess::processMoveOneLogic(const OrderLogicVertex* lvertexp, } if (!newFuncpr && domainp != m_deleteDomainp) { const string name = cfuncName(modp, domainp, scopep, nodep); - newFuncpr = new AstCFunc(nodep->fileline(), name, scopep); + newFuncpr + = new AstCFunc{nodep->fileline(), name, scopep, suspendable ? "VlCoroutine" : ""}; newFuncpr->isStatic(false); newFuncpr->isLoose(true); - newFuncpr->slow(m_slow); + newFuncpr->slow(slow); newStmtsr = 0; scopep->addActivep(newFuncpr); // Create top call to it @@ -1328,6 +1336,8 @@ AstActive* OrderProcess::processMoveOneLogic(const OrderLogicVertex* lvertexp, nodep = nextp; } + // Put suspendable processes into individual functions on their own + if (suspendable) newFuncpr = nullptr; return activep; } diff --git a/src/V3Sched.cpp b/src/V3Sched.cpp index e3f875327..af027ccb4 100644 --- a/src/V3Sched.cpp +++ b/src/V3Sched.cpp @@ -47,7 +47,6 @@ #include "V3Stats.h" #include "V3UniqueNames.h" -#include #include namespace V3Sched { @@ -202,30 +201,45 @@ LogicClasses gatherLogicClasses(AstNetlist* netlistp) { // Simple ordering in source order void orderSequentially(AstCFunc* funcp, const LogicByScope& lbs) { + // Create new subfunc for scope + const auto createNewSubFuncp = [&](AstScope* const scopep) { + const string subName{funcp->name() + "__" + scopep->nameDotless()}; + AstCFunc* const subFuncp = new AstCFunc{scopep->fileline(), subName, scopep}; + subFuncp->isLoose(true); + subFuncp->isConst(false); + subFuncp->declPrivate(true); + subFuncp->slow(funcp->slow()); + scopep->addActivep(subFuncp); + // Call it from the top function + funcp->addStmtsp(new AstCCall{scopep->fileline(), subFuncp}); + return subFuncp; + }; const VNUser1InUse user1InUse; // AstScope -> AstCFunc: the sub-function for the scope + const VNUser2InUse user2InUse; // AstScope -> int: sub-function counter used for names for (const auto& pair : lbs) { AstScope* const scopep = pair.first; AstActive* const activep = pair.second; - if (!scopep->user1p()) { - // Create a sub-function per scope so we can V3Combine them later - const string subName{funcp->name() + "__" + scopep->nameDotless()}; - AstCFunc* const subFuncp = new AstCFunc{scopep->fileline(), subName, scopep}; - subFuncp->isLoose(true); - subFuncp->isConst(false); - subFuncp->declPrivate(true); - subFuncp->slow(funcp->slow()); - scopep->addActivep(subFuncp); - scopep->user1p(subFuncp); - // Call it from the top function - funcp->addStmtsp(new AstCCall{scopep->fileline(), subFuncp}); - } - AstCFunc* const subFuncp = VN_AS(scopep->user1p(), CFunc); + // Create a sub-function per scope so we can V3Combine them later + if (!scopep->user1p()) scopep->user1p(createNewSubFuncp(scopep)); // Add statements to sub-function for (AstNode *logicp = activep->stmtsp(), *nextp; logicp; logicp = nextp) { + auto* subFuncp = VN_AS(scopep->user1p(), CFunc); nextp = logicp->nextp(); if (AstNodeProcedure* const procp = VN_CAST(logicp, NodeProcedure)) { - if (AstNode* const bodyp = procp->bodysp()) { + if (AstNode* bodyp = procp->bodysp()) { bodyp->unlinkFrBackWithNext(); + // If the process is suspendable, we need a separate function (a coroutine) + if (procp->isSuspendable()) { + subFuncp = createNewSubFuncp(scopep); + subFuncp->name(subFuncp->name() + "__" + cvtToStr(scopep->user2Inc())); + subFuncp->rtnType("VlCoroutine"); + if (VN_IS(procp, Always)) { + subFuncp->slow(false); + FileLine* const flp = procp->fileline(); + bodyp + = new AstWhile{flp, new AstConst{flp, AstConst::BitTrue{}}, bodyp}; + } + } subFuncp->addStmtsp(bodyp); } } else { @@ -432,6 +446,8 @@ class SenExprBuilder final { callp->dtypeSetBit(); return {callp, false}; } + case VEdgeType::ET_TRUE: // + return {currp(), false}; default: // LCOV_EXCL_START senItemp->v3fatalSrc("Unknown edge type"); return {nullptr, false}; @@ -937,7 +953,8 @@ void createEval(AstNetlist* netlistp, // AstVarScope* preTrigsp, // AstVarScope* nbaTrigsp, // AstCFunc* actFuncp, // - AstCFunc* nbaFuncp // + AstCFunc* nbaFuncp, // + TimingKit& timingKit // ) { FileLine* const flp = netlistp->fileline(); @@ -967,7 +984,10 @@ void createEval(AstNetlist* netlistp, // = makeEvalLoop( netlistp, "act", "Active", actTrig.m_vscp, actTrig.m_dumpp, [&]() { // Trigger - return new AstCCall{flp, actTrig.m_funcp}; + auto* const resultp = new AstCCall{flp, actTrig.m_funcp}; + // Commit trigger awaits from the previous iteration + resultp->addNextNull(timingKit.createCommit(netlistp)); + return resultp; }, [&]() { // Body AstNode* resultp = nullptr; @@ -994,6 +1014,9 @@ void createEval(AstNetlist* netlistp, // resultp = AstNode::addNext(resultp, callp); } + // Resume triggered timing schedulers + resultp = AstNode::addNextNull(resultp, timingKit.createResume(netlistp)); + // Invoke body function return AstNode::addNext(resultp, new AstCCall{flp, actFuncp}); }) @@ -1039,6 +1062,9 @@ void schedule(AstNetlist* netlistp) { V3Stats::addStat("Scheduling, " + name, size); }; + // Step 0. Prepare timing-related logic and external domains + auto timingKit = prepareTiming(netlistp); + // Step 1. Gather and classify all logic in the design LogicClasses logicClasses = gatherLogicClasses(netlistp); @@ -1113,7 +1139,8 @@ void schedule(AstNetlist* netlistp) { const auto& senTreeps = getSenTreesUsedBy({&logicRegions.m_pre, // &logicRegions.m_act, // - &logicRegions.m_nba}); + &logicRegions.m_nba, // + &timingKit.m_lbs}); const TriggerKit& actTrig = createTriggers(netlistp, senExprBuilder, senTreeps, "act", extraTriggers); @@ -1163,6 +1190,8 @@ void schedule(AstNetlist* netlistp) { remapSensitivities(logicRegions.m_pre, preTrigMap); remapSensitivities(logicRegions.m_act, actTrigMap); remapSensitivities(logicReplicas.m_act, actTrigMap); + remapSensitivities(timingKit.m_lbs, actTrigMap); + const auto& actTimingDomains = timingKit.remapDomains(actTrigMap); // Create the inverse map from trigger ref AstSenTree to original AstSenTree std::unordered_map trigToSenAct; @@ -1175,7 +1204,9 @@ void schedule(AstNetlist* netlistp) { AstCFunc* const actFuncp = V3Order::order( netlistp, {&logicRegions.m_pre, &logicRegions.m_act, &logicReplicas.m_act}, trigToSenAct, - "act", false, false, [=](const AstVarScope* vscp, std::vector& out) { + "act", false, false, [&](const AstVarScope* vscp, std::vector& out) { + auto it = actTimingDomains.find(vscp); + if (it != actTimingDomains.end()) out = it->second; if (vscp->varp()->isWrittenByDpi()) out.push_back(dpiExportTriggeredAct); }); splitCheck(actFuncp); @@ -1186,6 +1217,7 @@ void schedule(AstNetlist* netlistp) { // Remap sensitivities of the input logic to the triggers remapSensitivities(logicRegions.m_nba, nbaTrigMap); remapSensitivities(logicReplicas.m_nba, nbaTrigMap); + const auto& nbaTimingDomains = timingKit.remapDomains(nbaTrigMap); // Create the inverse map from trigger ref AstSenTree to original AstSenTree std::unordered_map trigToSenNba; @@ -1196,7 +1228,9 @@ void schedule(AstNetlist* netlistp) { AstCFunc* const nbaFuncp = V3Order::order( netlistp, {&logicRegions.m_nba, &logicReplicas.m_nba}, trigToSenNba, "nba", - v3Global.opt.mtasks(), false, [=](const AstVarScope* vscp, std::vector& out) { + v3Global.opt.mtasks(), false, [&](const AstVarScope* vscp, std::vector& out) { + auto it = nbaTimingDomains.find(vscp); + if (it != nbaTimingDomains.end()) out = it->second; if (vscp->varp()->isWrittenByDpi()) out.push_back(dpiExportTriggeredNba); }); splitCheck(nbaFuncp); @@ -1204,7 +1238,10 @@ void schedule(AstNetlist* netlistp) { if (v3Global.opt.stats()) V3Stats::statsStage("sched-create-nba"); // Step 11: Bolt it all together to create the '_eval' function - createEval(netlistp, icoLoopp, actTrig, preTrigVscp, nbaTrigVscp, actFuncp, nbaFuncp); + createEval(netlistp, icoLoopp, actTrig, preTrigVscp, nbaTrigVscp, actFuncp, nbaFuncp, + timingKit); + + transformForks(netlistp); splitCheck(initp); diff --git a/src/V3Sched.h b/src/V3Sched.h index 71bc1773f..876b0a510 100644 --- a/src/V3Sched.h +++ b/src/V3Sched.h @@ -23,6 +23,7 @@ #include "V3Ast.h" #include +#include #include #include @@ -113,6 +114,41 @@ struct LogicReplicas final { LogicReplicas& operator=(LogicReplicas&&) = default; }; +// Everything needed for combining timing with static scheduling. +class TimingKit final { + AstCFunc* m_resumeFuncp = nullptr; // Global timing resume function + AstCFunc* m_commitFuncp = nullptr; // Global timing commit function + + // Additional var sensitivities for V3Order + std::map> m_externalDomains; + +public: + LogicByScope m_lbs; // Actives that resume timing schedulers + + // Remaps external domains using the specified trigger map + std::map> + remapDomains(const std::unordered_map& trigMap) const; + // Creates a timing resume call (if needed, else returns null) + AstCCall* createResume(AstNetlist* const netlistp); + // Creates a timing commit call (if needed, else returns null) + AstCCall* createCommit(AstNetlist* const netlistp); + + TimingKit() = default; + TimingKit(LogicByScope&& lbs, + std::map>&& externalDomains) + : m_externalDomains{externalDomains} + , m_lbs{lbs} {} + VL_UNCOPYABLE(TimingKit); + TimingKit(TimingKit&&) = default; + TimingKit& operator=(TimingKit&&) = default; +}; + +// Creates the timing kit and marks variables written by suspendables +TimingKit prepareTiming(AstNetlist* const netlistp); + +// Transforms fork sub-statements into separate functions +void transformForks(AstNetlist* const netlistp); + // Top level entry point to scheduling void schedule(AstNetlist*); diff --git a/src/V3SchedReplicate.cpp b/src/V3SchedReplicate.cpp index 228f66be8..347cc6a66 100644 --- a/src/V3SchedReplicate.cpp +++ b/src/V3SchedReplicate.cpp @@ -124,6 +124,10 @@ public: if (varp()->isPrimaryInish() || varp()->isSigUserRWPublic() || varp()->isWrittenByDpi()) { addDrivingRegions(INPUT); } + // Currently we always execute suspendable processes at the beginning of + // the act region, which means combinational logic driven from a suspendable + // processes must be present in the 'act' region + if (varp()->isWrittenBySuspendable()) addDrivingRegions(ACTIVE); } AstVarScope* vscp() const { return m_vscp; } AstVar* varp() const { return m_vscp->varp(); } diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp new file mode 100644 index 000000000..5d22976ad --- /dev/null +++ b/src/V3SchedTiming.cpp @@ -0,0 +1,361 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Code scheduling +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-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 +// +//************************************************************************* +// +// Functions defined in this file are used by V3Sched.cpp to properly integrate +// static scheduling with timing features. They create external domains for +// variables, remap them to trigger vectors, and create timing resume/commit +// calls for the global eval loop. There is also a function that transforms +// forks into emittable constructs. +// +// See the internals documentation docs/internals.rst for more details. +// +//************************************************************************* + +#include "config_build.h" +#include "verilatedos.h" + +#include "V3EmitCBase.h" +#include "V3Sched.h" + +#include + +namespace V3Sched { + +//============================================================================ +// Remaps external domains using the specified trigger map + +std::map> +TimingKit::remapDomains(const std::unordered_map& trigMap) const { + std::map> remappedDomainMap; + for (const auto& vscpDomains : m_externalDomains) { + const AstVarScope* const vscp = vscpDomains.first; + const auto& domains = vscpDomains.second; + auto& remappedDomains = remappedDomainMap[vscp]; + remappedDomains.reserve(domains.size()); + for (AstSenTree* const domainp : domains) { + remappedDomains.push_back(trigMap.at(domainp)); + } + } + return remappedDomainMap; +} + +//============================================================================ +// Creates a timing resume call (if needed, else returns null) + +AstCCall* TimingKit::createResume(AstNetlist* const netlistp) { + if (!m_resumeFuncp) { + if (m_lbs.empty()) return nullptr; + // Create global resume function + AstScope* const scopeTopp = netlistp->topScopep()->scopep(); + m_resumeFuncp = new AstCFunc{netlistp->fileline(), "_timing_resume", scopeTopp, ""}; + m_resumeFuncp->dontCombine(true); + m_resumeFuncp->isLoose(true); + m_resumeFuncp->isConst(false); + m_resumeFuncp->declPrivate(true); + scopeTopp->addActivep(m_resumeFuncp); + for (auto& p : m_lbs) { + // Put all the timing actives in the resume function + AstActive* const activep = p.second; + m_resumeFuncp->addStmtsp(activep); + } + } + return new AstCCall{m_resumeFuncp->fileline(), m_resumeFuncp}; +} + +//============================================================================ +// Creates a timing commit call (if needed, else returns null) + +AstCCall* TimingKit::createCommit(AstNetlist* const netlistp) { + if (!m_commitFuncp) { + for (auto& p : m_lbs) { + AstActive* const activep = p.second; + auto* const resumep = VN_AS(activep->stmtsp(), CMethodHard); + UASSERT_OBJ(!resumep->nextp(), resumep, "Should be the only statement here"); + AstVarScope* const schedulerp = VN_AS(resumep->fromp(), VarRef)->varScopep(); + UASSERT_OBJ(schedulerp->dtypep()->basicp()->isDelayScheduler() + || schedulerp->dtypep()->basicp()->isTriggerScheduler(), + schedulerp, "Unexpected type"); + if (!schedulerp->dtypep()->basicp()->isTriggerScheduler()) continue; + // Create the global commit function only if we have trigger schedulers + if (!m_commitFuncp) { + AstScope* const scopeTopp = netlistp->topScopep()->scopep(); + m_commitFuncp + = new AstCFunc{netlistp->fileline(), "_timing_commit", scopeTopp, ""}; + m_commitFuncp->dontCombine(true); + m_commitFuncp->isLoose(true); + m_commitFuncp->isConst(false); + m_commitFuncp->declPrivate(true); + scopeTopp->addActivep(m_commitFuncp); + } + AstSenTree* const sensesp = activep->sensesp(); + FileLine* const flp = sensesp->fileline(); + // Negate the sensitivity. We will commit only if the event wasn't triggered on the + // current iteration + auto* const negSensesp = sensesp->cloneTree(false); + negSensesp->sensesp()->sensp( + new AstLogNot{flp, negSensesp->sensesp()->sensp()->unlinkFrBack()}); + sensesp->addNextHere(negSensesp); + auto* const newactp = new AstActive{flp, "", negSensesp}; + // Create the commit call and put it in the commit function + auto* const commitp = new AstCMethodHard{ + flp, new AstVarRef{flp, schedulerp, VAccess::READWRITE}, "commit"}; + commitp->addPinsp(resumep->pinsp()->cloneTree(false)); + commitp->statement(true); + commitp->dtypeSetVoid(); + newactp->addStmtsp(commitp); + m_commitFuncp->addStmtsp(newactp); + } + // We still haven't created a commit function (no trigger schedulers), return null + if (!m_commitFuncp) return nullptr; + } + return new AstCCall{m_commitFuncp->fileline(), m_commitFuncp}; +} + +//============================================================================ +// Creates the timing kit and marks variables written by suspendables + +TimingKit prepareTiming(AstNetlist* const netlistp) { + if (!v3Global.usesTiming()) return {}; + class AwaitVisitor final : public VNVisitor { + private: + // NODE STATE + // AstSenTree::user1() -> bool. Set true if the sentree has been visited. + const VNUser1InUse m_inuser1; + + // STATE + bool m_inProcess = false; // Are we in a process? + bool m_gatherVars = false; // Should we gather vars in m_writtenBySuspendable? + AstScope* const m_scopeTopp; // Scope at the top + LogicByScope& m_lbs; // Timing resume actives + // Additional var sensitivities + std::map>& m_externalDomains; + std::set m_processDomains; // Sentrees from the current process + // Variables written by suspendable processes + std::vector m_writtenBySuspendable; + + // METHODS + // Create an active with a timing scheduler resume() call + void createResumeActive(AstCAwait* const awaitp) { + auto* const methodp = VN_AS(awaitp->exprp(), CMethodHard); + AstVarScope* const schedulerp = VN_AS(methodp->fromp(), VarRef)->varScopep(); + AstSenTree* const sensesp = awaitp->sensesp(); + FileLine* const flp = sensesp->fileline(); + // Create a resume() call on the timing scheduler + auto* const resumep = new AstCMethodHard{ + flp, new AstVarRef{flp, schedulerp, VAccess::READWRITE}, "resume"}; + if (schedulerp->dtypep()->basicp()->isTriggerScheduler()) { + resumep->addPinsp(methodp->pinsp()->cloneTree(false)); + } + resumep->statement(true); + resumep->dtypeSetVoid(); + // Put it in an active and put that in the global resume function + auto* const activep = new AstActive{flp, "_timing", sensesp}; + activep->addStmtsp(resumep); + m_lbs.emplace_back(m_scopeTopp, activep); + } + + // VISITORS + virtual void visit(AstNodeProcedure* const nodep) override { + UASSERT_OBJ(!m_inProcess && !m_gatherVars && m_processDomains.empty() + && m_writtenBySuspendable.empty(), + nodep, "Process in process?"); + m_inProcess = true; + m_gatherVars = nodep->isSuspendable(); // Only gather vars in a suspendable + const VNUser2InUse user2InUse; // AstVarScope -> bool: Set true if var has been added + // to m_writtenBySuspendable + iterateChildren(nodep); + for (AstVarScope* const vscp : m_writtenBySuspendable) { + m_externalDomains[vscp].insert(m_processDomains.begin(), m_processDomains.end()); + vscp->varp()->setWrittenBySuspendable(); + } + m_processDomains.clear(); + m_writtenBySuspendable.clear(); + m_inProcess = false; + m_gatherVars = false; + } + virtual void visit(AstFork* nodep) override { + VL_RESTORER(m_gatherVars); + if (m_inProcess) m_gatherVars = true; + // If not in a process, we don't need to gather variables or domains + iterateChildren(nodep); + } + virtual void visit(AstCAwait* nodep) override { + if (AstSenTree* const sensesp = nodep->sensesp()) { + if (!sensesp->user1SetOnce()) createResumeActive(nodep); + nodep->clearSensesp(); // Clear as these sentrees will get deleted later + if (m_inProcess) m_processDomains.insert(sensesp); + } + } + virtual void visit(AstNodeVarRef* nodep) override { + if (m_gatherVars && nodep->access().isWriteOrRW() + && !nodep->varScopep()->user2SetOnce()) { + m_writtenBySuspendable.push_back(nodep->varScopep()); + } + } + + //-------------------- + virtual void visit(AstNodeMath*) override {} // Accelerate + virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + + public: + // CONSTRUCTORS + explicit AwaitVisitor(AstNetlist* nodep, LogicByScope& lbs, + std::map>& externalDomains) + : m_scopeTopp{nodep->topScopep()->scopep()} + , m_lbs{lbs} + , m_externalDomains{externalDomains} { + iterate(nodep); + } + virtual ~AwaitVisitor() override = default; + }; + LogicByScope lbs; + std::map> externalDomains; + AwaitVisitor{netlistp, lbs, externalDomains}; + return {std::move(lbs), std::move(externalDomains)}; +} + +//============================================================================ +// Visits all forks and transforms their sub-statements into separate functions. + +void transformForks(AstNetlist* const netlistp) { + if (!v3Global.usesTiming()) return; + // Transform all forked processes into functions + class ForkVisitor final : public VNVisitor { + private: + // NODE STATE + // AstVar::user1() -> bool. Set true if the variable was declared before the current + // fork. + const VNUser1InUse m_inuser1; + + // STATE + bool m_inClass = false; // Are we in a class? + AstFork* m_forkp = nullptr; // Current fork + AstCFunc* m_funcp = nullptr; // Current function + + // METHODS + // Remap local vars referenced by the given fork function + // TODO: We should only pass variables to the fork that are + // live in the fork body, but for that we need a proper data + // flow analysis framework which we don't have at the moment + void remapLocals(AstCFunc* const funcp, AstCCall* const callp) { + const VNUser2InUse user2InUse; // AstVarScope -> AstVarScope: var to remap to + 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"); + // Only handle vars passed by value or locals declared before the fork + if (!passByValue && (!varp->user1() || !varp->isFuncLocal())) return; + if (passByValue) { + // We can just pass it to the new function + } else if (m_forkp->joinType().join()) { + // If it's fork..join, we can refer to variables from the parent process + if (m_funcp->user1SetOnce()) { // Only do this once per function + // Move all locals to the heap before the fork + auto* const awaitp = new AstCAwait{ + m_forkp->fileline(), new AstCStmt{m_forkp->fileline(), "VlNow{}"}}; + awaitp->statement(true); + m_forkp->addHereThisAsNext(awaitp); + } + } else { + refp->v3warn(E_UNSUPPORTED, "Unsupported: variable local to a forking process " + "accessed in a fork..join_any or fork..join_none"); + return; + } + // Remap the reference + AstVarScope* const vscp = refp->varScopep(); + if (!vscp->user2p()) { + // Clone the var to the new function + AstVar* const varp = refp->varp(); + AstVar* const newvarp + = new AstVar{varp->fileline(), VVarType::BLOCKTEMP, varp->name(), varp}; + newvarp->funcLocal(true); + newvarp->direction(passByValue ? VDirection::INPUT : VDirection::REF); + funcp->addArgsp(newvarp); + AstVarScope* const newvscp + = new AstVarScope{newvarp->fileline(), funcp->scopep(), newvarp}; + funcp->scopep()->addVarp(newvscp); + vscp->user2p(newvscp); + callp->addArgsp(new AstVarRef{refp->fileline(), vscp, VAccess::READ}); + } + auto* const newvscp = VN_AS(vscp->user2p(), VarScope); + refp->varScopep(newvscp); + refp->varp(newvscp->varp()); + }); + } + + // VISITORS + virtual void visit(AstNodeModule* nodep) override { + VL_RESTORER(m_inClass); + m_inClass = VN_IS(nodep, Class); + iterateChildren(nodep); + } + virtual void visit(AstCFunc* nodep) override { + m_funcp = nodep; + iterateChildren(nodep); + m_funcp = nullptr; + } + virtual void visit(AstVar* nodep) override { nodep->user1(true); } + virtual void visit(AstFork* nodep) override { + VL_RESTORER(m_forkp); + m_forkp = nodep; + iterateChildrenConst(nodep); // Const, so we don't iterate the calls twice + // Replace self with the function calls (no co_await, as we don't want the main + // process to suspend whenever any of the children do) + nodep->replaceWith(nodep->stmtsp()->unlinkFrBackWithNext()); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } + virtual void visit(AstBegin* nodep) override { + UASSERT_OBJ(m_forkp, nodep, "Begin outside of a fork"); + UASSERT_OBJ(!nodep->name().empty(), nodep, "Begin needs a name"); + FileLine* const flp = nodep->fileline(); + // Create a function to put this begin's statements in + AstCFunc* const newfuncp + = new AstCFunc{flp, nodep->name(), m_funcp->scopep(), "VlCoroutine"}; + m_funcp->addNextHere(newfuncp); + newfuncp->isLoose(m_funcp->isLoose()); + newfuncp->slow(m_funcp->slow()); + newfuncp->isConst(m_funcp->isConst()); + newfuncp->declPrivate(true); + // Replace the begin with a call to the newly created function + auto* const callp = new AstCCall{flp, newfuncp}; + nodep->replaceWith(callp); + // If we're in a class, add a vlSymsp arg + if (m_inClass) { + newfuncp->argTypes(EmitCBaseVisitor::symClassVar()); + callp->argTypes("vlSymsp"); + } + // Put the begin's statements in the function, delete the begin + newfuncp->addStmtsp(nodep->stmtsp()->unlinkFrBackWithNext()); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + remapLocals(newfuncp, callp); + } + + //-------------------- + virtual void visit(AstNodeMath*) override {} // Accelerate + virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + + public: + // CONSTRUCTORS + explicit ForkVisitor(AstNetlist* nodep) { iterate(nodep); } + virtual ~ForkVisitor() override = default; + }; + ForkVisitor{netlistp}; + V3Global::dumpCheckGlobalTree("sched_forks", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6); +} + +} // namespace V3Sched diff --git a/src/V3Split.cpp b/src/V3Split.cpp index 83dc6ac5b..979371c8b 100644 --- a/src/V3Split.cpp +++ b/src/V3Split.cpp @@ -428,6 +428,10 @@ protected: UINFO(9, " NotSplittable " << nodep << endl); scoreboardPli(nodep); } + if (nodep->isTimingControl()) { + UINFO(9, " NoReordering " << nodep << endl); + m_noReorderWhy = "TimingControl"; + } iterateChildren(nodep); } diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp new file mode 100644 index 000000000..671435ff8 --- /dev/null +++ b/src/V3Timing.cpp @@ -0,0 +1,659 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Prepare AST for timing features +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-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 +// +// TimingVisitor transformations: +// - for each intra-assignment timing control: +// - if it's a continuous assignment, transform it into an always +// - introduce an intermediate variable +// - write the original RHS to the intermediate variable before the timing control +// - write the intermediate variable to the original LHS after the timing control +// - for each delay: +// - scale it according to the module's timescale +// - replace it with a CAwait statement waiting on the global delay scheduler (with the +// specified delay value) +// - if there is no global delay scheduler (see verilated_timing.{h,cpp}), create it +// - for each event control: +// - if there is no corresponding trigger scheduler (see verilated_timing.{h,cpp}), create it +// - replace with a CAwait statement waiting on the corresponding trigger scheduler +// - for each wait(cond) statement: +// - replace it with a loop like: while (!cond) @() +// - for each fork: +// - put each statement in a begin if it isn't in one already +// - if it's not a fork..join_none: +// - create a join sync variable +// - create statements that sync the main process with its children +// - for each process or C++ function, if it has CAwait statements, mark it as suspendable +// - if we mark a virtual function as suspendable, mark all overriding and overridden functions +// as suspendable, as well as calling processes +// +// See the internals documentation docs/internals.rst for more details. +// +//************************************************************************* + +#include "config_build.h" +#include "verilatedos.h" + +#include "V3Timing.h" + +#include "V3Ast.h" +#include "V3Const.h" +#include "V3EmitV.h" +#include "V3Graph.h" +#include "V3SenTree.h" +#include "V3UniqueNames.h" + +//###################################################################### +// Transform nodes affected by timing + +class TimingVisitor final : public VNVisitor { +private: + // TYPES + // Vertex of a dependency graph of suspendable nodes, e.g. if a node (process or task) is + // suspendable, all its dependents should also be suspendable + class DependencyVertex final : public V3GraphVertex { + AstNode* const m_nodep; // AST node represented by this graph vertex + // ACCESSORS + virtual string name() const override { + return cvtToHex(nodep()) + ' ' + nodep()->prettyTypeName(); + } + virtual FileLine* fileline() const override { return nodep()->fileline(); } + virtual string dotColor() const override { return nodep()->user2() ? "red" : "black"; } + + public: + // CONSTRUCTORS + DependencyVertex(V3Graph* graphp, AstNode* nodep) + : V3GraphVertex{graphp} + , m_nodep{nodep} {} + virtual ~DependencyVertex() override = default; + + // ACCESSORS + virtual AstNode* nodep() const { return m_nodep; } + }; + + // NODE STATE + // AstNode::user1() -> bool. Set true if the node has been + // processed. + // AstSenTree::user1() -> AstVarScope*. Trigger scheduler assigned + // to this sentree + // Ast{NodeProcedure,CFunc,Begin}::user2() -> bool. Set true if process/task is + // suspendable + // AstSenTree::user2() -> AstText*. Debug info passed to the + // timing schedulers + // Ast{NodeProcedure,CFunc,Begin}::user3() -> DependencyVertex*. Vertex in m_depGraph + const VNUser1InUse m_user1InUse; + const VNUser2InUse m_user2InUse; + const VNUser3InUse m_user3InUse; + + // STATE + // Current context + AstNetlist* const m_netlistp; // Root node + AstScope* const m_scopeTopp = m_netlistp->topScopep()->scopep(); // Scope at the top + AstClass* m_classp = nullptr; // Current class + AstScope* m_scopep = nullptr; // Current scope + AstActive* m_activep = nullptr; // Current active + AstNode* m_procp = nullptr; // NodeProcedure/CFunc/Fork we're under + double m_timescaleFactor; // Factor to scale delays by + + // 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 + + // DTypes + AstBasicDType* m_forkDtp = nullptr; // Fork variable type + AstBasicDType* m_trigSchedDtp = nullptr; // Trigger scheduler type + + // Timing-related globals + AstVarScope* m_delaySchedp = nullptr; // Global delay scheduler + AstSenTree* m_delaySensesp = nullptr; // Domain to trigger if a delayed coroutine is resumed + + // Other + V3Graph m_depGraph; // Dependency graph where a node is a dependency of another if it being + // suspendable makes the other node suspendable + SenTreeFinder m_finder{m_netlistp}; // Sentree finder and uniquifier + + // METHODS + VL_DEBUG_FUNC; // Declare debug() + // Get or create the dependency vertex for the given node + DependencyVertex* getDependencyVertex(AstNode* const nodep) { + if (!nodep->user3p()) nodep->user3p(new DependencyVertex{&m_depGraph, nodep}); + return nodep->user3u().to(); + } + // Find net delay on the LHS of an assignment + AstNode* getLhsNetDelay(AstNodeAssign* nodep) const { + bool foundWrite = false; + AstNode* delayp = nullptr; + nodep->lhsp()->foreach([&](const AstNodeVarRef* const refp) { + if (!refp->access().isWriteOrRW()) return; + UASSERT_OBJ(!foundWrite, nodep, "Should only be one variable written to on the LHS"); + foundWrite = true; + if (refp->varp()->delayp()) delayp = refp->varp()->delayp()->cloneTree(false); + }); + return delayp; + } + // Transform an assignment with an intra timing control into a timing control with the + // assignment under it + AstNodeStmt* factorOutTimingControl(AstNodeAssign* nodep) const { + AstNodeStmt* stmtp = nodep; + AstNode* delayp = getLhsNetDelay(nodep); + FileLine* const flp = nodep->fileline(); + AstNode* const controlp = nodep->timingControlp(); + if (controlp) { + controlp->unlinkFrBack(); + if (!VN_IS(controlp, SenTree)) { + delayp = delayp ? new AstAdd{flp, delayp, controlp} : controlp; + } + } + if (delayp) { + auto* const delayStmtp = new AstDelay{flp, delayp, nullptr}; + stmtp->replaceWith(delayStmtp); + delayStmtp->stmtsp(stmtp); + stmtp = delayStmtp; + } + if (auto* const sensesp = VN_CAST(controlp, SenTree)) { + auto* const eventControlp = new AstEventControl{flp, sensesp, nullptr}; + stmtp->replaceWith(eventControlp); + eventControlp->stmtsp(stmtp); + stmtp = eventControlp; + } + return stmtp == nodep ? nullptr : stmtp; + } + // Calculate the factor to scale delays by + double calculateTimescaleFactor(VTimescale timeunit) const { + 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; + auto* const dlySchedDtp = new AstBasicDType{ + m_scopeTopp->fileline(), VBasicDTypeKwd::DELAY_SCHEDULER, VSigning::UNSIGNED}; + m_netlistp->typeTablep()->addTypesp(dlySchedDtp); + m_delaySchedp = m_scopeTopp->createTemp("__VdlySched", dlySchedDtp); + // Delay scheduler has to be accessible from top + m_delaySchedp->varp()->sigPublic(true); + m_netlistp->delaySchedulerp(m_delaySchedp->varp()); + return m_delaySchedp; + } + // Creates the delay sentree + AstSenTree* getCreateDelaySenTree() { + if (m_delaySensesp) return m_delaySensesp; + FileLine* const flp = m_scopeTopp->fileline(); + auto* const awaitingCurrentTimep + = new AstCMethodHard{flp, new AstVarRef{flp, getCreateDelayScheduler(), VAccess::READ}, + "awaitingCurrentTime"}; + awaitingCurrentTimep->dtypeSetBit(); + m_delaySensesp + = new AstSenTree{flp, new AstSenItem{flp, VEdgeType::ET_TRUE, awaitingCurrentTimep}}; + m_netlistp->topScopep()->addSenTreep(m_delaySensesp); + return m_delaySensesp; + } + // Creates a trigger scheduler variable + AstVarScope* getCreateTriggerSchedulerp(AstSenTree* const sensesp) { + if (!sensesp->user1p()) { + if (!m_trigSchedDtp) { + m_trigSchedDtp + = new AstBasicDType{m_scopeTopp->fileline(), VBasicDTypeKwd::TRIGGER_SCHEDULER, + VSigning::UNSIGNED}; + m_netlistp->typeTablep()->addTypesp(m_trigSchedDtp); + } + AstVarScope* const trigSchedp + = m_scopeTopp->createTemp(m_trigSchedNames.get(sensesp), m_trigSchedDtp); + sensesp->user1p(trigSchedp); + } + return VN_AS(sensesp->user1p(), VarScope); + } + // Creates a string describing the sentree + AstText* createEventDescription(AstSenTree* const sensesp) const { + if (!sensesp->user2p()) { + std::stringstream ss; + ss << '"'; + V3EmitV::verilogForTree(sensesp, ss); + ss << '"'; + auto* const commentp = new AstText{sensesp->fileline(), ss.str()}; + sensesp->user2p(commentp); + return commentp; + } + return VN_AS(sensesp->user2p(), Text)->cloneTree(false); + } + // Creates the fork handle type and returns it + AstBasicDType* getCreateForkSyncDTypep() { + if (m_forkDtp) return m_forkDtp; + m_forkDtp = new AstBasicDType{m_scopeTopp->fileline(), VBasicDTypeKwd::FORK_SYNC, + VSigning::UNSIGNED}; + m_netlistp->typeTablep()->addTypesp(m_forkDtp); + return m_forkDtp; + } + // Create a temp variable and optionally put it before the specified node (mark local if so) + AstVarScope* createTemp(FileLine* const flp, const std::string& name, + AstNodeDType* const dtypep, AstNode* const insertBeforep = nullptr) { + AstVar* varp; + if (insertBeforep) { + varp = new AstVar{flp, VVarType::BLOCKTEMP, name, dtypep}; + varp->funcLocal(true); + insertBeforep->addHereThisAsNext(varp); + } else { + varp = new AstVar{flp, VVarType::MODULETEMP, name, dtypep}; + m_scopep->modp()->addStmtp(varp); + } + AstVarScope* vscp = new AstVarScope{flp, m_scopep, varp}; + m_scopep->addVarp(vscp); + return vscp; + } + // Add a done() call on the fork sync + void addForkDone(AstBegin* const beginp, AstVarScope* const forkVscp) const { + FileLine* const flp = beginp->fileline(); + auto* const donep = new AstCMethodHard{ + beginp->fileline(), new AstVarRef{flp, forkVscp, VAccess::WRITE}, "done"}; + donep->dtypeSetVoid(); + donep->statement(true); + // Add debug info + donep->addPinsp(new AstText{flp, '"' + flp->filename() + '"'}); + donep->addPinsp(new AstText{flp, cvtToStr(flp->lineno())}); + beginp->addStmtsp(donep); + } + // Handle the 'join' part of a fork..join + void makeForkJoin(AstFork* const forkp) { + // Create a fork sync var + FileLine* const flp = forkp->fileline(); + // If we're in a function, insert the sync var directly before the fork + AstNode* const insertBeforep = VN_IS(m_procp, CFunc) ? forkp : nullptr; + AstVarScope* forkVscp + = createTemp(flp, forkp->name() + "__sync", getCreateForkSyncDTypep(), insertBeforep); + unsigned joinCount = 0; // Needed for join counter + // Add a .done() to each begin + for (AstNode* beginp = forkp->stmtsp(); beginp; beginp = beginp->nextp()) { + addForkDone(VN_AS(beginp, Begin), forkVscp); + joinCount++; + } + if (forkp->joinType().joinAny()) joinCount = 1; + // Set the join counter + auto* const initp = new AstCMethodHard{flp, new AstVarRef{flp, forkVscp, VAccess::WRITE}, + "init", new AstConst{flp, joinCount}}; + initp->dtypeSetVoid(); + initp->statement(true); + forkp->addHereThisAsNext(initp); + // Await the join at the end + auto* const joinp + = new AstCMethodHard{flp, new AstVarRef{flp, forkVscp, VAccess::WRITE}, "join"}; + joinp->dtypeSetVoid(); + // Add debug info + joinp->addPinsp(new AstText{flp, '"' + flp->filename() + '"'}); + joinp->addPinsp(new AstText{flp, cvtToStr(flp->lineno())}); + auto* const awaitp = new AstCAwait{flp, joinp}; + awaitp->statement(true); + forkp->addNextHere(awaitp); + } + + // VISITORS + virtual void visit(AstNodeModule* nodep) override { + UASSERT(!m_classp, "Module or class under class"); + VL_RESTORER(m_classp); + m_classp = VN_CAST(nodep, Class); + VL_RESTORER(m_timescaleFactor); + m_timescaleFactor = calculateTimescaleFactor(nodep->timeunit()); + iterateChildren(nodep); + } + virtual void visit(AstScope* nodep) override { + VL_RESTORER(m_scopep); + m_scopep = nodep; + iterateChildren(nodep); + } + virtual void visit(AstActive* nodep) override { + m_activep = nodep; + iterateChildren(nodep); + m_activep = nullptr; + } + virtual void visit(AstNodeProcedure* nodep) override { + VL_RESTORER(m_procp); + m_procp = nodep; + iterateChildren(nodep); + if (nodep->user2()) nodep->setSuspendable(); + } + virtual void visit(AstAlways* nodep) override { + visit(static_cast(nodep)); + if (nodep->isSuspendable() && !nodep->user1SetOnce()) { + FileLine* const flp = nodep->fileline(); + AstSenTree* const sensesp = m_activep->sensesp(); + if (sensesp->hasClocked()) { + AstNode* bodysp = nodep->bodysp()->unlinkFrBackWithNext(); + auto* const controlp = new AstEventControl{flp, sensesp->cloneTree(false), bodysp}; + nodep->addStmtp(controlp); + iterate(controlp); + } + // Note: The 'while (true)' outer loop will be added in V3Sched + auto* const activep = new AstActive{ + flp, "", new AstSenTree{flp, new AstSenItem{flp, AstSenItem::Initial{}}}}; + activep->sensesStorep(activep->sensesp()); + activep->addStmtsp(nodep->unlinkFrBack()); + m_activep->addNextHere(activep); + } + } + virtual void visit(AstCFunc* nodep) override { + VL_RESTORER(m_procp); + m_procp = nodep; + iterateChildren(nodep); + DependencyVertex* const vxp = getDependencyVertex(nodep); + if (m_classp && nodep->isVirtual() + && !nodep->user1SetOnce()) { // If virtual (only visit once) + // Go over overridden functions + m_classp->repairCache(); + for (auto* cextp = m_classp->extendsp(); cextp; + cextp = VN_AS(cextp->nextp(), ClassExtends)) { + if (auto* const overriddenp + = VN_CAST(cextp->classp()->findMember(nodep->name()), CFunc)) { + if (overriddenp->user2()) { // If suspendable + if (!nodep->user2()) { + // It should be a coroutine but it has no awaits. Add a co_return at + // the end (either that or a co_await is required in a coroutine) + nodep->addStmtsp(new AstCStmt{nodep->fileline(), "co_return;\n"}); + } + nodep->user2(true); + // If it's suspendable already, no need to add it as our dependency or + // self to its dependencies + } else { + DependencyVertex* const overriddenVxp = getDependencyVertex(overriddenp); + new V3GraphEdge{&m_depGraph, vxp, overriddenVxp, 1}; + new V3GraphEdge{&m_depGraph, overriddenVxp, vxp, 1}; + } + } + } + } + if (nodep->user2() && !nodep->isCoroutine()) { // If first marked as suspendable + nodep->rtnType("VlCoroutine"); + // Revisit dependent nodes if needed + for (V3GraphEdge* edgep = vxp->inBeginp(); edgep; edgep = edgep->inNextp()) { + auto* const depVxp = static_cast(edgep->fromp()); + AstNode* const depp = depVxp->nodep(); + if (!depp->user2()) { // If dependent not suspendable + depp->user2(true); + if (auto* const funcp = VN_CAST(depp, CFunc)) { + // It's a coroutine but has no awaits (a class method that overrides/is + // overridden by a suspendable, but doesn't have any awaits itself). Add a + // co_return at the end (either that or a co_await is required in a + // coroutine) + funcp->addStmtsp(new AstCStmt{funcp->fileline(), "co_return;\n"}); + } + } + iterate(depp); + } + } + } + virtual void visit(AstNodeCCall* nodep) override { + if (nodep->funcp()->user2()) { // If suspendable + auto* const awaitp = new AstCAwait{nodep->fileline(), nullptr}; + nodep->replaceWith(awaitp); + awaitp->exprp(nodep); + } else { + // Add our process/func as the CFunc's dependency as we might have to put an await here + DependencyVertex* const procVxp = getDependencyVertex(m_procp); + DependencyVertex* const funcVxp = getDependencyVertex(nodep->funcp()); + new V3GraphEdge{&m_depGraph, procVxp, funcVxp, 1}; + } + iterateChildren(nodep); + } + virtual void visit(AstCAwait* nodep) override { + v3Global.setUsesTiming(); + m_procp->user2(true); + } + virtual void visit(AstDelay* nodep) override { + FileLine* const flp = nodep->fileline(); + AstNode* valuep = V3Const::constifyEdit(nodep->lhsp()->unlinkFrBack()); + auto* const constp = VN_CAST(valuep, Const); + if (constp && constp->isZero()) { + nodep->v3warn(ZERODLY, "Unsupported: #0 delays do not schedule process resumption in " + "the Inactive region"); + } else { + // Scale the delay + if (valuep->dtypep()->isDouble()) { + valuep = new AstRToIRoundS{ + flp, + new AstMulD{flp, valuep, + new AstConst{flp, AstConst::RealDouble{}, m_timescaleFactor}}}; + } else { + valuep = new AstMul{flp, valuep, + new AstConst{flp, AstConst::Unsized64(), + static_cast(m_timescaleFactor)}}; + } + } + // Replace self with a 'co_await dlySched.delay()' + auto* const delayMethodp = new AstCMethodHard{ + flp, new AstVarRef{flp, getCreateDelayScheduler(), VAccess::WRITE}, "delay", valuep}; + delayMethodp->dtypeSetVoid(); + // Add debug info + delayMethodp->addPinsp(new AstText{flp, '"' + flp->filename() + '"'}); + delayMethodp->addPinsp(new AstText{flp, cvtToStr(flp->lineno())}); + // Create the co_await + auto* const awaitp = new AstCAwait{flp, delayMethodp, getCreateDelaySenTree()}; + awaitp->statement(true); + // Relink child statements after the co_await + if (nodep->stmtsp()) awaitp->addNext(nodep->stmtsp()->unlinkFrBackWithNext()); + nodep->replaceWith(awaitp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } + virtual void visit(AstEventControl* nodep) override { + if (m_classp) nodep->v3warn(E_UNSUPPORTED, "Unsupported: event controls in methods"); + auto* const sensesp = m_finder.getSenTree(nodep->sensesp()); + nodep->sensesp()->unlinkFrBack()->deleteTree(); + // Get this sentree's trigger scheduler + FileLine* const flp = nodep->fileline(); + // Replace self with a 'co_await trigSched.trigger()' + auto* const triggerMethodp = new AstCMethodHard{ + flp, new AstVarRef{flp, getCreateTriggerSchedulerp(sensesp), VAccess::WRITE}, + "trigger"}; + triggerMethodp->dtypeSetVoid(); + // Add debug info + triggerMethodp->addPinsp(createEventDescription(sensesp)); + triggerMethodp->addPinsp(new AstText{flp, '"' + flp->filename() + '"'}); + triggerMethodp->addPinsp(new AstText{flp, cvtToStr(flp->lineno())}); + // Create the co_await + auto* const awaitp = new AstCAwait{flp, triggerMethodp, sensesp}; + awaitp->statement(true); + // Relink child statements after the co_await + if (nodep->stmtsp()) awaitp->addNext(nodep->stmtsp()->unlinkFrBackWithNext()); + nodep->replaceWith(awaitp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } + virtual void visit(AstNodeAssign* nodep) override { + iterateChildren(nodep); + // Only process once to avoid infinite loops (due to the net delay) + if (nodep->user1SetOnce()) return; + AstNode* const controlp = factorOutTimingControl(nodep); + if (!controlp) return; + // Handle the intra assignment timing control + FileLine* const flp = nodep->fileline(); + if (VN_IS(nodep, AssignDly)) { + // If it's an NBA with an intra assignment delay, put it in a fork + auto* const forkp = new AstFork{flp, "", nullptr}; + forkp->joinType(VJoinType::JOIN_NONE); + controlp->replaceWith(forkp); + forkp->addStmtsp(controlp); + } + // Insert new vars before the timing control if we're in a function; in a process we can't + // do that. These intra-assignment vars will later be passed to forked processes by value. + AstNode* const insertBeforep = VN_IS(m_procp, CFunc) ? controlp : nullptr; + // Function for replacing values with intermediate variables + const auto replaceWithIntermediate = [&](AstNode* const valuep, const std::string& name) { + AstVarScope* const newvscp = createTemp(flp, name, valuep->dtypep(), insertBeforep); + valuep->replaceWith(new AstVarRef{flp, newvscp, VAccess::READ}); + controlp->addHereThisAsNext( + new AstAssign{flp, new AstVarRef{flp, newvscp, VAccess::WRITE}, valuep}); + }; + // Create the intermediate select vars. Note: because 'foreach' proceeds in + // pre-order, and we replace indices in selects with variables, we cannot + // reach another select under the index position. This is exactly what + // we want as only the top level selects are LValues. As an example, + // this transforms 'x[a[i]][b[j]] = y' + // into 't1 = a[i]; t0 = b[j]; x[t1][t0] = y'. + nodep->lhsp()->foreach([&](AstSel* selp) { + if (VN_IS(selp->lsbp(), Const)) return; + replaceWithIntermediate(selp->lsbp(), m_intraLsbNames.get(nodep)); + // widthp should be const + }); + nodep->lhsp()->foreach([&](AstNodeSel* selp) { + if (VN_IS(selp->bitp(), Const)) return; + replaceWithIntermediate(selp->bitp(), m_intraIndexNames.get(nodep)); + }); + // Replace the RHS with an intermediate value var + replaceWithIntermediate(nodep->rhsp(), m_intraValueNames.get(nodep)); + } + virtual void visit(AstAssignW* nodep) override { + iterateChildren(nodep); + auto* const netDelayp = getLhsNetDelay(nodep); + if (!netDelayp && !nodep->timingControlp()) return; + // This assignment will be converted to an always. In some cases this may generate an + // UNOPTFLAT, e.g.: assign #1 clk = ~clk. We create a temp var for the LHS of this assign, + // to disable the UNOPTFLAT warning for it. + // TODO: Find a way to do this without introducing this var. Perhaps make V3SchedAcyclic + // recognize awaits and prevent it from treating this kind of logic as cyclic + AstNode* const lhsp = nodep->lhsp()->unlinkFrBack(); + std::string varname; + if (auto* const refp = VN_CAST(lhsp, VarRef)) { + varname = m_contAssignVarNames.get(refp->name()); + } else { + varname = m_contAssignVarNames.get(lhsp); + } + auto* const tempvscp = m_scopep->createTemp(varname, lhsp->dtypep()); + tempvscp->varp()->delayp(netDelayp); + FileLine* const flp = nodep->fileline(); + flp->modifyWarnOff(V3ErrorCode::UNOPTFLAT, true); + tempvscp->fileline(flp); + tempvscp->varp()->fileline(flp); + // Remap the LHS to the new temp var + nodep->lhsp(new AstVarRef{flp, tempvscp, VAccess::WRITE}); + // Convert it to an always; the new assign with intra delay will be handled by + // visit(AstNodeAssign*) + AstAlways* const alwaysp = nodep->convertToAlways(); + visit(alwaysp); + // Put the LHS back in the AssignW; put the temp var on the RHS + nodep->lhsp(lhsp); + nodep->rhsp(new AstVarRef{flp, tempvscp, VAccess::READ}); + // Put the AssignW right after the always. Different order can produce UNOPTFLAT on the LHS + // var + alwaysp->addNextHere(nodep); + } + virtual void visit(AstWait* nodep) override { + // Wait on changed events related to the vars in the wait statement + AstSenItem* const senItemsp = varRefpsToSenItemsp(nodep->condp()); + AstNode* const condp = nodep->condp()->unlinkFrBack(); + AstNode* const bodysp = nodep->bodysp(); + if (bodysp) bodysp->unlinkFrBackWithNext(); + FileLine* const flp = nodep->fileline(); + if (senItemsp) { + // Put the event control in a while loop with the wait expression as condition + auto* const loopp + = new AstWhile{flp, new AstLogNot{flp, condp}, + new AstEventControl{flp, new AstSenTree{flp, senItemsp}, nullptr}}; + loopp->addNextNull(bodysp); + nodep->replaceWith(loopp); + } else { + condp->v3warn(WAITCONST, "Wait statement condition is constant"); + auto* constCondp = VN_AS(V3Const::constifyEdit(condp), Const); + if (constCondp->isZero()) { + // We have to await forever instead of simply returning in case we're deep in a + // callstack + auto* const awaitp = new AstCAwait{flp, new AstCStmt{flp, "VlForever{}"}}; + awaitp->statement(true); + nodep->replaceWith(awaitp); + if (bodysp) VL_DO_DANGLING(bodysp->deleteTree(), bodysp); + } else if (bodysp) { + // Just put the body there + nodep->replaceWith(bodysp); + } + VL_DO_DANGLING(constCondp->deleteTree(), condp); + } + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } + virtual void visit(AstFork* nodep) override { + if (nodep->user1SetOnce()) return; + // Create a unique name for this fork + nodep->name(m_forkNames.get(nodep)); + unsigned idx = 0; // Index for naming begins + AstNode* stmtp = nodep->stmtsp(); + // Put each statement in a begin + while (stmtp) { + if (!VN_IS(stmtp, Begin)) { + auto* const beginp = new AstBegin{stmtp->fileline(), "", nullptr}; + stmtp->replaceWith(beginp); + beginp->addStmtsp(stmtp); + stmtp = beginp; + } + auto* const beginp = VN_AS(stmtp, Begin); + stmtp = beginp->nextp(); + VL_RESTORER(m_procp); + m_procp = beginp; + iterate(beginp); + if (!m_procp->user2()) { + // No awaits, we can inline this process + if (auto* const stmtsp = beginp->stmtsp()) { + nodep->addHereThisAsNext(stmtsp->unlinkFrBackWithNext()); + } + VL_DO_DANGLING(beginp->unlinkFrBack()->deleteTree(), beginp); + // We inlined at least one process, so we can consider it joined; convert join_any + // to join_none + if (nodep->joinType().joinAny()) nodep->joinType(VJoinType::JOIN_NONE); + } else { + // Name the begin (later the name will be used for a new function) + beginp->name(nodep->name() + "__" + cvtToStr(idx++)); + } + } + if (!nodep->stmtsp()) { + VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + } else if (!nodep->joinType().joinNone()) { + makeForkJoin(nodep); + } + } + + //-------------------- + virtual void visit(AstNodeMath*) override {} // Accelerate + virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } + +public: + // CONSTRUCTORS + explicit TimingVisitor(AstNetlist* nodep) + : m_netlistp{nodep} { + iterate(nodep); + if (debug() >= 6) m_depGraph.dumpDotFilePrefixed("timing_deps"); + } + virtual ~TimingVisitor() override = default; +}; + +//###################################################################### +// Timing class functions + +void V3Timing::timingAll(AstNetlist* nodep) { + UINFO(2, __FUNCTION__ << ": " << endl); + TimingVisitor{nodep}; + V3Global::dumpCheckGlobalTree("timing", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); +} diff --git a/src/V3Timing.h b/src/V3Timing.h new file mode 100644 index 000000000..2114f1bbb --- /dev/null +++ b/src/V3Timing.h @@ -0,0 +1,32 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Prepare AST for features features +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-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 +// +//************************************************************************* + +#ifndef _V3TIMING_H_ +#define _V3TIMING_H_ + +#include "config_build.h" +#include "verilatedos.h" + +#include "V3Ast.h" + +//============================================================================ + +class V3Timing final { +public: + static void timingAll(AstNetlist* nodep); +}; + +#endif // Guard diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp index 12f011366..fec087411 100644 --- a/src/V3Unknown.cpp +++ b/src/V3Unknown.cpp @@ -57,6 +57,7 @@ private: AstNodeModule* m_modp = nullptr; // Current module AstAssignW* m_assignwp = nullptr; // Current assignment AstAssignDly* m_assigndlyp = nullptr; // Current assignment + AstNode* m_timingControlp = nullptr; // Current assignment's intra timing control bool m_constXCvt = false; // Convert X's bool m_allowXUnique = true; // Allow unique assignments VDouble0 m_statUnkVars; // Statistic tracking @@ -123,12 +124,14 @@ private: m_modp->addStmtp(varp); AstNode* const abovep = prep->backp(); // Grab above point before we replace 'prep' prep->replaceWith(new AstVarRef(fl, varp, VAccess::WRITE)); + if (m_timingControlp) m_timingControlp->unlinkFrBack(); AstIf* const newp = new AstIf( fl, condp, - (needDly ? static_cast( - new AstAssignDly(fl, prep, new AstVarRef(fl, varp, VAccess::READ))) - : static_cast( - new AstAssign(fl, prep, new AstVarRef(fl, varp, VAccess::READ))))); + (needDly + ? static_cast(new AstAssignDly{ + fl, prep, new AstVarRef{fl, varp, VAccess::READ}, m_timingControlp}) + : static_cast(new AstAssign{ + fl, prep, new AstVarRef{fl, varp, VAccess::READ}, m_timingControlp}))); newp->branchPred(VBranchPred::BP_LIKELY); newp->isBoundsCheck(true); if (debug() >= 9) newp->dumpTree(cout, " _new: "); @@ -155,18 +158,29 @@ private: } virtual void visit(AstAssignDly* nodep) override { VL_RESTORER(m_assigndlyp); + VL_RESTORER(m_timingControlp); { m_assigndlyp = nodep; + m_timingControlp = nodep->timingControlp(); VL_DO_DANGLING(iterateChildren(nodep), nodep); // May delete nodep. } } virtual void visit(AstAssignW* nodep) override { VL_RESTORER(m_assignwp); + VL_RESTORER(m_timingControlp); { m_assignwp = nodep; + m_timingControlp = nodep->timingControlp(); VL_DO_DANGLING(iterateChildren(nodep), nodep); // May delete nodep. } } + virtual void visit(AstNodeAssign* nodep) override { + VL_RESTORER(m_timingControlp); + { + m_timingControlp = nodep->timingControlp(); + iterateChildren(nodep); + } + } virtual void visit(AstCaseItem* nodep) override { VL_RESTORER(m_constXCvt); { diff --git a/src/V3Width.cpp b/src/V3Width.cpp index f938f95d7..d13b15ad6 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -607,8 +607,20 @@ private: VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); return; } + if (nodep->fileline()->timingOn()) { + if (v3Global.opt.timing().isSetTrue()) { + userIterate(nodep->lhsp(), WidthVP{nullptr, BOTH}.p()); + iterateNull(nodep->stmtsp()); + return; + } else if (v3Global.opt.timing().isSetFalse()) { + nodep->v3warn(STMTDLY, "Ignoring delay on this statement due to --no-timing"); + } else { + nodep->v3warn( + E_NEEDTIMINGOPT, + "Use --timing or --no-timing to specify how delays should be handled"); + } + } if (nodep->stmtsp()) nodep->addNextHere(nodep->stmtsp()->unlinkFrBack()); - nodep->v3warn(STMTDLY, "Unsupported: Ignoring delay on this delayed statement."); VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); } virtual void visit(AstFork* nodep) override { @@ -618,19 +630,27 @@ private: VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); return; } - if (v3Global.opt.bboxUnsup() + if (!nodep->fileline()->timingOn() // With no statements, begin is identical || !nodep->stmtsp() - // With one statement, a begin block does as good as a fork/join or join_any - || (!nodep->stmtsp()->nextp() && !nodep->joinType().joinNone())) { + || (!v3Global.opt.timing().isSetTrue() // If no --timing + && (v3Global.opt.bboxUnsup() + // With one statement and no timing, a begin block does as good as a + // fork/join or join_any + || (!nodep->stmtsp()->nextp() && !nodep->joinType().joinNone())))) { AstNode* stmtsp = nullptr; if (nodep->stmtsp()) stmtsp = nodep->stmtsp()->unlinkFrBack(); AstBegin* const newp = new AstBegin{nodep->fileline(), nodep->name(), stmtsp}; nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); + } else if (v3Global.opt.timing().isSetTrue()) { + iterateChildren(nodep); + } else if (v3Global.opt.timing().isSetFalse()) { + nodep->v3warn(E_NOTIMING, "Fork statements require --timing"); + VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); } else { - nodep->v3warn(E_UNSUPPORTED, "Unsupported: fork statements"); - // TBD might support only normal join, if so complain about other join flavors + nodep->v3warn(E_NEEDTIMINGOPT, + "Use --timing or --no-timing to specify how forks should be handled"); } } virtual void visit(AstDisableFork* nodep) override { @@ -1358,10 +1378,28 @@ private: VL_DO_DANGLING(nodep->deleteTree(), nodep); } virtual void visit(AstEventControl* nodep) override { - nodep->v3warn(E_UNSUPPORTED, "Unsupported: event control statement in this location\n" - << nodep->warnMore() - << "... Suggest have one event control statement " - << "per procedure, at the top of the procedure"); + if (VN_IS(m_ftaskp, Func)) { + nodep->v3error("Event controls are not legal in functions. Suggest use a task " + "(IEEE 1800-2017 13.4.4)"); + VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + return; + } + if (nodep->fileline()->timingOn()) { + if (v3Global.opt.timing().isSetTrue()) { + iterateChildren(nodep); + return; + } else if (v3Global.opt.timing().isSetFalse()) { + nodep->v3warn(E_NOTIMING, + "Event control statement in this location requires --timing\n" + << nodep->warnMore() + << "... With --no-timing, suggest have one event control " + << "statement per procedure, at the top of the procedure"); + } else { + nodep->v3warn(E_NEEDTIMINGOPT, "Use --timing or --no-timing to specify how " + "event controls should be handled"); + } + } + if (nodep->stmtsp()) nodep->addNextHere(nodep->stmtsp()->unlinkFrBack()); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } virtual void visit(AstAttrOf* nodep) override { @@ -4236,10 +4274,26 @@ private: nodep->v3warn(E_UNSUPPORTED, "Unsupported: assignment of event data type"); } } - if (nodep->timingControlp()) { - nodep->timingControlp()->v3warn( - ASSIGNDLY, "Unsupported: Ignoring timing control on this assignment."); - nodep->timingControlp()->unlinkFrBackWithNext()->deleteTree(); + if (auto* const controlp = nodep->timingControlp()) { + if (VN_IS(m_ftaskp, Func)) { + controlp->v3error("Timing controls are not legal in functions. Suggest use a task " + "(IEEE 1800-2017 13.4.4)"); + VL_DO_DANGLING(controlp->unlinkFrBackWithNext()->deleteTree(), controlp); + } else if (nodep->fileline()->timingOn() && v3Global.opt.timing().isSetTrue()) { + iterateNull(controlp); + } else { + if (nodep->fileline()->timingOn()) { + if (v3Global.opt.timing().isSetFalse()) { + controlp->v3warn(ASSIGNDLY, "Ignoring timing control on this " + "assignment/primitive due to --no-timing"); + } else { + controlp->v3warn(E_NEEDTIMINGOPT, + "Use --timing or --no-timing to specify how " + "timing controls should be handled"); + } + } + VL_DO_DANGLING(controlp->unlinkFrBackWithNext()->deleteTree(), controlp); + } } if (VN_IS(nodep->rhsp(), EmptyQueue)) { UINFO(9, "= {} -> .delete(): " << nodep); @@ -5067,6 +5121,35 @@ private: userIterateChildren(nodep, WidthVP(SELF, BOTH).p()); } } + virtual void visit(AstWait* nodep) override { + if (VN_IS(m_ftaskp, Func)) { + nodep->v3error("Wait statements are not legal in functions. Suggest use a task " + "(IEEE 1800-2017 13.4.4)"); + VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + return; + } + if (nodep->fileline()->timingOn()) { + if (v3Global.opt.timing().isSetTrue()) { + userIterate(nodep->condp(), WidthVP(SELF, PRELIM).p()); + iterateNull(nodep->bodysp()); + return; + } else if (v3Global.opt.timing().isSetFalse()) { + nodep->v3warn(E_NOTIMING, "Wait statements require --timing"); + } else { + nodep->v3warn(E_NEEDTIMINGOPT, "Use --timing or --no-timing to specify how wait " + "statements should be handled"); + } + } + // If we ignore timing: + // Statements we'll just execute immediately; equivalent to if they followed this + if (AstNode* const bodysp = nodep->bodysp()) { + bodysp->unlinkFrBackWithNext(); + nodep->replaceWith(bodysp); + } else { + nodep->unlinkFrBack(); + } + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } virtual void visit(AstWith* nodep) override { // Should otherwise be underneath a method call AstNodeDType* const vdtypep = m_vup->dtypeNullSkipRefp(); diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 46971cc54..a68c7628f 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -89,6 +89,7 @@ #include "V3TSP.h" #include "V3Table.h" #include "V3Task.h" +#include "V3Timing.h" #include "V3Trace.h" #include "V3TraceDecl.h" #include "V3Tristate.h" @@ -362,6 +363,14 @@ static void process() { // Reorder assignments in pipelined blocks if (v3Global.opt.fReorder()) V3Split::splitReorderAll(v3Global.rootp()); + if (v3Global.opt.timing().isSetTrue()) { + // Convert AST for timing if requested + // Needs to be after V3Gate, as that step modifies sentrees + // Needs to be before V3Delayed, as delayed assignments are handled differently in + // suspendable processes + V3Timing::timingAll(v3Global.rootp()); + } + // Create delayed assignments // This creates lots of duplicate ACTIVES so ActiveTop needs to be after this step V3Delayed::delayedAll(v3Global.rootp()); diff --git a/src/config_build.h.in b/src/config_build.h.in index d044c1411..32a0da56f 100644 --- a/src/config_build.h.in +++ b/src/config_build.h.in @@ -82,6 +82,7 @@ using std::endl; // - 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 diff --git a/src/verilog.l b/src/verilog.l index c3eb40f4c..798b44ef3 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -131,6 +131,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "sc_bv" { FL; return yVLT_SC_BV; } "sformat" { FL; return yVLT_SFORMAT; } "split_var" { FL; return yVLT_SPLIT_VAR; } + "timing_off" { FL; return yVLT_TIMING_OFF; } + "timing_on" { FL; return yVLT_TIMING_ON; } "tracing_off" { FL; return yVLT_TRACING_OFF; } "tracing_on" { FL; return yVLT_TRACING_ON; } @@ -748,6 +750,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "/*verilator split_var*/" { FL; return yVL_SPLIT_VAR; } "/*verilator tag"[^*]*"*/" { FL; yylval.strp = PARSEP->newString(V3ParseImp::lexParseTag(yytext)); return yVL_TAG; } + "/*verilator timing_off*/" { FL_FWD; PARSEP->lexFileline()->timingOn(false); FL_BRK; } + "/*verilator timing_on*/" { FL_FWD; PARSEP->lexFileline()->timingOn(true); FL_BRK; } "/*verilator trace_init_task*/" { FL; return yVL_TRACE_INIT_TASK; } "/*verilator tracing_off*/" { FL_FWD; PARSEP->lexFileline()->tracingOn(false); FL_BRK; } "/*verilator tracing_on*/" { FL_FWD; PARSEP->lexFileline()->tracingOn(true); FL_BRK; } diff --git a/src/verilog.y b/src/verilog.y index 71e97120c..938a2e82f 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -40,11 +40,22 @@ #define BBUNSUP(fl, msg) (fl)->v3warn(E_UNSUPPORTED, msg) #define GATEUNSUP(fl, tok) \ { BBUNSUP((fl), "Unsupported: Verilog 1995 gate primitive: " << (tok)); } -#define PRIMDLYUNSUP(nodep) \ - { \ - if (nodep) { \ - nodep->v3warn(ASSIGNDLY, "Unsupported: Ignoring delay on this primitive."); \ - nodep->deleteTree(); \ +#define RISEFALLDLYUNSUP(nodep) \ + if (nodep->fileline()->timingOn() && v3Global.opt.timing().isSetTrue()) { \ + nodep->v3warn(RISEFALLDLY, \ + "Unsupported: rising/falling/turn-off delays. Using the first delay"); \ + } +#define MINTYPMAXDLYUNSUP(nodep) \ + if (nodep->fileline()->timingOn() && v3Global.opt.timing().isSetTrue()) { \ + nodep->v3warn( \ + MINTYPMAXDLY, \ + "Unsupported: minimum/typical/maximum delay expressions. Using the typical delay"); \ + } +#define PUT_DLYS_IN_ASSIGNS(delayp, assignsp) \ + if (delayp) { \ + for (auto* nodep = assignsp; nodep; nodep = nodep->nextp()) { \ + auto* const assignp = VN_AS(nodep, NodeAssign); \ + assignp->timingControlp(nodep == assignsp ? delayp : delayp->cloneTree(false)); \ } \ } @@ -393,6 +404,8 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yVLT_SC_BV "sc_bv" %token yVLT_SFORMAT "sformat" %token yVLT_SPLIT_VAR "split_var" +%token yVLT_TIMING_OFF "timing_off" +%token yVLT_TIMING_ON "timing_on" %token yVLT_TRACING_OFF "tracing_off" %token yVLT_TRACING_ON "tracing_on" @@ -1742,13 +1755,13 @@ net_dataTypeE: // // Otherwise #(...) can't be determined to be a delay or parameters // // Submit this as a footnote to the committee var_data_type { $$ = $1; } - | signingE rangeList delayE + | signingE rangeList delay_controlE { $$ = GRAMMARP->addRange(new AstBasicDType{$2->fileline(), LOGIC, $1}, $2, true); GRAMMARP->setNetDelay($3); } // not implicit | signing { $$ = new AstBasicDType{$1, LOGIC, $1}; } // not implicit - | /*implicit*/ delayE + | /*implicit*/ delay_controlE { $$ = new AstBasicDType{CRELINE(), LOGIC}; GRAMMARP->setNetDelay($1); } // not implicit ; @@ -2428,14 +2441,10 @@ module_common_item: // ==IEEE: module_common_item ; continuous_assign: // IEEE: continuous_assign - yASSIGN strengthSpecE delayE assignList ';' + yASSIGN strengthSpecE delay_controlE assignList ';' { $$ = $4; - if ($3) - for (auto* nodep = $$; nodep; nodep = nodep->nextp()) { - auto* const assignp = VN_AS(nodep, NodeAssign); - assignp->addTimingControlp(nodep == $$ ? $3 : $3->cloneTree(false)); - } + PUT_DLYS_IN_ASSIGNS($3, $$); } ; @@ -2678,27 +2687,22 @@ assignOne: ; delay_or_event_controlE: // IEEE: delay_or_event_control plus empty + /* empty */ { $$ = nullptr; } + | delay_control { $$ = $1; } + | event_control { $$ = $1; } +//UNSUP | yREPEAT '(' expr ')' event_control { } + ; + +delay_controlE: /* empty */ { $$ = nullptr; } | delay_control { $$ = $1; } - | event_control { $$ = $1; } -//UNSUP | yREPEAT '(' expr ')' event_control { } - ; - -delayE: - /* empty */ { $$ = nullptr; } - | delay { $$ = $1; } - ; - -delay: - delay_control - { $$ = $1; } ; delay_control: //== IEEE: delay_control '#' delay_value { $$ = $2; } | '#' '(' minTypMax ')' { $$ = $3; } - | '#' '(' minTypMax ',' minTypMax ')' { $$ = $3; DEL($5); } - | '#' '(' minTypMax ',' minTypMax ',' minTypMax ')' { $$ = $3; DEL($5); DEL($7); } + | '#' '(' minTypMax ',' minTypMax ')' { $$ = $3; RISEFALLDLYUNSUP($3); DEL($5); } + | '#' '(' minTypMax ',' minTypMax ',' minTypMax ')' { $$ = $3; RISEFALLDLYUNSUP($3); DEL($5); DEL($7); } ; delay_value: // ==IEEE:delay_value @@ -2715,7 +2719,7 @@ delayExpr: minTypMax: // IEEE: mintypmax_expression and constant_mintypmax_expression delayExpr { $$ = $1; } - | delayExpr ':' delayExpr ':' delayExpr { $$ = $3; DEL($1); DEL($5); } + | delayExpr ':' delayExpr ':' delayExpr { $$ = $3; MINTYPMAXDLYUNSUP($3); DEL($1); DEL($5); } ; netSigList: // IEEE: list_of_port_identifiers @@ -2729,8 +2733,9 @@ netSig: // IEEE: net_decl_assignment - one element from | netId sigAttrListE '=' expr { $$ = VARDONEA($1, *$1, nullptr, $2); auto* const assignp = new AstAssignW{$3, new AstVarRef{$1, *$1, VAccess::WRITE}, $4}; - if ($$->delayp()) assignp->addTimingControlp($$->delayp()->unlinkFrBack()); // IEEE 1800-2017 10.3.3 - $$->addNext(assignp); } | netId variable_dimensionList sigAttrListE + if ($$->delayp()) assignp->timingControlp($$->delayp()->unlinkFrBack()); // IEEE 1800-2017 10.3.3 + $$->addNext(assignp); } + | netId variable_dimensionList sigAttrListE { $$ = VARDONEA($1,*$1, $2, $3); } ; @@ -3270,8 +3275,14 @@ statement_item: // IEEE: statement_item // | par_block { $$ = $1; } // // IEEE: procedural_timing_control_statement + procedural_timing_control - | delay_control stmtBlock { $$ = new AstDelay{$1->fileline(), $1, $2}; } - | event_control stmtBlock { $$ = new AstEventControl(FILELINE_OR_CRE($1), $1, $2); } + | delay_control stmtBlock { AstNode* nextp = nullptr; + if ($2 && $2->nextp()) nextp = $2->nextp()->unlinkFrBackWithNext(); + $$ = new AstDelay{$1->fileline(), $1, $2}; + $$->addNextNull(nextp); } + | event_control stmtBlock { AstNode* nextp = nullptr; + if ($2 && $2->nextp()) nextp = $2->nextp()->unlinkFrBackWithNext(); + $$ = new AstEventControl{FILELINE_OR_CRE($1), $1, $2}; + $$->addNextNull(nextp); } //UNSUP cycle_delay stmtBlock { UNSUP } // | seq_block { $$ = $1; } @@ -4704,33 +4715,33 @@ stream_expressionOrDataType: // IEEE: from streaming_concatenation // Gate declarations gateDecl: - yBUF delayE gateBufList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yBUFIF0 delayE gateBufif0List ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yBUFIF1 delayE gateBufif1List ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yNOT delayE gateNotList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yNOTIF0 delayE gateNotif0List ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yNOTIF1 delayE gateNotif1List ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yAND delayE gateAndList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yNAND delayE gateNandList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yOR delayE gateOrList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yNOR delayE gateNorList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yXOR delayE gateXorList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yXNOR delayE gateXnorList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yPULLUP delayE gatePullupList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yPULLDOWN delayE gatePulldownList ';' { $$ = $3; PRIMDLYUNSUP($2); } - | yNMOS delayE gateBufif1List ';' { $$ = $3; PRIMDLYUNSUP($2); } // ~=bufif1, as don't have strengths yet - | yPMOS delayE gateBufif0List ';' { $$ = $3; PRIMDLYUNSUP($2); } // ~=bufif0, as don't have strengths yet + yBUF delay_controlE gateBufList ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } + | yBUFIF0 delay_controlE gateBufif0List ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } + | yBUFIF1 delay_controlE gateBufif1List ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } + | yNOT delay_controlE gateNotList ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } + | yNOTIF0 delay_controlE gateNotif0List ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } + | yNOTIF1 delay_controlE gateNotif1List ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } + | yAND delay_controlE gateAndList ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } + | yNAND delay_controlE gateNandList ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } + | yOR delay_controlE gateOrList ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } + | yNOR delay_controlE gateNorList ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } + | yXOR delay_controlE gateXorList ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } + | yXNOR delay_controlE gateXnorList ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } + | yPULLUP delay_controlE gatePullupList ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } + | yPULLDOWN delay_controlE gatePulldownList ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } + | yNMOS delay_controlE gateBufif1List ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } // ~=bufif1, as don't have strengths yet + | yPMOS delay_controlE gateBufif0List ';' { $$ = $3; PUT_DLYS_IN_ASSIGNS($2, $3); } // ~=bufif0, as don't have strengths yet // - | yTRAN delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"tran"); } // Unsupported - | yRCMOS delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rcmos"); } // Unsupported - | yCMOS delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"cmos"); } // Unsupported - | yRNMOS delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rmos"); } // Unsupported - | yRPMOS delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"pmos"); } // Unsupported - | yRTRAN delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rtran"); } // Unsupported - | yRTRANIF0 delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rtranif0"); } // Unsupported - | yRTRANIF1 delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rtranif1"); } // Unsupported - | yTRANIF0 delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"tranif0"); } // Unsupported - | yTRANIF1 delayE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"tranif1"); } // Unsupported + | yTRAN delay_controlE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"tran"); } // Unsupported + | yRCMOS delay_controlE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rcmos"); } // Unsupported + | yCMOS delay_controlE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"cmos"); } // Unsupported + | yRNMOS delay_controlE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rmos"); } // Unsupported + | yRPMOS delay_controlE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"pmos"); } // Unsupported + | yRTRAN delay_controlE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rtran"); } // Unsupported + | yRTRANIF0 delay_controlE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rtranif0"); } // Unsupported + | yRTRANIF1 delay_controlE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"rtranif1"); } // Unsupported + | yTRANIF0 delay_controlE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"tranif0"); } // Unsupported + | yTRANIF1 delay_controlE gateUnsupList ';' { $$ = $3; GATEUNSUP($3,"tranif1"); } // Unsupported ; gateBufList: @@ -6541,6 +6552,7 @@ vltItem: vltOffFront: yVLT_COVERAGE_OFF { $$ = V3ErrorCode::I_COVERAGE; } + | yVLT_TIMING_OFF { $$ = V3ErrorCode::I_TIMING; } | yVLT_TRACING_OFF { $$ = V3ErrorCode::I_TRACING; } | yVLT_LINT_OFF { $$ = V3ErrorCode::I_LINT; } | yVLT_LINT_OFF yVLT_D_RULE idAny @@ -6550,6 +6562,7 @@ vltOffFront: vltOnFront: yVLT_COVERAGE_ON { $$ = V3ErrorCode::I_COVERAGE; } + | yVLT_TIMING_ON { $$ = V3ErrorCode::I_TIMING; } | yVLT_TRACING_ON { $$ = V3ErrorCode::I_TRACING; } | yVLT_LINT_ON { $$ = V3ErrorCode::I_LINT; } | yVLT_LINT_ON yVLT_D_RULE idAny diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 22a2a67f8..5f33c65eb 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -1125,7 +1125,7 @@ sub compile { } if (!$param{fails} && $param{make_main}) { - $self->_make_main(); + $self->_make_main($param{timing_loop}); } if ($param{verilator_make_gmake} @@ -1480,6 +1480,12 @@ sub have_sc { return 0; } +sub have_coroutines { + my $self = (ref $_[0] ? shift : $Self); + return 1 if $self->verilator_version =~ /coroutine support *= *1/i; + return 0; +} + sub make_version { my $ver = `$ENV{MAKE} --version`; if ($ver =~ /make ([0-9]+\.[0-9]+)/i) { @@ -1731,6 +1737,11 @@ sub _try_regex { sub _make_main { my $self = shift; + my $timing_loop = shift; + + if ($timing_loop && $self->sc) { + $self->error("Cannot use timing loop and SystemC together!\n"); + } if ($self->vhdl) { $self->_read_inputs_vhdl(); @@ -1859,33 +1870,61 @@ sub _make_main { } print $fh " ${set}fastclk = false;\n" if $self->{inputs}{fastclk}; print $fh " ${set}clk = false;\n" if $self->{inputs}{clk}; - _print_advance_time($self, $fh, 10); + if (!$timing_loop) { + _print_advance_time($self, $fh, 10); + } print $fh " }\n"; my $time = $self->sc ? "sc_time_stamp()" : "contextp->time()"; - print $fh " while ((${time} < sim_time * MAIN_TIME_MULTIPLIER)\n"; - print $fh " && !contextp->gotFinish()) {\n"; + print $fh " while ("; + if (!$timing_loop || $self->{inputs}{clk}) { + print $fh "(${time} < sim_time * MAIN_TIME_MULTIPLIER) && "; + } + print $fh "!contextp->gotFinish()) {\n"; - for (my $i = 0; $i < 5; $i++) { - my $action = 0; - if ($self->{inputs}{fastclk}) { - print $fh " ${set}fastclk = !${set}fastclk;\n"; - $action = 1; + if ($timing_loop) { + print $fh " topp->eval();\n"; + if ($self->{trace}) { + $fh->print("#if VM_TRACE\n"); + $fh->print(" if (tfp) tfp->dump(contextp->time());\n"); + $fh->print("#endif // VM_TRACE\n"); } - if ($i == 0 && $self->{inputs}{clk}) { - print $fh " ${set}clk = !${set}clk;\n"; - $action = 1; + if ($self->{inputs}{clk}) { + print $fh " uint64_t cycles = contextp->time() / MAIN_TIME_MULTIPLIER;\n"; + print $fh " uint64_t new_time = (cycles + 1) * MAIN_TIME_MULTIPLIER;\n"; + print $fh " if (topp->eventsPending() &&\n"; + print $fh " topp->nextTimeSlot() / MAIN_TIME_MULTIPLIER <= cycles) {\n"; + print $fh " new_time = topp->nextTimeSlot();\n"; + print $fh " } else {\n"; + print $fh " ${set}clk = !${set}clk;\n"; + print $fh " }\n"; + print $fh " contextp->time(new_time);\n"; + } else { + print $fh " if (!topp->eventsPending()) break;\n"; + print $fh " contextp->time(topp->nextTimeSlot());\n"; } - if ($self->{savable}) { - $fh->print(" if (save_time && ${time} == save_time) {\n"); - $fh->print(" save_model(\"$self->{obj_dir}/saved.vltsv\");\n"); - $fh->print(" printf(\"Exiting after save_model\\n\");\n"); - $fh->print(" topp.reset(nullptr);\n"); - $fh->print(" return 0;\n"); - $fh->print(" }\n"); + } else { + for (my $i = 0; $i < 5; $i++) { + my $action = 0; + if ($self->{inputs}{fastclk}) { + print $fh " ${set}fastclk = !${set}fastclk;\n"; + $action = 1; + } + if ($i == 0 && $self->{inputs}{clk}) { + print $fh " ${set}clk = !${set}clk;\n"; + $action = 1; + } + if ($self->{savable}) { + $fh->print(" if (save_time && ${time} == save_time) {\n"); + $fh->print(" save_model(\"$self->{obj_dir}/saved.vltsv\");\n"); + $fh->print(" printf(\"Exiting after save_model\\n\");\n"); + $fh->print(" topp.reset(nullptr);\n"); + $fh->print(" return 0;\n"); + $fh->print(" }\n"); + } + _print_advance_time($self, $fh, 1, $action); } - _print_advance_time($self, $fh, 1, $action); } if ($self->{benchmarksim}) { $fh->print(" if (VL_UNLIKELY(!warm)) {\n"); @@ -1941,7 +1980,7 @@ sub _print_advance_time { else { $set = "topp->"; } if ($self->sc) { - print $fh " sc_start(${time}, $Self->{sc_time_resolution});\n"; + print $fh " sc_start(${time} * MAIN_TIME_MULTIPLIER, $Self->{sc_time_resolution});\n"; } else { if ($action) { print $fh " ${set}eval();\n"; diff --git a/test_regress/t/t_altera_lpm_counter.pl b/test_regress/t/t_altera_lpm_counter.pl index e079ef062..78ec8c557 100755 --- a/test_regress/t/t_altera_lpm_counter.pl +++ b/test_regress/t/t_altera_lpm_counter.pl @@ -14,7 +14,7 @@ top_filename("t/t_altera_lpm.v"); (my $module = $Self->{name}) =~ s/.*t_altera_//; compile( - verilator_flags2 => ["--top-module ${module}"] + verilator_flags2 => ["--top-module ${module}", "--no-timing"] ); ok(1); diff --git a/test_regress/t/t_delay.pl b/test_regress/t/t_delay.pl index cf79784fb..3e8a3c919 100755 --- a/test_regress/t/t_delay.pl +++ b/test_regress/t/t_delay.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2 => ['-Wno-STMTDLY -Wno-ASSIGNDLY'], + verilator_flags2 => ['-Wno-STMTDLY -Wno-ASSIGNDLY --no-timing'], ); execute( diff --git a/test_regress/t/t_delay.v b/test_regress/t/t_delay.v index c391c5b61..161362387 100644 --- a/test_regress/t/t_delay.v +++ b/test_regress/t/t_delay.v @@ -4,6 +4,8 @@ // any use, without warranty, 2003 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 +`timescale 100ns/1ns + module t (/*AUTOARG*/ // Inputs clk diff --git a/test_regress/t/t_delay_func_bad.out b/test_regress/t/t_delay_func_bad.out deleted file mode 100644 index dd63449c5..000000000 --- a/test_regress/t/t_delay_func_bad.out +++ /dev/null @@ -1,9 +0,0 @@ -%Error: t/t_delay_func_bad.v:10:8: Delays are not legal in functions. Suggest use a task (IEEE 1800-2017 13.4.4) - : ... In instance t - 10 | #1 $stop; - | ^ -%Error: t/t_delay_func_bad.v:23:8: Delays are not legal in final blocks (IEEE 1800-2017 9.2.3) - : ... In instance t - 23 | #1; - | ^ -%Error: Exiting due to diff --git a/test_regress/t/t_delay_func_bad.v b/test_regress/t/t_delay_func_bad.v deleted file mode 100644 index aa7ceddfc..000000000 --- a/test_regress/t/t_delay_func_bad.v +++ /dev/null @@ -1,27 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2020 by Wilson Snyder. -// SPDX-License-Identifier: CC0-1.0 - -module t(/*AUTOARG*/); - - function int f; - #1 $stop; - f = 0; - endfunction - - int i; - - initial begin - i = f(); - $write("*-* All Finished *-*\n"); - $finish; - end - - final begin - #1; - $stop; - end - -endmodule diff --git a/test_regress/t/t_delay_stmtdly_bad.out b/test_regress/t/t_delay_stmtdly_bad.out index fe957acdb..90327f0d8 100644 --- a/test_regress/t/t_delay_stmtdly_bad.out +++ b/test_regress/t/t_delay_stmtdly_bad.out @@ -1,31 +1,31 @@ -%Warning-ASSIGNDLY: t/t_delay.v:22:13: Unsupported: Ignoring timing control on this assignment. +%Warning-ASSIGNDLY: t/t_delay.v:24:13: Ignoring timing control on this assignment/primitive due to --no-timing : ... In instance t - 22 | assign #(1.2000000000000000) dly1 = dly0 + 32'h1; + 24 | assign #(1.2000000000000000) dly1 = dly0 + 32'h1; | ^~~~~~~~~~~~~~~~~~ ... For warning description see https://verilator.org/warn/ASSIGNDLY?v=latest ... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message. -%Warning-ASSIGNDLY: t/t_delay.v:27:19: Unsupported: Ignoring timing control on this assignment. +%Warning-ASSIGNDLY: t/t_delay.v:29:19: Ignoring timing control on this assignment/primitive due to --no-timing : ... In instance t - 27 | dly0 <= #0 32'h11; + 29 | dly0 <= #0 32'h11; | ^ -%Warning-ASSIGNDLY: t/t_delay.v:30:19: Unsupported: Ignoring timing control on this assignment. +%Warning-ASSIGNDLY: t/t_delay.v:32:19: Ignoring timing control on this assignment/primitive due to --no-timing : ... In instance t - 30 | dly0 <= #0.12 dly0 + 32'h12; + 32 | dly0 <= #0.12 dly0 + 32'h12; | ^~~~ -%Warning-ASSIGNDLY: t/t_delay.v:38:26: Unsupported: Ignoring timing control on this assignment. +%Warning-ASSIGNDLY: t/t_delay.v:40:26: Ignoring timing control on this assignment/primitive due to --no-timing : ... In instance t - 38 | dly0 <= #(dly_s.dly) 32'h55; + 40 | dly0 <= #(dly_s.dly) 32'h55; | ^~~ -%Warning-STMTDLY: t/t_delay.v:43:11: Unsupported: Ignoring delay on this delayed statement. +%Warning-STMTDLY: t/t_delay.v:45:11: Ignoring delay on this statement due to --no-timing : ... In instance t - 43 | #100 $finish; + 45 | #100 $finish; | ^~~ -%Warning-UNUSED: t/t_delay.v:20:12: Signal is not used: 'dly_s' +%Warning-UNUSED: t/t_delay.v:22:12: Signal is not used: 'dly_s' : ... In instance t - 20 | dly_s_t dly_s; + 22 | dly_s_t dly_s; | ^~~~~ -%Warning-BLKSEQ: t/t_delay.v:37:20: Blocking assignment '=' in sequential logic process +%Warning-BLKSEQ: t/t_delay.v:39:20: Blocking assignment '=' in sequential logic process : ... Suggest using delayed assignment '<=' - 37 | dly_s.dly = 55; + 39 | dly_s.dly = 55; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_delay_stmtdly_bad.pl b/test_regress/t/t_delay_stmtdly_bad.pl index 85ea0432b..59820b3fb 100755 --- a/test_regress/t/t_delay_stmtdly_bad.pl +++ b/test_regress/t/t_delay_stmtdly_bad.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); top_filename("t/t_delay.v"); lint( - verilator_flags2 => ['-Wall -Wno-DECLFILENAME'], + verilator_flags2 => ['--no-timing -Wall -Wno-DECLFILENAME'], fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_delay_timing.pl b/test_regress/t/t_delay_timing.pl new file mode 100755 index 000000000..505ebf865 --- /dev/null +++ b/test_regress/t/t_delay_timing.pl @@ -0,0 +1,32 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +$Self->{main_time_multiplier} = 10e-7 / 10e-9; + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + top_filename("t/t_delay.v"); + + compile( + timing_loop => 1, + verilator_flags2 => ['--timing -Wno-ZERODLY'], + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_event_control.out b/test_regress/t/t_event_control.out new file mode 100644 index 000000000..f04260a95 --- /dev/null +++ b/test_regress/t/t_event_control.out @@ -0,0 +1,12 @@ +%Error-NOTIMING: t/t_event_control.v:14:7: Event control statement in this location requires --timing + : ... In instance t + : ... With --no-timing, suggest have one event control statement per procedure, at the top of the procedure + 14 | @(clk); + | ^ + ... For error description see https://verilator.org/warn/NOTIMING?v=latest +%Error-NOTIMING: t/t_event_control.v:16:7: Event control statement in this location requires --timing + : ... In instance t + : ... With --no-timing, suggest have one event control statement per procedure, at the top of the procedure + 16 | @(clk); + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_event_control_unsup.pl b/test_regress/t/t_event_control.pl similarity index 90% rename from test_regress/t/t_event_control_unsup.pl rename to test_regress/t/t_event_control.pl index be66c40e6..1047a4907 100755 --- a/test_regress/t/t_event_control_unsup.pl +++ b/test_regress/t/t_event_control.pl @@ -11,13 +11,10 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( + verilator_flags2 => ['--no-timing'], fails => $Self->{vlt_all}, expect_filename => $Self->{golden_filename}, ); -execute( - check_finished => 1, - ) if !$Self->{vlt_all}; - ok(1); 1; diff --git a/test_regress/t/t_event_control_unsup.v b/test_regress/t/t_event_control.v similarity index 100% rename from test_regress/t/t_event_control_unsup.v rename to test_regress/t/t_event_control.v diff --git a/test_regress/t/t_event_control_timing.out b/test_regress/t/t_event_control_timing.out new file mode 100644 index 000000000..35690cce5 --- /dev/null +++ b/test_regress/t/t_event_control_timing.out @@ -0,0 +1,3 @@ +[10] Got +[15] Got +*-* All Finished *-* diff --git a/test_regress/t/t_event_control_timing.pl b/test_regress/t/t_event_control_timing.pl new file mode 100755 index 000000000..6a4829740 --- /dev/null +++ b/test_regress/t/t_event_control_timing.pl @@ -0,0 +1,30 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + top_filename("t/t_event_control.v"); + + compile( + verilator_flags2 => ["--timing"], + ); + + execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_event_control_unsup.out b/test_regress/t/t_event_control_unsup.out deleted file mode 100644 index 7c40c182e..000000000 --- a/test_regress/t/t_event_control_unsup.out +++ /dev/null @@ -1,12 +0,0 @@ -%Error-UNSUPPORTED: t/t_event_control_unsup.v:14:7: Unsupported: event control statement in this location - : ... In instance t - : ... Suggest have one event control statement per procedure, at the top of the procedure - 14 | @(clk); - | ^ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_event_control_unsup.v:16:7: Unsupported: event control statement in this location - : ... In instance t - : ... Suggest have one event control statement per procedure, at the top of the procedure - 16 | @(clk); - | ^ -%Error: Exiting due to diff --git a/test_regress/t/t_fork.out b/test_regress/t/t_fork.out index f0f3b3489..6070aeb85 100644 --- a/test_regress/t/t_fork.out +++ b/test_regress/t/t_fork.out @@ -1,6 +1,6 @@ -%Error-UNSUPPORTED: t/t_fork.v:10:14: Unsupported: fork statements - : ... In instance t +%Error-NOTIMING: t/t_fork.v:10:14: Fork statements require --timing + : ... In instance t 10 | fork : fblk | ^~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest + ... For error description see https://verilator.org/warn/NOTIMING?v=latest %Error: Exiting due to diff --git a/test_regress/t/t_fork.pl b/test_regress/t/t_fork.pl index a5846c699..9459580d1 100755 --- a/test_regress/t/t_fork.pl +++ b/test_regress/t/t_fork.pl @@ -11,6 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); lint( + verilator_flags2 => ['--no-timing'], fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_fork_bbox.pl b/test_regress/t/t_fork_bbox.pl index 3a83673be..72f18add1 100755 --- a/test_regress/t/t_fork_bbox.pl +++ b/test_regress/t/t_fork_bbox.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); lint( - verilator_flags2 => ['--lint-only --bbox-unsup'], + verilator_flags2 => ['--lint-only --no-timing --bbox-unsup'], ); ok(1); diff --git a/test_regress/t/t_fork_disable.out b/test_regress/t/t_fork_disable.out index 9c589b372..62ba6a34f 100644 --- a/test_regress/t/t_fork_disable.out +++ b/test_regress/t/t_fork_disable.out @@ -1,12 +1,8 @@ -%Error-UNSUPPORTED: t/t_fork_disable.v:12:7: Unsupported: fork statements - : ... In instance t - 12 | fork - | ^~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error-UNSUPPORTED: t/t_fork_disable.v:16:7: Unsupported: disable fork statements : ... In instance t 16 | disable fork; | ^~~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error-UNSUPPORTED: t/t_fork_disable.v:17:7: Unsupported: wait fork statements : ... In instance t 17 | wait fork; diff --git a/test_regress/t/t_fork_disable.pl b/test_regress/t/t_fork_disable.pl index 89ffd046b..0ca21a5ca 100755 --- a/test_regress/t/t_fork_disable.pl +++ b/test_regress/t/t_fork_disable.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(linter => 1); lint( - verilator_flags2 => ['--lint-only'], + verilator_flags2 => ['--lint-only --timing'], fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_fork_label.pl b/test_regress/t/t_fork_label.pl index 1c4ba9485..8bb4480e1 100755 --- a/test_regress/t/t_fork_label.pl +++ b/test_regress/t/t_fork_label.pl @@ -10,7 +10,9 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -compile(); +compile( + verilator_flags2 => ['--no-timing'], + ); execute(); diff --git a/test_regress/t/t_fork_label_timing.pl b/test_regress/t/t_fork_label_timing.pl new file mode 100755 index 000000000..8d67932b9 --- /dev/null +++ b/test_regress/t/t_fork_label_timing.pl @@ -0,0 +1,30 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + top_filename("t/t_fork_label.v"); + + compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_fork_timing.pl b/test_regress/t/t_fork_timing.pl new file mode 100755 index 000000000..f31aef7c3 --- /dev/null +++ b/test_regress/t/t_fork_timing.pl @@ -0,0 +1,29 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + top_filename("t/t_fork.v"); + + compile( + verilator_flags2 => ["--timing"], + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_func_lib_sub.pl b/test_regress/t/t_func_lib_sub.pl index 6c38477cd..8651e4fd4 100755 --- a/test_regress/t/t_func_lib_sub.pl +++ b/test_regress/t/t_func_lib_sub.pl @@ -11,6 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt_all => 1); compile( + verilator_flags2 => ['--no-timing'], ); # No execute ok(1); diff --git a/test_regress/t/t_func_lib_sub_timing.pl b/test_regress/t/t_func_lib_sub_timing.pl new file mode 100755 index 000000000..0acb617a6 --- /dev/null +++ b/test_regress/t/t_func_lib_sub_timing.pl @@ -0,0 +1,25 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); # UNOPTTHREADS in vltmt + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + top_filename("t/t_func_lib_sub.v"); + + compile( + verilator_flags2 => ["--timing"], + ); +} +# No execute +ok(1); +1; diff --git a/test_regress/t/t_func_rand.pl b/test_regress/t/t_func_rand.pl index ce5a6dd80..32375a0ef 100755 --- a/test_regress/t/t_func_rand.pl +++ b/test_regress/t/t_func_rand.pl @@ -13,7 +13,7 @@ scenarios(vlt_all => 1); compile( make_top_shell => 0, make_main => 0, - verilator_flags2 => ["--exe $Self->{t_dir}/$Self->{name}.cpp"], + verilator_flags2 => ["--exe $Self->{t_dir}/$Self->{name}.cpp", "--no-timing"], ); execute( diff --git a/test_regress/t/t_gate_basic.pl b/test_regress/t/t_gate_basic.pl index a17622844..b56aa9309 100755 --- a/test_regress/t/t_gate_basic.pl +++ b/test_regress/t/t_gate_basic.pl @@ -11,6 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( + verilator_flags2 => ["--no-timing"], ); execute( diff --git a/test_regress/t/t_gate_basic_timing.pl b/test_regress/t/t_gate_basic_timing.pl new file mode 100755 index 000000000..713929427 --- /dev/null +++ b/test_regress/t/t_gate_basic_timing.pl @@ -0,0 +1,32 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +$Self->{main_time_multiplier} = 10e-7 / 10e-9; + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + top_filename("t/t_gate_basic.v"); + + compile( + timing_loop => 1, + verilator_flags2 => ["--timing --timescale 10ns/1ns -Wno-RISEFALLDLY"], + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_gate_delay_unsup.out b/test_regress/t/t_gate_delay_unsup.out index 7a1697074..c3e3e70fd 100644 --- a/test_regress/t/t_gate_delay_unsup.out +++ b/test_regress/t/t_gate_delay_unsup.out @@ -1,12 +1,6 @@ -%Warning-ASSIGNDLY: t/t_gate_basic.v:23:12: Unsupported: Ignoring delay on this primitive. - 23 | not #(0.108) NT0 (nt0, a[0]); - | ^~~~~ - ... For warning description see https://verilator.org/warn/ASSIGNDLY?v=latest - ... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message. -%Warning-ASSIGNDLY: t/t_gate_basic.v:24:11: Unsupported: Ignoring delay on this primitive. - 24 | and #1 AN0 (an0, a[0], b[0]); - | ^ -%Warning-ASSIGNDLY: t/t_gate_basic.v:25:12: Unsupported: Ignoring delay on this primitive. +%Warning-RISEFALLDLY: t/t_gate_basic.v:25:12: Unsupported: rising/falling/turn-off delays. Using the first delay 25 | nand #(2,3) ND0 (nd0, a[0], b[0], b[1]); | ^ + ... For warning description see https://verilator.org/warn/RISEFALLDLY?v=latest + ... Use "/* verilator lint_off RISEFALLDLY */" and lint_on around source to disable this message. %Error: Exiting due to diff --git a/test_regress/t/t_gate_delay_unsup.pl b/test_regress/t/t_gate_delay_unsup.pl index 2f885e5ae..ecb0ab324 100755 --- a/test_regress/t/t_gate_delay_unsup.pl +++ b/test_regress/t/t_gate_delay_unsup.pl @@ -13,7 +13,7 @@ scenarios(linter => 1); top_filename("t/t_gate_basic.v"); lint( - verilator_flags2 => ["--lint-only -Wall -Wno-DECLFILENAME -Wno-UNUSED"], + verilator_flags2 => ["--lint-only -Wall -Wno-DECLFILENAME -Wno-UNUSED --timing"], fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_gen_forif.pl b/test_regress/t/t_gen_forif.pl index bc8663a80..4017016a5 100755 --- a/test_regress/t/t_gen_forif.pl +++ b/test_regress/t/t_gen_forif.pl @@ -12,6 +12,7 @@ scenarios(simulator => 1); compile( nc_flags2 => ['+access+r'], + verilator_flags2 => ["--no-timing"], ); execute( diff --git a/test_regress/t/t_gen_intdot.pl b/test_regress/t/t_gen_intdot.pl index b46d46042..e245a66a7 100755 --- a/test_regress/t/t_gen_intdot.pl +++ b/test_regress/t/t_gen_intdot.pl @@ -11,6 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( + verilator_flags2 => ["--no-timing"], ); execute( diff --git a/test_regress/t/t_lib.pl b/test_regress/t/t_lib.pl index 93aa4bfd8..ef6fcd3b2 100755 --- a/test_regress/t/t_lib.pl +++ b/test_regress/t/t_lib.pl @@ -30,6 +30,7 @@ while (1) { run(logfile => "$secret_dir/vlt_compile.log", cmd => ["perl", "$ENV{VERILATOR_ROOT}/bin/verilator", + '--no-timing', "--prefix", "Vt_lib_prot_secret", "-cc", @@ -52,6 +53,7 @@ while (1) { compile( verilator_flags2 => ["$secret_dir/secret.sv", + '--no-timing', "-LDFLAGS", "$secret_prefix/libsecret.a"], xsim_flags2 => ["$secret_dir/secret.sv"], diff --git a/test_regress/t/t_lib_nolib.pl b/test_regress/t/t_lib_nolib.pl index d4b9b47e9..0a385f0cb 100755 --- a/test_regress/t/t_lib_nolib.pl +++ b/test_regress/t/t_lib_nolib.pl @@ -21,7 +21,7 @@ top_filename("t/t_lib_prot.v"); # Tests the same code as t_lib_prot.pl but without --protect-lib compile( - verilator_flags2 => ["t/t_lib_prot_secret.v"], + verilator_flags2 => ["t/t_lib_prot_secret.v", '--no-timing'], xsim_flags2 => ["t/t_lib_prot_secret.v"], ); diff --git a/test_regress/t/t_lib_prot.pl b/test_regress/t/t_lib_prot.pl index 2df0816e8..14c01dc7c 100755 --- a/test_regress/t/t_lib_prot.pl +++ b/test_regress/t/t_lib_prot.pl @@ -28,6 +28,7 @@ while (1) { run(logfile => "$secret_dir/vlt_compile.log", cmd => ["perl", "$ENV{VERILATOR_ROOT}/bin/verilator", + '--no-timing', "--prefix", "Vt_lib_prot_secret", "-cc", @@ -52,6 +53,7 @@ while (1) { compile( verilator_flags2 => ["$secret_dir/secret.sv", + '--no-timing', "-LDFLAGS", "$secret_prefix/libsecret.a"], xsim_flags2 => ["$secret_dir/secret.sv"], diff --git a/test_regress/t/t_lib_prot_clk_gated.pl b/test_regress/t/t_lib_prot_clk_gated.pl index 4a290d26d..b1286cca2 100755 --- a/test_regress/t/t_lib_prot_clk_gated.pl +++ b/test_regress/t/t_lib_prot_clk_gated.pl @@ -29,6 +29,7 @@ while (1) { run(logfile => "$secret_dir/vlt_compile.log", cmd => ["perl", "$ENV{VERILATOR_ROOT}/bin/verilator", + '--no-timing', "--prefix", "Vt_lib_prot_secret", "-cc", @@ -54,6 +55,7 @@ while (1) { compile( verilator_flags2 => ["$secret_dir/secret.sv", + '--no-timing', "-GGATED_CLK=1", "-LDFLAGS", "$secret_prefix/libsecret.a"], diff --git a/test_regress/t/t_lib_prot_shared.pl b/test_regress/t/t_lib_prot_shared.pl index cc0c2f977..cd8b2a1c6 100755 --- a/test_regress/t/t_lib_prot_shared.pl +++ b/test_regress/t/t_lib_prot_shared.pl @@ -32,6 +32,7 @@ while (1) { cmd => ["perl", "$ENV{VERILATOR_ROOT}/bin/verilator", ($Self->{vltmt} ? ' --threads 6' : ''), + '--no-timing', "--prefix", "Vt_lib_prot_secret", "-cc", @@ -56,6 +57,7 @@ while (1) { compile( verilator_flags2 => ["$secret_dir/secret.sv", + '--no-timing', "-LDFLAGS", "'-Wl,-rpath,$abs_secret_dir -L$abs_secret_dir -l$secret_prefix'"], xsim_flags2 => ["$secret_dir/secret.sv"], diff --git a/test_regress/t/t_lint_stmtdly_bad.out b/test_regress/t/t_lint_stmtdly_bad.out index f23238765..b47faf8ef 100644 --- a/test_regress/t/t_lint_stmtdly_bad.out +++ b/test_regress/t/t_lint_stmtdly_bad.out @@ -1,4 +1,4 @@ -%Warning-STMTDLY: t/t_lint_stmtdly_bad.v:10:8: Unsupported: Ignoring delay on this delayed statement. +%Warning-STMTDLY: t/t_lint_stmtdly_bad.v:10:8: Ignoring delay on this statement due to --no-timing : ... In instance t 10 | #100 $finish; | ^~~ diff --git a/test_regress/t/t_lint_stmtdly_bad.pl b/test_regress/t/t_lint_stmtdly_bad.pl index 548dab0af..bcb7303da 100755 --- a/test_regress/t/t_lint_stmtdly_bad.pl +++ b/test_regress/t/t_lint_stmtdly_bad.pl @@ -11,6 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); compile( + verilator_flags2 => ["--no-timing"], fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_lint_wait_bad.out b/test_regress/t/t_lint_wait_bad.out new file mode 100644 index 000000000..5ceecf26d --- /dev/null +++ b/test_regress/t/t_lint_wait_bad.out @@ -0,0 +1,12 @@ +%Warning-WAITCONST: t/t_timing_wait.v:47:13: Wait statement condition is constant + 47 | wait(0 < 1) $write("*-* All Finished *-*\n"); + | ^ + ... For warning description see https://verilator.org/warn/WAITCONST?v=latest + ... Use "/* verilator lint_off WAITCONST */" and lint_on around source to disable this message. +%Warning-WAITCONST: t/t_timing_wait.v:51:17: Wait statement condition is constant + 51 | initial wait(0) $stop; + | ^ +%Warning-WAITCONST: t/t_timing_wait.v:52:19: Wait statement condition is constant + 52 | initial wait(1 == 0) $stop; + | ^~ +%Error: Exiting due to diff --git a/test_regress/t/t_lint_wait_bad.pl b/test_regress/t/t_lint_wait_bad.pl new file mode 100755 index 000000000..7500d4750 --- /dev/null +++ b/test_regress/t/t_lint_wait_bad.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t/t_timing_wait.v"); + +lint( + verilator_flags2 => ["--timing"], + expect_filename => $Self->{golden_filename}, + fails => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_math_signed5.pl b/test_regress/t/t_math_signed5.pl index b46d46042..f5debdb98 100755 --- a/test_regress/t/t_math_signed5.pl +++ b/test_regress/t/t_math_signed5.pl @@ -11,6 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( + verilator_flags2 => ['--no-timing'], ); execute( diff --git a/test_regress/t/t_math_signed5_timing.pl b/test_regress/t/t_math_signed5_timing.pl new file mode 100755 index 000000000..2365fef9a --- /dev/null +++ b/test_regress/t/t_math_signed5_timing.pl @@ -0,0 +1,30 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + top_filename("t/t_math_signed5.v"); + + compile( + verilator_flags2 => ['--timing'], + timing_loop => 1, + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_mem_slot.pl b/test_regress/t/t_mem_slot.pl index 19193485f..9e97f1977 100755 --- a/test_regress/t/t_mem_slot.pl +++ b/test_regress/t/t_mem_slot.pl @@ -13,7 +13,7 @@ scenarios(vlt_all => 1); compile( make_top_shell => 0, make_main => 0, - verilator_flags2 => ["--exe $Self->{t_dir}/$Self->{name}.cpp"], + verilator_flags2 => ["--exe $Self->{t_dir}/$Self->{name}.cpp --no-timing"], ); execute( diff --git a/test_regress/t/t_mod_dollar$.pl b/test_regress/t/t_mod_dollar$.pl index 2d8172ca7..7441e7b09 100755 --- a/test_regress/t/t_mod_dollar$.pl +++ b/test_regress/t/t_mod_dollar$.pl @@ -14,7 +14,7 @@ scenarios(vlt => 1); # prefix properly using post-escaped identifiers run(cmd => ["../bin/verilator", "--cc", - "--Mdir obj_vlt/t_mod_dollar", + "--Mdir " . $Self->{obj_dir} . "/t_mod_dollar", "--exe --build --main", 't/t_mod_dollar$.v', ], diff --git a/test_regress/t/t_net_delay.out b/test_regress/t/t_net_delay.out new file mode 100644 index 000000000..1b79c6bac --- /dev/null +++ b/test_regress/t/t_net_delay.out @@ -0,0 +1,11 @@ +%Warning-ASSIGNDLY: t/t_net_delay.v:13:15: Ignoring timing control on this assignment/primitive due to --no-timing + : ... In instance t + 13 | wire[3:0] #4 val1 = cyc; + | ^ + ... For warning description see https://verilator.org/warn/ASSIGNDLY?v=latest + ... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message. +%Warning-ASSIGNDLY: t/t_net_delay.v:17:12: Ignoring timing control on this assignment/primitive due to --no-timing + : ... In instance t + 17 | assign #4 val2 = cyc; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_timing_intra_assign_event.pl b/test_regress/t/t_net_delay.pl similarity index 89% rename from test_regress/t/t_timing_intra_assign_event.pl rename to test_regress/t/t_net_delay.pl index d61820774..09ee1bbae 100755 --- a/test_regress/t/t_timing_intra_assign_event.pl +++ b/test_regress/t/t_net_delay.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); lint( - verilator_flags2 => ['-Wall -Wno-DECLFILENAME'], + verilator_flags2 => ['-Wall -Wno-DECLFILENAME --no-timing'], fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_timing_net_delay.v b/test_regress/t/t_net_delay.v similarity index 91% rename from test_regress/t/t_timing_net_delay.v rename to test_regress/t/t_net_delay.v index aa125ca8c..c9b524005 100644 --- a/test_regress/t/t_timing_net_delay.v +++ b/test_regress/t/t_net_delay.v @@ -21,7 +21,7 @@ module t (/*AUTOARG*/ `ifdef TEST_VERBOSE $write("[%0t] cyc=%0d, val1=%0d, val2=%0d\n", $time, cyc, val1, val2); `endif - if (cyc >= 4 && val1 != cyc-1 && val2 != cyc-3) $stop; + if (cyc >= 7 && val1 != cyc-1 && val2 != cyc-7) $stop; if (cyc == 15) begin $write("*-* All Finished *-*\n"); $finish; diff --git a/test_regress/t/t_net_delay_timing.pl b/test_regress/t/t_net_delay_timing.pl new file mode 100755 index 000000000..63a94fdbd --- /dev/null +++ b/test_regress/t/t_net_delay_timing.pl @@ -0,0 +1,30 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + top_filename("t/t_net_delay.v"); + + compile( + timing_loop => 1, + verilator_flags2 => ["--timing"], + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_net_delay_timing_sc.pl b/test_regress/t/t_net_delay_timing_sc.pl new file mode 100755 index 000000000..1fd75cffb --- /dev/null +++ b/test_regress/t/t_net_delay_timing_sc.pl @@ -0,0 +1,34 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +$Self->{main_time_multiplier} = 2; + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +elsif (!$Self->have_sc) { + skip("No SystemC installed"); +} +else { + top_filename("t/t_net_delay.v"); + + compile( + verilator_flags2 => ["--sc --exe --timing --timescale 10ps/1ps"], + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_notiming.out b/test_regress/t/t_notiming.out new file mode 100644 index 000000000..cb2b6017c --- /dev/null +++ b/test_regress/t/t_notiming.out @@ -0,0 +1,33 @@ +%Warning-STMTDLY: t/t_notiming.v:12:9: Ignoring delay on this statement due to --no-timing + : ... In instance t + 12 | #1 + | ^ + ... For warning description see https://verilator.org/warn/STMTDLY?v=latest + ... Use "/* verilator lint_off STMTDLY */" and lint_on around source to disable this message. +%Error-NOTIMING: t/t_notiming.v:13:8: Fork statements require --timing + : ... In instance t + 13 | fork @e; @e; join; + | ^~~~ +%Error-NOTIMING: t/t_notiming.v:14:8: Event control statement in this location requires --timing + : ... In instance t + : ... With --no-timing, suggest have one event control statement per procedure, at the top of the procedure + 14 | @e + | ^ +%Error-NOTIMING: t/t_notiming.v:15:8: Wait statements require --timing + : ... In instance t + 15 | wait(x == 4) + | ^~~~ +%Error-NOTIMING: t/t_notiming.v:19:8: Event control statement in this location requires --timing + : ... In instance t + : ... With --no-timing, suggest have one event control statement per procedure, at the top of the procedure + 19 | @e + | ^ +%Warning-STMTDLY: t/t_notiming.v:26:13: Ignoring delay on this statement due to --no-timing + : ... In instance t + 26 | initial #1 ->e; + | ^ +%Warning-STMTDLY: t/t_notiming.v:27:13: Ignoring delay on this statement due to --no-timing + : ... In instance t + 27 | initial #2 $stop; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_timing_net_delay.pl b/test_regress/t/t_notiming.pl similarity index 90% rename from test_regress/t/t_timing_net_delay.pl rename to test_regress/t/t_notiming.pl index d61820774..5a683788e 100755 --- a/test_regress/t/t_timing_net_delay.pl +++ b/test_regress/t/t_notiming.pl @@ -10,8 +10,8 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -lint( - verilator_flags2 => ['-Wall -Wno-DECLFILENAME'], +compile( + verilator_flags2 => ["--no-timing"], fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_notiming.v b/test_regress/t/t_notiming.v new file mode 100644 index 000000000..8c822d4d2 --- /dev/null +++ b/test_regress/t/t_notiming.v @@ -0,0 +1,28 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t; + event e; + + initial begin + int x; + #1 + fork @e; @e; join; + @e + wait(x == 4) + x = #1 8; + if (x != 8) $stop; + if ($time != 0) $stop; + @e + if (!e.triggered) $stop; + if ($time != 1) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + + initial #1 ->e; + initial #2 $stop; // timeout +endmodule diff --git a/test_regress/t/t_notiming_off.out b/test_regress/t/t_notiming_off.out new file mode 100644 index 000000000..fc269af87 --- /dev/null +++ b/test_regress/t/t_notiming_off.out @@ -0,0 +1,29 @@ +%Error-NOTIMING: t/t_timing_off.v:25:8: Event control statement in this location requires --timing + : ... In instance t + : ... With --no-timing, suggest have one event control statement per procedure, at the top of the procedure + 25 | @e1; + | ^ + ... For error description see https://verilator.org/warn/NOTIMING?v=latest +%Warning-STMTDLY: t/t_timing_off.v:33:13: Ignoring delay on this statement due to --no-timing + : ... In instance t + 33 | initial #2 ->e1; + | ^ + ... Use "/* verilator lint_off STMTDLY */" and lint_on around source to disable this message. +%Warning-STMTDLY: t/t_timing_off.v:37:13: Ignoring delay on this statement due to --no-timing + : ... In instance t + 37 | initial #3 $stop; + | ^ +%Warning-STMTDLY: t/t_timing_off.v:38:13: Ignoring delay on this statement due to --no-timing + : ... In instance t + 38 | initial #1 @(e1, e2) #1 $stop; + | ^ +%Error-NOTIMING: t/t_timing_off.v:38:15: Event control statement in this location requires --timing + : ... In instance t + : ... With --no-timing, suggest have one event control statement per procedure, at the top of the procedure + 38 | initial #1 @(e1, e2) #1 $stop; + | ^ +%Warning-STMTDLY: t/t_timing_off.v:38:26: Ignoring delay on this statement due to --no-timing + : ... In instance t + 38 | initial #1 @(e1, e2) #1 $stop; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_notiming_off.pl b/test_regress/t/t_notiming_off.pl new file mode 100755 index 000000000..cca2c7651 --- /dev/null +++ b/test_regress/t/t_notiming_off.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +top_filename("t/t_timing_off.v"); + +compile( + verilator_flags2 => ["--no-timing"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_order.pl b/test_regress/t/t_order.pl index b46d46042..800b5bdc4 100755 --- a/test_regress/t/t_order.pl +++ b/test_regress/t/t_order.pl @@ -10,7 +10,10 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); +$Self->{main_time_multiplier} = 1e-8 / 1e-9; + compile( + verilator_flags2 => ["--timescale 10ns/1ns --no-timing"], ); execute( diff --git a/test_regress/t/t_order_timing.pl b/test_regress/t/t_order_timing.pl new file mode 100755 index 000000000..ee807ce82 --- /dev/null +++ b/test_regress/t/t_order_timing.pl @@ -0,0 +1,32 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +$Self->{main_time_multiplier} = 1e-8 / 1e-9; + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + top_filename("t/t_order.v"); + + compile( + timing_loop => 1, + verilator_flags2 => ["--timescale 10ns/1ns --timing"], + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_package_ddecl.pl b/test_regress/t/t_package_ddecl.pl index b46d46042..f5debdb98 100755 --- a/test_regress/t/t_package_ddecl.pl +++ b/test_regress/t/t_package_ddecl.pl @@ -11,6 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( + verilator_flags2 => ['--no-timing'], ); execute( diff --git a/test_regress/t/t_package_ddecl_timing.pl b/test_regress/t/t_package_ddecl_timing.pl new file mode 100755 index 000000000..d471a7adb --- /dev/null +++ b/test_regress/t/t_package_ddecl_timing.pl @@ -0,0 +1,30 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + top_filename("t/t_package_ddecl.v"); + + compile( + verilator_flags2 => ['--timing'], + timing_loop => 1, + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_parse_delay.pl b/test_regress/t/t_parse_delay.pl index b46d46042..40a477a35 100755 --- a/test_regress/t/t_parse_delay.pl +++ b/test_regress/t/t_parse_delay.pl @@ -11,10 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - ); - -execute( - check_finished => 1, + verilator_flags2 => ['--no-timing'], ); ok(1); diff --git a/test_regress/t/t_parse_delay_timing.pl b/test_regress/t/t_parse_delay_timing.pl new file mode 100755 index 000000000..f4847bf8c --- /dev/null +++ b/test_regress/t/t_parse_delay_timing.pl @@ -0,0 +1,25 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + top_filename("t/t_parse_delay.v"); + + compile( + verilator_flags2 => ['--timing'], + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_always.pl b/test_regress/t/t_timing_always.pl new file mode 100755 index 000000000..f86c4b944 --- /dev/null +++ b/test_regress/t/t_timing_always.pl @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_always.v b/test_regress/t/t_timing_always.v new file mode 100644 index 000000000..e92bc2539 --- /dev/null +++ b/test_regress/t/t_timing_always.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, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +`ifdef TEST_VERBOSE + `define WRITE_VERBOSE(args) $write args +`else + `define WRITE_VERBOSE(args) +`endif + +module t; + logic clk = 0; + always #3 clk = ~clk; + + logic flag_a; + logic flag_b; + always @(posedge clk) + begin + `WRITE_VERBOSE(("[%0t] b <= 0\n", $time)); + flag_b <= 1'b0; + #2 + `WRITE_VERBOSE(("[%0t] a <= 1\n", $time)); + flag_a <= 1'b1; + #2 + `WRITE_VERBOSE(("[%0t] b <= 1\n", $time)); + flag_b <= 1'b1; + end + always @(flag_a) if ($time > 0) + begin + #1 + `WRITE_VERBOSE(("[%0t] Checking if b == 0\n", $time)); + if (flag_b !== 1'b0) $stop; + #2 + `WRITE_VERBOSE(("[%0t] Checking if b == 1\n", $time)); + if (flag_b !== 1'b1) $stop; + #10 + $write("*-* All Finished *-*\n"); + $finish; + end + initial #20 $stop; // timeout +endmodule diff --git a/test_regress/t/t_timing_class.pl b/test_regress/t/t_timing_class.pl new file mode 100755 index 000000000..c469d3de3 --- /dev/null +++ b/test_regress/t/t_timing_class.pl @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_class.v b/test_regress/t/t_timing_class.v new file mode 100644 index 000000000..4b8480ced --- /dev/null +++ b/test_regress/t/t_timing_class.v @@ -0,0 +1,166 @@ +// 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 + +`ifdef TEST_VERBOSE + `define WRITE_VERBOSE(args) $write args +`else + `define WRITE_VERBOSE(args) +`endif + +module t; + // ============================================= + // EVENTS + class EventClass; + event e; + + task sleep; /* @e; */ endtask // Unsupported + task wake; ->e; endtask + endclass + + EventClass ec = new; + int event_trig_count = 0; + + initial begin + @ec.e; + ec.sleep; + end + + initial #25 ec.wake; + initial #50 ->ec.e; + + always @ec.e begin + event_trig_count++; + `WRITE_VERBOSE(("Event in class triggered at time %0t!\n", $time)); + end + + // ============================================= + // DELAYS + virtual class DelayClass; + pure virtual task do_delay; + pure virtual task do_sth_else; + endclass + + `ifdef TEST_VERBOSE + `define DELAY_CLASS(dt) \ + class Delay``dt extends DelayClass; \ + virtual task do_delay; \ + $write("Starting a #%0d delay\n", dt); \ + #dt \ + $write("Ended a #%0d delay\n", dt); \ + endtask \ + virtual task do_sth_else; \ + $write("Task with no delay (in Delay%0d)\n", dt); \ + endtask \ + endclass + `else + `define DELAY_CLASS(dt) \ + class Delay``dt extends DelayClass; \ + virtual task do_delay; \ + #dt; \ + endtask \ + virtual task do_sth_else; \ + endtask \ + endclass + `endif + + `DELAY_CLASS(10); + `DELAY_CLASS(20); + `DELAY_CLASS(40); + + class NoDelay extends DelayClass; + virtual task do_delay; + `WRITE_VERBOSE(("Task with no delay\n")); + endtask + virtual task do_sth_else; + `WRITE_VERBOSE(("Task with no delay (in NoDelay)\n")); + endtask + endclass + + class AssignDelayClass; + logic x; + logic y; + task do_assign; + y = #10 x; + endtask + endclass + + initial begin + DelayClass dc; + Delay10 d10 = new; + Delay20 d20 = new; + Delay40 d40 = new; + NoDelay dNo = new; + AssignDelayClass dAsgn = new; + `WRITE_VERBOSE(("I'm at time %0t\n", $time)); + dc = d10; + dc.do_delay; + dc.do_sth_else; + `WRITE_VERBOSE(("I'm at time %0t\n", $time)); + if ($time != 10) $stop; + dc = d20; + dc.do_delay; + dc.do_sth_else; + `WRITE_VERBOSE(("I'm at time %0t\n", $time)); + if ($time != 30) $stop; + dc = d40; + dc.do_delay; + dc.do_sth_else; + `WRITE_VERBOSE(("I'm at time %0t\n", $time)); + if ($time != 70) $stop; + dc = dNo; + dc.do_delay; + dc.do_sth_else; + `WRITE_VERBOSE(("I'm at time %0t\n", $time)); + dAsgn.x = 1; + dAsgn.y = 0; + fork #5 dAsgn.x = 0; join_none + dAsgn.do_assign; + if ($time != 80) $stop; + if (event_trig_count != 2) $stop; + if (dAsgn.y != 1) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + + // ============================================= + // FORKS + class ForkDelayClass; + task do_delay; #40; endtask + endclass + + class ForkClass; + int done = 0; + task do_fork(); + ForkDelayClass d; + fork + begin + #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 + join + done++; + `WRITE_VERBOSE(("All forked processes ended at time %0t\n", $time)); + endtask + endclass + + initial begin + ForkClass fc = new; + fc.do_fork; + if (fc.done != 4 || $time != 70) $stop; + end + + initial #81 $stop; // timeout +endmodule diff --git a/test_regress/t/t_timing_class_unsup.out b/test_regress/t/t_timing_class_unsup.out new file mode 100644 index 000000000..0cb96600b --- /dev/null +++ b/test_regress/t/t_timing_class_unsup.out @@ -0,0 +1,6 @@ +%Error-UNSUPPORTED: t/t_timing_class_unsup.v:10:17: Unsupported: event controls in methods + : ... In instance $unit::EventClass + 10 | task sleep; @e; endtask + | ^ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_delay_func_bad.pl b/test_regress/t/t_timing_class_unsup.pl similarity index 82% rename from test_regress/t/t_delay_func_bad.pl rename to test_regress/t/t_timing_class_unsup.pl index 27159da5b..8ab3c0995 100755 --- a/test_regress/t/t_delay_func_bad.pl +++ b/test_regress/t/t_timing_class_unsup.pl @@ -2,7 +2,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } # DESCRIPTION: Verilator: Verilog Test driver/expect definition # -# Copyright 2019 by Wilson Snyder. This program is free software; you +# Copyright 2022 by Antmicro Ltd. This program is free software; you # can redistribute it and/or modify it under the terms of either the GNU # Lesser General Public License Version 3 or the Perl Artistic License # Version 2.0. @@ -11,6 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(linter => 1); lint( + verilator_flags2 => ["--timing"], fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_timing_class_unsup.v b/test_regress/t/t_timing_class_unsup.v new file mode 100644 index 000000000..01795aa00 --- /dev/null +++ b/test_regress/t/t_timing_class_unsup.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, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class EventClass; + event e; + + task sleep; @e; endtask + task wake; ->e; endtask +endclass diff --git a/test_regress/t/t_timing_clkgen1.pl b/test_regress/t/t_timing_clkgen1.pl index e1998178c..aa7288ef4 100755 --- a/test_regress/t/t_timing_clkgen1.pl +++ b/test_regress/t/t_timing_clkgen1.pl @@ -2,7 +2,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } # DESCRIPTION: Verilator: Verilog Test driver/expect definition # -# Copyright 2019 by Wilson Snyder. This program is free software; you +# Copyright 2022 by Antmicro Ltd. This program is free software; you # can redistribute it and/or modify it under the terms of either the GNU # Lesser General Public License Version 3 or the Perl Artistic License # Version 2.0. @@ -10,20 +10,19 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -$Self->{vlt_all} and unsupported("Verilator unsupported, clocking"); +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --main --timing -Wno-MINTYPMAXDLY"], + make_main => 0, + ); -compile( - #verilator_flags2 => ['--exe --build --main --timing'], # Unsupported - verilator_flags2 => ['--exe --build --main --bbox-unsup -Wno-STMTDLY -Wno-INITIALDLY'], - verilator_make_cmake => 0, - verilator_make_gmake => 0, - make_main => 0, - make_top => 1, - ); - -execute( - check_finished => 1, - ); + execute( + check_finished => 1, + ); +} ok(1); 1; diff --git a/test_regress/t/t_timing_clkgen2.pl b/test_regress/t/t_timing_clkgen2.pl new file mode 100755 index 000000000..f86c4b944 --- /dev/null +++ b/test_regress/t/t_timing_clkgen2.pl @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_clkgen2.v b/test_regress/t/t_timing_clkgen2.v new file mode 100644 index 000000000..c1ec90fb1 --- /dev/null +++ b/test_regress/t/t_timing_clkgen2.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, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +`ifdef TEST_VERBOSE + `define WRITE_VERBOSE(args) $write args +`else + `define WRITE_VERBOSE(args) +`endif + +module t; + logic clk = 0; + logic clk_inv; + int cnt1 = 0; + int cnt2 = 0; + + always #4 clk = ~clk; + always @(negedge clk) begin + cnt1++; + `WRITE_VERBOSE(("[%0t] NEG clk (%b)\n", $time, clk)); + end + always @(posedge clk) begin + cnt1++; + `WRITE_VERBOSE(("[%0t] POS clk (%b)\n", $time, clk)); + end + + assign #2 clk_inv = ~clk; + initial forever begin + @(posedge clk_inv) cnt2++; + `WRITE_VERBOSE(("[%0t] POS clk_inv (%b)\n", $time, clk_inv)); + @(negedge clk_inv) cnt2++; + `WRITE_VERBOSE(("[%0t] NEG clk_inv (%b)\n", $time, clk_inv)); + end + + initial #41 begin + if (cnt1 != 10 && cnt2 != 10) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_timing_clkgen3.pl b/test_regress/t/t_timing_clkgen3.pl new file mode 100755 index 000000000..f86c4b944 --- /dev/null +++ b/test_regress/t/t_timing_clkgen3.pl @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_clkgen3.v b/test_regress/t/t_timing_clkgen3.v new file mode 100644 index 000000000..28da638a3 --- /dev/null +++ b/test_regress/t/t_timing_clkgen3.v @@ -0,0 +1,46 @@ +// 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 + +`timescale 10ns / 1ns + +`ifdef TEST_VERBOSE + `define WRITE_VERBOSE(args) $write args +`else + `define WRITE_VERBOSE(args) +`endif + +module t; + logic clk = 0; + logic clk_copy; + int cyc = 0; + int cnt1 = 0; + int cnt2 = 0; + + initial forever #1 clk = ~clk; + + always @(negedge clk) begin + #0.75 cnt1++; + `WRITE_VERBOSE(("[%0t] NEG clk (%b)\n", $time, clk)); + end + + always @(posedge clk) begin + cyc <= cyc + 1; + #0.5 `WRITE_VERBOSE(("[%0t] POS clk (%b)\n", $time, clk)); + if (cyc == 5) begin + if (cnt1 != 4 && cnt2 != 9) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end + + assign clk_copy = clk; + always @(posedge clk_copy or negedge clk_copy) begin + #0.25 cnt2++; + `WRITE_VERBOSE(("[%0t] POS/NEG clk_copy (%b)\n", $time, clk_copy)); + end + + initial #100 $stop; // timeout +endmodule diff --git a/test_regress/t/t_timing_clkgen_sc.pl b/test_regress/t/t_timing_clkgen_sc.pl new file mode 100755 index 000000000..a5fe43850 --- /dev/null +++ b/test_regress/t/t_timing_clkgen_sc.pl @@ -0,0 +1,32 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +elsif (!$Self->have_sc) { + skip("No SystemC installed"); +} +else { + top_filename("t/t_timing_clkgen2.v"); + + compile( + verilator_flags2 => ["--sc --exe --timing --timescale 10ps/1ps"], + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_clkgen_unsup.out b/test_regress/t/t_timing_clkgen_unsup.out new file mode 100644 index 000000000..8ee56209f --- /dev/null +++ b/test_regress/t/t_timing_clkgen_unsup.out @@ -0,0 +1,6 @@ +%Warning-MINTYPMAXDLY: t/t_timing_clkgen1.v:9:13: Unsupported: minimum/typical/maximum delay expressions. Using the typical delay + 9 | #(8.0:5:3) clk = 1; + | ^ + ... For warning description see https://verilator.org/warn/MINTYPMAXDLY?v=latest + ... Use "/* verilator lint_off MINTYPMAXDLY */" and lint_on around source to disable this message. +%Error: Exiting due to diff --git a/test_regress/t/t_timing_clkgen_unsup.pl b/test_regress/t/t_timing_clkgen_unsup.pl new file mode 100755 index 000000000..b380d0484 --- /dev/null +++ b/test_regress/t/t_timing_clkgen_unsup.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +top_filename("t/t_timing_clkgen1.v"); + +lint( + verilator_flags2 => ["--timing"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_timing_cmake.pl b/test_regress/t/t_timing_cmake.pl new file mode 100755 index 000000000..acd0f0d36 --- /dev/null +++ b/test_regress/t/t_timing_cmake.pl @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} elsif (!$Self->have_cmake) { + skip("cmake is not installed"); +} else { + top_filename("t/t_timing_events.v"); + + compile( + verilator_flags2 => ["--timescale 10ns/1ns --main --timing"], + verilator_make_gmake => 0, + verilator_make_cmake => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_debug1.out b/test_regress/t/t_timing_debug1.out new file mode 100644 index 000000000..0ad01cbe5 --- /dev/null +++ b/test_regress/t/t_timing_debug1.out @@ -0,0 +1,1909 @@ +-V{t#,#}- Verilated::debug is on. Message prefix indicates {,}. +-V{t#,#}+ Vt_timing_debug1___024root___ctor_var_reset +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Initial +-V{t#,#}+ Vt_timing_debug1___024root___eval_static +-V{t#,#}+ Vt_timing_debug1___024root___eval_static__TOP +-V{t#,#}+ Vt_timing_debug1___024root___eval_initial +-V{t#,#}+ Vt_timing_debug1___024root___eval_initial__TOP__0 +-V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:18 +-V{t#,#}+ Vt_timing_debug1___024root___eval_initial__TOP__1 +-V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_initial__TOP__2 +-V{t#,#} Suspending process waiting for @(posedge t.clk2) at t/t_timing_sched.v:46 +-V{t#,#}+ Vt_timing_debug1___024root___eval_initial__TOP__3 +-V{t#,#}+ Vt_timing_debug1___024root___eval_settle +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__stl +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__stl +-V{t#,#} 'stl' region trigger index 0 is active: Internal 'stl' trigger - first iteration +-V{t#,#} 'stl' region trigger index 1 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#} 'stl' region trigger index 2 is active: @([hybrid] __VassignWtmp___t.clk2__0) +-V{t#,#} 'stl' region trigger index 3 is active: @([hybrid] t.c1) +-V{t#,#}+ Vt_timing_debug1___024root___eval_stl +-V{t#,#}+ Vt_timing_debug1___024root___stl_sequent__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___stl_sequent__TOP__1 +-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___stl_comb__TOP__2 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork___h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__stl +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__stl +-V{t#,#} No triggers active +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#} 'act' region trigger index 1 is active: @([hybrid] __VassignWtmp___t.clk2__0) +-V{t#,#} 'act' region trigger index 2 is active: @([hybrid] t.c1) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:18 +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Committing processes waiting for @(posedge t.clk2): +-V{t#,#} - Process waiting at t/t_timing_sched.v:46 +-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___act_sequent__TOP__1 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork___h########__0__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 +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 3: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 3: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Ready processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:18 +-V{t#,#} Ready processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming processes waiting for @(posedge t.clk1) +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:18 +-V{t#,#} Suspending process waiting for @(posedge t.clk2) at t/t_timing_sched.v:18 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__1 +-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 +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk2): +-V{t#,#} - Process waiting at t/t_timing_sched.v:18 +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___nba_sequent__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 6: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 7: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 7: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 9: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 9: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Ready processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming processes waiting for @(posedge t.clk1) +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__1 +-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 +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___nba_sequent__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 12: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 13: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 1 is active: @([hybrid] __VassignWtmp___t.clk2__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 5 is active: @(posedge t.clk2) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Ready processes waiting for @(posedge t.clk2): +-V{t#,#} - Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Ready processes waiting for @(posedge t.clk2): +-V{t#,#} - Process waiting at t/t_timing_sched.v:18 +-V{t#,#} Resuming processes waiting for @(posedge t.clk2) +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:18 +-V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:18 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__1 +-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 +-V{t#,#} 'act' region trigger index 2 is active: @([hybrid] t.c1) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:18 +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-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 +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 12: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 12: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 13: Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Suspending process waiting for @(posedge t.clk2) at t/t_timing_sched.v:46 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk2): +-V{t#,#} - Process waiting at t/t_timing_sched.v:46 +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 13: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 15: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 15: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Ready processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:18 +-V{t#,#} Ready processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming processes waiting for @(posedge t.clk1) +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:18 +-V{t#,#} Suspending process waiting for @(posedge t.clk2) at t/t_timing_sched.v:18 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__1 +-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 +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk2): +-V{t#,#} - Process waiting at t/t_timing_sched.v:18 +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___nba_sequent__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 18: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 19: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 19: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 21: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 21: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Ready processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming processes waiting for @(posedge t.clk1) +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__1 +-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 +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___nba_sequent__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 25: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 24: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 1 is active: @([hybrid] __VassignWtmp___t.clk2__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 24: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 25: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 25: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 27: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 27: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Ready processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming processes waiting for @(posedge t.clk1) +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__1 +-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 +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___nba_sequent__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 31: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 31: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#} 'act' region trigger index 1 is active: @([hybrid] __VassignWtmp___t.clk2__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___act_sequent__TOP__1 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork___h########__0__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) +-V{t#,#} 'act' region trigger index 5 is active: @(posedge t.clk2) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Ready processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming processes waiting for @(posedge t.clk1) +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Ready processes waiting for @(posedge t.clk2): +-V{t#,#} - Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Ready processes waiting for @(posedge t.clk2): +-V{t#,#} - Process waiting at t/t_timing_sched.v:18 +-V{t#,#} Resuming processes waiting for @(posedge t.clk2) +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:18 +-V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:18 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__1 +-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 +-V{t#,#} 'act' region trigger index 2 is active: @([hybrid] t.c1) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:18 +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-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 +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___nba_sequent__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 34: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 36: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Awaiting time 37: Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Suspending process waiting for @(posedge t.clk2) at t/t_timing_sched.v:46 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk2): +-V{t#,#} - Process waiting at t/t_timing_sched.v:46 +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 36: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 37: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 37: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 39: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 39: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Ready processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:18 +-V{t#,#} Ready processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming processes waiting for @(posedge t.clk1) +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:18 +-V{t#,#} Suspending process waiting for @(posedge t.clk2) at t/t_timing_sched.v:18 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__1 +-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 +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk2): +-V{t#,#} - Process waiting at t/t_timing_sched.v:18 +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___nba_sequent__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 42: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 43: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 43: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 45: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 45: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 1 is active: @([hybrid] __VassignWtmp___t.clk2__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 45: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Ready processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming processes waiting for @(posedge t.clk1) +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__1 +-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 +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___nba_sequent__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 48: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 49: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 49: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 51: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 51: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Ready processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming processes waiting for @(posedge t.clk1) +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__1 +-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 +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___nba_sequent__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 54: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 57: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 1 is active: @([hybrid] __VassignWtmp___t.clk2__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 5 is active: @(posedge t.clk2) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Ready processes waiting for @(posedge t.clk2): +-V{t#,#} - Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Ready processes waiting for @(posedge t.clk2): +-V{t#,#} - Process waiting at t/t_timing_sched.v:18 +-V{t#,#} Resuming processes waiting for @(posedge t.clk2) +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:18 +-V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:18 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__1 +-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 +-V{t#,#} 'act' region trigger index 2 is active: @([hybrid] t.c1) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:18 +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-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 +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 56: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 57: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Suspending process waiting for @(posedge t.clk2) at t/t_timing_sched.v:46 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk2): +-V{t#,#} - Process waiting at t/t_timing_sched.v:46 +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 57: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Ready processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Ready processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:18 +-V{t#,#} Resuming processes waiting for @(posedge t.clk1) +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:18 +-V{t#,#} Suspending process waiting for @(posedge t.clk2) at t/t_timing_sched.v:18 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__1 +-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 +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk2): +-V{t#,#} - Process waiting at t/t_timing_sched.v:18 +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___nba_sequent__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 60: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 61: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 61: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 63: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 63: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Ready processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming processes waiting for @(posedge t.clk1) +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__1 +-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 +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___nba_sequent__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 67: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#} 'act' region trigger index 1 is active: @([hybrid] __VassignWtmp___t.clk2__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___act_sequent__TOP__1 +-V{t#,#}+ Vt_timing_debug1___024root____Vfork___h########__0__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 67: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 69: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 69: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Ready processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming processes waiting for @(posedge t.clk1) +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__1 +-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 +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___nba_sequent__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 72: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 73: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 73: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 75: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 75: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 3 is active: @(posedge t.clk1) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Ready processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming processes waiting for @(posedge t.clk1) +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__1 +-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 +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___nba_sequent__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 79: Process waiting at t/t_timing_sched.v:17 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 1 is active: @([hybrid] __VassignWtmp___t.clk2__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 5 is active: @(posedge t.clk2) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Ready processes waiting for @(posedge t.clk2): +-V{t#,#} - Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Ready processes waiting for @(posedge t.clk2): +-V{t#,#} - Process waiting at t/t_timing_sched.v:18 +-V{t#,#} Resuming processes waiting for @(posedge t.clk2) +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:18 +-V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:18 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__1 +-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 +-V{t#,#} 'act' region trigger index 2 is active: @([hybrid] t.c1) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk1): +-V{t#,#} - Process waiting at t/t_timing_sched.v:18 +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-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 +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug1::eval_step +-V{t#,#}+ Vt_timing_debug1___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug1___024root___eval +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 4 is active: @([true] __VdlySched.awaitingCurrentTime()) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___timing_resume +-V{t#,#} Delayed processes: +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 79: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Awaiting time 88: Process waiting at t/t_timing_sched.v:13 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 +*-* All Finished *-* +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 +-V{t#,#} Suspending process waiting for @(posedge t.clk2) at t/t_timing_sched.v:46 +-V{t#,#}+ Vt_timing_debug1___024root___eval_act +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__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 0 is active: @([hybrid] __VassignWtmp___t.clk1__0) +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#} Committing processes waiting for @(posedge t.clk2): +-V{t#,#} - Process waiting at t/t_timing_sched.v:46 +-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___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_nba +-V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 +-V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug1___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug1___024root___timing_commit +-V{t#,#}+ Vt_timing_debug1___024root___eval_final diff --git a/test_regress/t/t_timing_debug1.pl b/test_regress/t/t_timing_debug1.pl new file mode 100755 index 000000000..0d4523725 --- /dev/null +++ b/test_regress/t/t_timing_debug1.pl @@ -0,0 +1,35 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt_all => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + top_filename("t/t_timing_sched.v"); + + compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + + execute( + all_run_flags => ["+verilator+debug"], + check_finished => 1, + ); + + if (!$Self->{vltmt}) { # vltmt output may vary between thread exec order + files_identical("$Self->{obj_dir}/vlt_sim.log", $Self->{golden_filename}, "logfile"); + } +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_debug2.out b/test_regress/t/t_timing_debug2.out new file mode 100644 index 000000000..a206663b2 --- /dev/null +++ b/test_regress/t/t_timing_debug2.out @@ -0,0 +1,616 @@ +-V{t#,#}- Verilated::debug is on. Message prefix indicates {,}. +-V{t#,#}+ Vt_timing_debug2___024root___ctor_var_reset +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}+ Initial +-V{t#,#}+ Vt_timing_debug2___024root___eval_static +-V{t#,#}+ Vt_timing_debug2___024root___eval_initial +-V{t#,#}+ Vt_timing_debug2___024root___eval_initial__TOP__0 +[0] fork..join process 4 +-V{t#,#}+ Vt_timing_debug2___024root____Vfork___h########__0__0 +-V{t#,#}+ Vt_timing_debug2___024root____Vfork___h########__0__1 +-V{t#,#}+ Vt_timing_debug2___024root____Vfork___h########__0__2 +-V{t#,#}+ Vt_timing_debug2___024root____Vfork___h########__0__3 +-V{t#,#} Awaiting join of fork at: t/t_timing_fork_join.v:13-V{t0,14}+ Vt_timing_debug2___024root___eval_initial__TOP__1 +-V{t#,#}+ Vt_timing_debug2___024root___eval_settle +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 0 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 2: Process waiting at t/t_timing_fork_join.v:15 +-V{t#,#} Awaiting time 8: Process waiting at t/t_timing_fork_join.v:16 +-V{t#,#} Awaiting time 4: Process waiting at t/t_timing_fork_join.v:17 +-V{t#,#} Awaiting time 16: Process waiting at t/t_timing_fork_join.v:19 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_fork_join.v:79 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:79 +[2] fork..join process 3 +-V{t#,#} Process forked at t/t_timing_fork_join.v:17 finished-V{t0,48}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-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#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 0 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 4: Process waiting at t/t_timing_fork_join.v:15 +-V{t#,#} Awaiting time 8: Process waiting at t/t_timing_fork_join.v:16 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_fork_join.v:17 +-V{t#,#} Awaiting time 16: Process waiting at t/t_timing_fork_join.v:19 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:19 +[4] fork..join process 2 +-V{t#,#} Process forked at t/t_timing_fork_join.v:16 finished-V{t0,75}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-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#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 0 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 8: Process waiting at t/t_timing_fork_join.v:15 +-V{t#,#} Awaiting time 16: Process waiting at t/t_timing_fork_join.v:16 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_fork_join.v:17 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:17 +[8] fork..join process 1 +-V{t#,#} Process forked at t/t_timing_fork_join.v:15 finished-V{t0,101}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-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#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 0 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 16: Process waiting at t/t_timing_fork_join.v:15 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_fork_join.v:16 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:16 +[16] fork in fork starts +[16] fork..join process 8 +-V{t#,#}+ Vt_timing_debug2___024root____Vfork___h########__0__0 +-V{t#,#}+ Vt_timing_debug2___024root____Vfork___h########__0__1 +-V{t#,#}+ Vt_timing_debug2___024root____Vfork___h########__0__2 +-V{t#,#} Awaiting join of fork at: t/t_timing_fork_join.v:21-V{t0,129}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-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#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 0 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_fork_join.v:15 +-V{t#,#} Awaiting time 24: Process waiting at t/t_timing_fork_join.v:22 +-V{t#,#} Awaiting time 32: Process waiting at t/t_timing_fork_join.v:23 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_fork_join.v:24 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:24 +[20] fork..join process 7 +-V{t#,#} Process forked at t/t_timing_fork_join.v:24 finished-V{t0,156}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-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#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 0 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 24: Process waiting at t/t_timing_fork_join.v:15 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_fork_join.v:22 +-V{t#,#} Awaiting time 32: Process waiting at t/t_timing_fork_join.v:23 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:23 +[24] fork..join process 6 +-V{t#,#} Process forked at t/t_timing_fork_join.v:23 finished-V{t0,182}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-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#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 0 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 32: Process waiting at t/t_timing_fork_join.v:15 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_fork_join.v:22 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:22 +[32] fork..join process 5 +-V{t#,#} Process forked at t/t_timing_fork_join.v:22 finished-V{t0,207} Resuming: Process waiting at (null):0 +[32] fork..join in fork ends +-V{t#,#} Process forked at t/t_timing_fork_join.v:19 finished-V{t0,209} Resuming: Process waiting at (null):0 +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-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#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 0 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 64: Process waiting at t/t_timing_fork_join.v:15 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_fork_join.v:30 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:30 +[64] main process +fork..join_any process 2 +-V{t#,#}+ Vt_timing_debug2___024root____Vfork___h########__0__0 +-V{t#,#} Suspending process waiting for @([event] t.e1) at t/t_timing_fork_join.v:33 +back in main process +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-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.e1): +-V{t#,#} - Process waiting at t/t_timing_fork_join.v:33 +-V{t#,#}+ Vt_timing_debug2___024root___eval_nba +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 0 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 65: Process waiting at t/t_timing_fork_join.v:15 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_fork_join.v:40 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:40 +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 1 is active: @([event] t.e1) +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Ready processes waiting for @([event] t.e1): +-V{t#,#} - Process waiting at t/t_timing_fork_join.v:33 +-V{t#,#} Resuming processes waiting for @([event] t.e1) +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:33 +fork..join_any process 1 +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 1 is active: @([event] t.e1) +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} No ready processes waiting for @([event] t.e1) +-V{t#,#} Resuming processes waiting for @([event] t.e1) +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-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#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 0 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 66: Process waiting at t/t_timing_fork_join.v:15 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_fork_join.v:41 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:41 +-V{t#,#}+ Vt_timing_debug2___024root____Vfork___h########__0__0 +-V{t#,#}+ Vt_timing_debug2___024root____Vfork___h########__0__1 +-V{t#,#} Suspending process waiting for @([event] t.e1) at t/t_timing_fork_join.v:44 +-V{t#,#} Awaiting join of fork at: t/t_timing_fork_join.v:41-V{t0,308}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-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.e1): +-V{t#,#} - Process waiting at t/t_timing_fork_join.v:44 +-V{t#,#}+ Vt_timing_debug2___024root___eval_nba +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 0 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 68: Process waiting at t/t_timing_fork_join.v:15 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_fork_join.v:42 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:42 +fork..join_any process 1 +-V{t#,#} Process forked at t/t_timing_fork_join.v:42 finished-V{t0,335} Resuming: Process waiting at (null):0 +back in main process +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-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#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 0 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 69: Process waiting at t/t_timing_fork_join.v:15 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_fork_join.v:50 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:50 +-V{t#,#} Suspending process waiting for @([event] t.e1) at t/t_timing_fork_join.v:51 +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 1 is active: @([event] t.e1) +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Ready processes waiting for @([event] t.e1): +-V{t#,#} - Process waiting at t/t_timing_fork_join.v:44 +-V{t#,#} Uncommitted processes waiting for @([event] t.e1): +-V{t#,#} - Process waiting at t/t_timing_fork_join.v:51 +-V{t#,#} Resuming processes waiting for @([event] t.e1) +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:44 +fork..join_any process 2 +-V{t#,#} Process forked at t/t_timing_fork_join.v:43 finished-V{t0,374} Committing processes waiting for @([event] t.e1): +-V{t#,#} - Process waiting at t/t_timing_fork_join.v:51 +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 1 is active: @([event] t.e1) +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Ready processes waiting for @([event] t.e1): +-V{t#,#} - Process waiting at t/t_timing_fork_join.v:51 +-V{t#,#} Resuming processes waiting for @([event] t.e1) +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:51 +-V{t#,#}+ Vt_timing_debug2___024root____Vfork___h########__0__0 +-V{t#,#}+ Vt_timing_debug2___024root____Vfork___h########__0__1 +-V{t#,#} Suspending process waiting for @([event] t.e2) at t/t_timing_fork_join.v:62 +-V{t#,#}+ Vt_timing_debug2___024root____Vfork___h########__0__2 +-V{t#,#} Suspending process waiting for @([event] t.e3) at t/t_timing_fork_join.v:68 +in main process +-V{t#,#} Suspending process waiting for @([event] t.e1) at t/t_timing_fork_join.v:75 +-V{t#,#} Committing processes waiting for @([event] t.e1): +-V{t#,#} - Process waiting at t/t_timing_fork_join.v:75 +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-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.e2): +-V{t#,#} - Process waiting at t/t_timing_fork_join.v:62 +-V{t#,#} Committing processes waiting for @([event] t.e3): +-V{t#,#} - Process waiting at t/t_timing_fork_join.v:68 +-V{t#,#}+ Vt_timing_debug2___024root___eval_nba +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 0 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_fork_join.v:15 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_fork_join.v:56 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:56 +fork..join_none process 1 +-V{t#,#} Suspending process waiting for @([event] t.e2) at t/t_timing_fork_join.v:58 +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 2 is active: @([event] t.e2) +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Ready processes waiting for @([event] t.e2): +-V{t#,#} - Process waiting at t/t_timing_fork_join.v:62 +-V{t#,#} Uncommitted processes waiting for @([event] t.e2): +-V{t#,#} - Process waiting at t/t_timing_fork_join.v:58 +-V{t#,#} Resuming processes waiting for @([event] t.e2) +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:62 +fork..join_none process 2 +-V{t#,#} Committing processes waiting for @([event] t.e2): +-V{t#,#} - Process waiting at t/t_timing_fork_join.v:58 +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-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#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 0 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 71: Process waiting at t/t_timing_fork_join.v:15 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_fork_join.v:63 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:63 +-V{t#,#} Suspending process waiting for @([event] t.e3) at t/t_timing_fork_join.v:64 +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 3 is active: @([event] t.e3) +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Ready processes waiting for @([event] t.e3): +-V{t#,#} - Process waiting at t/t_timing_fork_join.v:68 +-V{t#,#} Uncommitted processes waiting for @([event] t.e3): +-V{t#,#} - Process waiting at t/t_timing_fork_join.v:64 +-V{t#,#} Resuming processes waiting for @([event] t.e3) +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:68 +fork..join_none process 3 +-V{t#,#} Committing processes waiting for @([event] t.e3): +-V{t#,#} - Process waiting at t/t_timing_fork_join.v:64 +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-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#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 0 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 72: Process waiting at t/t_timing_fork_join.v:15 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_fork_join.v:69 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:69 +-V{t#,#} Suspending process waiting for @([event] t.e3) at t/t_timing_fork_join.v:70 +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 3 is active: @([event] t.e3) +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Ready processes waiting for @([event] t.e3): +-V{t#,#} - Process waiting at t/t_timing_fork_join.v:64 +-V{t#,#} Uncommitted processes waiting for @([event] t.e3): +-V{t#,#} - Process waiting at t/t_timing_fork_join.v:70 +-V{t#,#} Resuming processes waiting for @([event] t.e3) +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:64 +fork..join_none process 2 again +-V{t#,#} Committing processes waiting for @([event] t.e3): +-V{t#,#} - Process waiting at t/t_timing_fork_join.v:70 +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-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#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 0 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 73: Process waiting at t/t_timing_fork_join.v:15 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_fork_join.v:65 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:65 +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 2 is active: @([event] t.e2) +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Ready processes waiting for @([event] t.e2): +-V{t#,#} - Process waiting at t/t_timing_fork_join.v:58 +-V{t#,#} Resuming processes waiting for @([event] t.e2) +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:58 +fork..join_none process 1 again +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-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#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} No triggers active +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+++++TOP Evaluate Vt_timing_debug2::eval_step +-V{t#,#}+ Vt_timing_debug2___024root___eval_debug_assertions +-V{t#,#}+ Eval +-V{t#,#}+ Vt_timing_debug2___024root___eval +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 0 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 74: Process waiting at t/t_timing_fork_join.v:15 +-V{t#,#} Awaiting time 100: Process waiting at t/t_timing_fork_join.v:59 +-V{t#,#} Resuming delayed processes +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:59 +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 3 is active: @([event] t.e3) +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Ready processes waiting for @([event] t.e3): +-V{t#,#} - Process waiting at t/t_timing_fork_join.v:70 +-V{t#,#} Resuming processes waiting for @([event] t.e3) +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:70 +fork..join_none process 3 again +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act +-V{t#,#} 'act' region trigger index 1 is active: @([event] t.e1) +-V{t#,#}+ Vt_timing_debug2___024root___timing_commit +-V{t#,#}+ Vt_timing_debug2___024root___timing_resume +-V{t#,#} Ready processes waiting for @([event] t.e1): +-V{t#,#} - Process waiting at t/t_timing_fork_join.v:75 +-V{t#,#} Resuming processes waiting for @([event] t.e1) +-V{t#,#} Resuming: Process waiting at t/t_timing_fork_join.v:75 +*-* All Finished *-* +-V{t#,#}+ Vt_timing_debug2___024root___eval_act +-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act +-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#,#}+ 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_final diff --git a/test_regress/t/t_timing_debug2.pl b/test_regress/t/t_timing_debug2.pl new file mode 100755 index 000000000..c5b6b9286 --- /dev/null +++ b/test_regress/t/t_timing_debug2.pl @@ -0,0 +1,35 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt_all => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + top_filename("t/t_timing_fork_join.v"); + + compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + + execute( + all_run_flags => ["+verilator+debug"], + check_finished => 1, + ); + + if (!$Self->{vltmt}) { # vltmt output may vary between thread exec order + files_identical("$Self->{obj_dir}/vlt_sim.log", $Self->{golden_filename}, "logfile"); + } +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_delay_callstack.pl b/test_regress/t/t_timing_delay_callstack.pl new file mode 100755 index 000000000..f86c4b944 --- /dev/null +++ b/test_regress/t/t_timing_delay_callstack.pl @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_delay_callstack.v b/test_regress/t/t_timing_delay_callstack.v new file mode 100644 index 000000000..995f25d87 --- /dev/null +++ b/test_regress/t/t_timing_delay_callstack.v @@ -0,0 +1,61 @@ +// 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; + int counter = 0; + + // As Verilator doesn't support recursive calls, let's use macros to + // generate tasks for a deep call stack + `ifdef TEST_VERBOSE + `define DEEP_STACK_DELAY_END(i) \ + task delay``i; \ + counter++; \ + $write("[%0t] at depth %0d\n", $time, i); \ + counter++; \ + endtask + + `define DEEP_STACK_DELAY(i, j) \ + task delay``i; \ + $write("[%0t] entering depth %0d\n", $time, i); \ + #1 delay``j; \ + counter++; \ + #1 $write("[%0t] leaving depth %0d\n", $time, i); \ + counter++; \ + endtask + `else + `define DEEP_STACK_DELAY_END(i) \ + task delay``i; \ + counter += 2; \ + endtask + + `define DEEP_STACK_DELAY(i, j) \ + task delay``i; \ + #1 delay``j; \ + counter++; \ + #1; \ + counter++; \ + endtask + `endif + + `DEEP_STACK_DELAY_END(10); + `DEEP_STACK_DELAY(9, 10); + `DEEP_STACK_DELAY(8, 9); + `DEEP_STACK_DELAY(7, 8); + `DEEP_STACK_DELAY(6, 7); + `DEEP_STACK_DELAY(5, 6); + `DEEP_STACK_DELAY(4, 5); + `DEEP_STACK_DELAY(3, 4); + `DEEP_STACK_DELAY(2, 3); + `DEEP_STACK_DELAY(1, 2); + + initial begin + delay1; + if ($time != 9*2) $stop; + if (counter != 10*2) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_timing_events.pl b/test_regress/t/t_timing_events.pl new file mode 100755 index 000000000..c469d3de3 --- /dev/null +++ b/test_regress/t/t_timing_events.pl @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_events.v b/test_regress/t/t_timing_events.v new file mode 100644 index 000000000..583c66808 --- /dev/null +++ b/test_regress/t/t_timing_events.v @@ -0,0 +1,32 @@ +// 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; + event e1; + event e2; + event e3; + initial forever begin + #2 + ->e1; + #2 + ->e2; + #2 + ->e3; + end + initial begin + for (int i = 0; i < 10; i++) begin + @(e1, e2, e3) + if (!e1.triggered && !e2.triggered && !e3.triggered) $stop; +`ifdef TEST_VERBOSE + $write("got event %0d\n", i); +`endif + end + $write("*-* All Finished *-*\n"); + $finish; + end + + initial #21 $stop; // timeout +endmodule diff --git a/test_regress/t/t_timing_fork_comb.pl b/test_regress/t/t_timing_fork_comb.pl new file mode 100755 index 000000000..d96687ccb --- /dev/null +++ b/test_regress/t/t_timing_fork_comb.pl @@ -0,0 +1,36 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + # Should convert the first always into combo and detect cycle + compile( + fails => 1, + verilator_flags2 => ["--timing"], + expect => + '%Warning-UNOPTFLAT: t/t_timing_fork_comb.v:\d+:\d+: Signal unoptimizable: Circular combinational logic:' + ); + + compile( + verilator_flags2 => ["--exe --main --timing -Wno-UNOPTFLAT"], + make_main => 0, + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_fork_comb.v b/test_regress/t/t_timing_fork_comb.v new file mode 100644 index 000000000..9463698c5 --- /dev/null +++ b/test_regress/t/t_timing_fork_comb.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, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t; + logic clk = 0; + + assign #5 clk = ~clk; + + int a = 0; + always @(posedge clk) begin + a <= a + 1; +`ifdef TEST_VERBOSE + $display("a=%0d, b=%0d, c=%0d, d=%0d, e=%0d, f=%0d, v=%b", a, b, c, d, e, f, v); +`endif + end + + int b = 0, c = 0, d = 0, e = 0, f = 0; + always @a begin + b = a << 1; + fork + #10 d = b + c; + e = c + d; + #5 f = d + e; + join_none + c = a + b; + end + + logic[5:0] v; + always @a begin + v[0] = a[0]; + fork + begin + v[1] = a[1]; + #5 v[2] = a[2]; + end + #10 v[3] = a[3]; + join_none + v[4] = a[4]; + end + + initial #100 begin +`ifdef TEST_VERBOSE + $display("a=%0d, b=%0d, c=%0d, d=%0d, e=%0d, f=%0d, v=%b", a, b, c, d, e, f, v); +`endif + if (a != 10) $stop; + if (b != 20) $stop; + if (c != 30) $stop; + if (d != 50) $stop; + if (e != 75) $stop; + if (f != 125) $stop; + if (v != 'b001010) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_timing_fork_join.out b/test_regress/t/t_timing_fork_join.out new file mode 100644 index 000000000..46f216b1e --- /dev/null +++ b/test_regress/t/t_timing_fork_join.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.pl b/test_regress/t/t_timing_fork_join.pl new file mode 100755 index 000000000..4ab3c9652 --- /dev/null +++ b/test_regress/t/t_timing_fork_join.pl @@ -0,0 +1,29 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + + execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_fork_join.v b/test_regress/t/t_timing_fork_join.v new file mode 100644 index 000000000..fb5b6c60d --- /dev/null +++ b/test_regress/t/t_timing_fork_join.v @@ -0,0 +1,80 @@ +// 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; + event e1; + event e2; + event e3; + + initial begin + fork + begin /*empty*/ end + #8 $write("[%0t] fork..join process 1\n", $time); + #4 $write("[%0t] fork..join process 2\n", $time); + #2 $write("[%0t] fork..join process 3\n", $time); + $write("[%0t] fork..join process 4\n", $time); + begin : fork_in_fork #16 + $write("[%0t] fork in fork starts\n", $time); + fork + #16 $write("[%0t] fork..join process 5\n", $time); + #8 $write("[%0t] fork..join process 6\n", $time); + #4 $write("[%0t] fork..join process 7\n", $time); + $write("[%0t] fork..join process 8\n", $time); + join + $write("[%0t] fork..join in fork ends\n", $time); + end + join + #32 $write("[%0t] main process\n", $time); + fork + begin + @e1; + $write("fork..join_any process 1\n"); + ->e1; + end + $write("fork..join_any process 2\n"); + join_any + $write("back in main process\n"); + #1 ->e1; + #1 fork + #2 $write("fork..join_any process 1\n"); + begin + @e1; + $write("fork..join_any process 2\n"); + ->e1; + end + join_any + $write("back in main process\n"); + #1 ->e1; + @e1; + // Order of triggering: + // p1->e2 ==> p2->e3 ==> p3->e3 ==> p2->e2 ==> p1->e3 ==> p3->e1 + fork + begin + #1 $write("fork..join_none process 1\n"); + ->e2; + @e2 $write("fork..join_none process 1 again\n"); + #1 ->e3; + end + begin + @e2 $write("fork..join_none process 2\n"); + #1 ->e3; + @e3 $write("fork..join_none process 2 again\n"); + #1 ->e2; + end + begin + @e3 $write("fork..join_none process 3\n"); + #1 ->e3; + @e3 $write("fork..join_none process 3 again\n"); + ->e1; + end + join_none + $write("in main process\n"); + @e1; + $write("*-* All Finished *-*\n"); + $finish; + end + initial #100 $stop; // timeout +endmodule diff --git a/test_regress/t/t_timing_fork_many.pl b/test_regress/t/t_timing_fork_many.pl new file mode 100755 index 000000000..f86c4b944 --- /dev/null +++ b/test_regress/t/t_timing_fork_many.pl @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_fork_many.v b/test_regress/t/t_timing_fork_many.v new file mode 100644 index 000000000..555865436 --- /dev/null +++ b/test_regress/t/t_timing_fork_many.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, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t; + int counter = 0; + + // As Verilator doesn't support recursive calls, let's use macros to generate tasks + `define FORK2_END(i) \ + task fork2_``i; \ + #1 counter++; \ + endtask + + `define FORK2(i, j) \ + task fork2_``i; \ + fork \ + #1 fork2_``j; \ + #1 fork2_``j; \ + join \ + endtask + + `FORK2_END(0); + `FORK2(1, 0); + `FORK2(2, 1); + `FORK2(3, 2); + `FORK2(4, 3); + `FORK2(5, 4); + `FORK2(6, 5); + `FORK2(7, 6); + `FORK2(8, 7); + + initial begin + fork2_8; +`ifdef TEST_VERBOSE + $write("[%0t] process counter == %0d\n", $time, counter); +`endif + if (counter != 1 << 8) $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 new file mode 100644 index 000000000..39713d51f --- /dev/null +++ b/test_regress/t/t_timing_fork_unsup.out @@ -0,0 +1,34 @@ +%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 + 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 + 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 + 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.pl b/test_regress/t/t_timing_fork_unsup.pl new file mode 100755 index 000000000..8ab3c0995 --- /dev/null +++ b/test_regress/t/t_timing_fork_unsup.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 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + verilator_flags2 => ["--timing"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_timing_fork_unsup.v b/test_regress/t/t_timing_fork_unsup.v new file mode 100644 index 000000000..39c141452 --- /dev/null +++ b/test_regress/t/t_timing_fork_unsup.v @@ -0,0 +1,31 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t; + class C; + task f; + int x = 0; + fork + #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 + endclass + + initial begin + C o = new; + o.f; + end +endmodule diff --git a/test_regress/t/t_timing_func_bad.out b/test_regress/t/t_timing_func_bad.out new file mode 100644 index 000000000..8bf343ea8 --- /dev/null +++ b/test_regress/t/t_timing_func_bad.out @@ -0,0 +1,25 @@ +%Error: t/t_timing_func_bad.v:10:8: Delays are not legal in functions. Suggest use a task (IEEE 1800-2017 13.4.4) + : ... In instance t + 10 | #1 $stop; + | ^ +%Error: t/t_timing_func_bad.v:15:13: Timing controls are not legal in functions. Suggest use a task (IEEE 1800-2017 13.4.4) + : ... In instance t + 15 | f2 = #5 0; $stop; + | ^ +%Error: t/t_timing_func_bad.v:20:7: Event controls are not legal in functions. Suggest use a task (IEEE 1800-2017 13.4.4) + : ... In instance t + 20 | @e $stop; + | ^ +%Error: t/t_timing_func_bad.v:25:12: Timing controls are not legal in functions. Suggest use a task (IEEE 1800-2017 13.4.4) + : ... In instance t + 25 | f4 = @e 0; $stop; + | ^ +%Error: t/t_timing_func_bad.v:31:7: Wait statements are not legal in functions. Suggest use a task (IEEE 1800-2017 13.4.4) + : ... In instance t + 31 | wait(i == 0) $stop; + | ^~~~ +%Error: t/t_timing_func_bad.v:42:8: Delays are not legal in final blocks (IEEE 1800-2017 9.2.3) + : ... In instance t + 42 | #1; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_timing_func_bad.pl b/test_regress/t/t_timing_func_bad.pl new file mode 100755 index 000000000..0ee17366a --- /dev/null +++ b/test_regress/t/t_timing_func_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 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + verilator_flags2 => ['--no-timing'], + ); + +ok(1); +1; diff --git a/test_regress/t/t_timing_func_bad.v b/test_regress/t/t_timing_func_bad.v new file mode 100644 index 000000000..0e8f13b78 --- /dev/null +++ b/test_regress/t/t_timing_func_bad.v @@ -0,0 +1,46 @@ +// 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*/); + + function int f1; + #1 $stop; + f1 = 0; + endfunction + + function int f2; + f2 = #5 0; $stop; + endfunction + + event e; + function int f3; + @e $stop; + f3 = 0; + endfunction + + function int f4; + f4 = @e 0; $stop; + endfunction + + int i; + + function int f5; + wait(i == 0) $stop; + f5 = 0; + endfunction + + initial begin + i = f1(); + $write("*-* All Finished *-*\n"); + $finish; + end + + final begin + #1; + $stop; + end + +endmodule diff --git a/test_regress/t/t_timing_intra_assign.out b/test_regress/t/t_timing_intra_assign.out new file mode 100644 index 000000000..fc870d925 --- /dev/null +++ b/test_regress/t/t_timing_intra_assign.out @@ -0,0 +1,15 @@ +val[0]=0 val[1]=0 val[2]=0 +val[0]=1 val[1]=0 val[2]=0 +val[0]=2 val[1]=0 val[2]=15 +val[0]=3 val[1]=0 val[2]=15 +val[0]=4 val[1]=1 val[2]=14 +val[0]=5 val[1]=1 val[2]=14 +val[0]=6 val[1]=2 val[2]=13 +val[0]=7 val[1]=4 val[2]=11 +val[0]=8 val[1]=7 val[2]=8 +val[0]=9 val[1]=7 val[2]=8 +val[0]=10 val[1]=7 val[2]=8 +val[0]=11 val[1]=7 val[2]=8 +val[0]=12 val[1]=7 val[2]=8 +val[0]=13 val[1]=7 val[2]=8 +*-* All Finished *-* diff --git a/test_regress/t/t_timing_intra_assign.pl b/test_regress/t/t_timing_intra_assign.pl new file mode 100755 index 000000000..6852f73f7 --- /dev/null +++ b/test_regress/t/t_timing_intra_assign.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 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --main --timing -Wno-UNOPTFLAT"], + make_main => 0, + ); + + execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + + compile( + verilator_flags2 => ["--exe --main --timing -Wno-UNOPTFLAT -fno-localize"], + make_main => 0, + ); + + execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_intra_assign.v b/test_regress/t/t_timing_intra_assign.v new file mode 100644 index 000000000..35afe20a9 --- /dev/null +++ b/test_regress/t/t_timing_intra_assign.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, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t; + logic[3:0] val[3]; + logic[1:0] idx1 = 0; + logic[1:0] idx2 = 0; + logic[0:0] idx3 = 0; + event e; + + always @val[0] $write("val[0]=%0d val[1]=%0d val[2]=%0d\n", val[0], val[1], val[2]); + + assign #10 {val[1], val[2]} = {val[0], 4'hf-val[0]}; + + always #10 begin // always so we can use NBA + val[0] = 1; + #10 val[0] = 2; + fork #5 val[0] = 3; join_none + val[0] = #10 val[0] + 2; + val[idx1] <= #10 val[idx1] + 2; + fork begin #5 + val[0] = 5; + idx1 = 2; + idx2 = 3; + idx3 = 1; + #40 ->e; + end join_none + val[idx1][idx2[idx3+:2]] = #20 1; + @e val[0] = 8; + fork begin + #1 val[0] = 9; + #2 ->e; + end join_none + val[0] = @e val[0] + 2; + val[0] <= @e val[0] + 2; + fork begin + #1 val[0] = 11; + end join_none + #2 ->e; + idx1 = 0; + idx2 = 0; + idx3 = 0; + fork begin #2 + idx1 = 2; + idx2 = 3; + idx3 = 1; + end join_none + #1 val[idx1[idx3+:2]][idx2] <= @e 1; + #1 ->e; + #1 $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_timing_intra_assign_delay.out b/test_regress/t/t_timing_intra_assign_delay.out deleted file mode 100644 index f726ad4b4..000000000 --- a/test_regress/t/t_timing_intra_assign_delay.out +++ /dev/null @@ -1,31 +0,0 @@ -%Warning-ASSIGNDLY: t/t_timing_intra_assign_delay.v:12:11: Unsupported: Ignoring timing control on this assignment. - : ... In instance t - 12 | assign #10 val2 = val1; - | ^~ - ... For warning description see https://verilator.org/warn/ASSIGNDLY?v=latest - ... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message. -%Warning-STMTDLY: t/t_timing_intra_assign_delay.v:16:6: Unsupported: Ignoring delay on this delayed statement. - : ... In instance t - 16 | #10 val1 = 2; - | ^~ -%Error-UNSUPPORTED: t/t_timing_intra_assign_delay.v:17:5: Unsupported: fork statements - : ... In instance t - 17 | fork #5 val1 = 3; join_none - | ^~~~ -%Warning-ASSIGNDLY: t/t_timing_intra_assign_delay.v:18:13: Unsupported: Ignoring timing control on this assignment. - : ... In instance t - 18 | val1 = #10 val1 + 2; - | ^~ -%Warning-ASSIGNDLY: t/t_timing_intra_assign_delay.v:19:14: Unsupported: Ignoring timing control on this assignment. - : ... In instance t - 19 | val1 <= #10 val1 + 2; - | ^~ -%Error-UNSUPPORTED: t/t_timing_intra_assign_delay.v:20:5: Unsupported: fork statements - : ... In instance t - 20 | fork #5 val1 = 5; join_none - | ^~~~ -%Warning-STMTDLY: t/t_timing_intra_assign_delay.v:21:6: Unsupported: Ignoring delay on this delayed statement. - : ... In instance t - 21 | #20 $write("*-* All Finished *-*\n"); - | ^~ -%Error: Exiting due to diff --git a/test_regress/t/t_timing_intra_assign_delay.v b/test_regress/t/t_timing_intra_assign_delay.v deleted file mode 100644 index 4ddc2461d..000000000 --- a/test_regress/t/t_timing_intra_assign_delay.v +++ /dev/null @@ -1,24 +0,0 @@ -// 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; - int val1, val2; - - always @val1 $write("[%0t] val1=%0d val2=%0d\n", $time, val1, val2); - - assign #10 val2 = val1; - - initial begin - val1 = 1; - #10 val1 = 2; - fork #5 val1 = 3; join_none - val1 = #10 val1 + 2; - val1 <= #10 val1 + 2; - fork #5 val1 = 5; join_none - #20 $write("*-* All Finished *-*\n"); - $finish; - end -endmodule diff --git a/test_regress/t/t_timing_intra_assign_event.out b/test_regress/t/t_timing_intra_assign_event.out deleted file mode 100644 index 3fd9349f3..000000000 --- a/test_regress/t/t_timing_intra_assign_event.out +++ /dev/null @@ -1,32 +0,0 @@ -%Error-UNSUPPORTED: t/t_timing_intra_assign_event.v:15:5: Unsupported: event control statement in this location - : ... In instance t - : ... Suggest have one event control statement per procedure, at the top of the procedure - 15 | @e val = 2; - | ^ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_timing_intra_assign_event.v:16:5: Unsupported: fork statements - : ... In instance t - 16 | fork begin - | ^~~~ -%Warning-ASSIGNDLY: t/t_timing_intra_assign_event.v:21:11: Unsupported: Ignoring timing control on this assignment. - : ... In instance t - 21 | val = @e val + 2; - | ^ - ... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message. -%Warning-ASSIGNDLY: t/t_timing_intra_assign_event.v:22:12: Unsupported: Ignoring timing control on this assignment. - : ... In instance t - 22 | val <= @e val + 2; - | ^ -%Error-UNSUPPORTED: t/t_timing_intra_assign_event.v:23:5: Unsupported: fork statements - : ... In instance t - 23 | fork begin - | ^~~~ -%Warning-STMTDLY: t/t_timing_intra_assign_event.v:29:6: Unsupported: Ignoring delay on this delayed statement. - : ... In instance t - 29 | #1 $write("*-* All Finished *-*\n"); - | ^ -%Warning-STMTDLY: t/t_timing_intra_assign_event.v:33:12: Unsupported: Ignoring delay on this delayed statement. - : ... In instance t - 33 | initial #1 ->e; - | ^ -%Error: Exiting due to diff --git a/test_regress/t/t_timing_intra_assign_event.v b/test_regress/t/t_timing_intra_assign_event.v deleted file mode 100644 index d98da3a66..000000000 --- a/test_regress/t/t_timing_intra_assign_event.v +++ /dev/null @@ -1,34 +0,0 @@ -// 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; - int val; - event e; - - always @val $write("val=%0d\n", val); - - initial begin - val = 1; - @e val = 2; - fork begin - @e #1 val = 3; - ->e; - end join_none - ->e; - val = @e val + 2; - val <= @e val + 2; - fork begin - @e val = 5; - ->e; - end join_none - ->e; - ->e; - #1 $write("*-* All Finished *-*\n"); - $finish; - end - - initial #1 ->e; -endmodule diff --git a/test_regress/t/t_timing_long.pl b/test_regress/t/t_timing_long.pl index eb279f82e..3efef3dff 100755 --- a/test_regress/t/t_timing_long.pl +++ b/test_regress/t/t_timing_long.pl @@ -54,9 +54,22 @@ top_filename("$Self->{obj_dir}/t_timing_long.v"); gen($Self->{top_filename}); +if ($Self->have_coroutines) { + compile( + verilator_flags2 => ["--exe --build --main --timing"], + verilator_make_cmake => 0, + verilator_make_gmake => 0, + make_main => 0, + make_top => 1, + ); + + execute( + check_finished => 1, + ); +} + compile( - # verilator_flags2 => ["--exe --build --main --timing"], # Unsupported - verilator_flags2 => ["--exe --build --main -Wno-STMTDLY"], + verilator_flags2 => ["--exe --build --main --no-timing -Wno-STMTDLY"], verilator_make_cmake => 0, verilator_make_gmake => 0, make_main => 0, diff --git a/test_regress/t/t_timing_nba.pl b/test_regress/t/t_timing_nba.pl new file mode 100755 index 000000000..f86c4b944 --- /dev/null +++ b/test_regress/t/t_timing_nba.pl @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_nba.v b/test_regress/t/t_timing_nba.v new file mode 100644 index 000000000..9554a5ad3 --- /dev/null +++ b/test_regress/t/t_timing_nba.v @@ -0,0 +1,41 @@ +// 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; + integer cyc = 0; + + reg [7:0] a; + reg [127:0] b; + + always #1 begin + cyc <= cyc + 1; + if (cyc == 0) begin + a <= 8'hFF; + a[7] <= 1'b0; + end + else if (cyc == 1) begin +`ifdef TEST_VERBOSE + $write("a = %x\n", a); +`endif + if (a != 8'h7F) $stop; + end + else if (cyc == 2) begin + b <= 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + b[127] <= 1'b0; + end + else if (cyc == 3) begin +`ifdef TEST_VERBOSE + $write("b = %x\n", b); +`endif + if (b != 128'h7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) $stop; + end + else if (cyc > 3) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule diff --git a/test_regress/t/t_timing_net_delay.out b/test_regress/t/t_timing_net_delay.out deleted file mode 100644 index 116ccc0a0..000000000 --- a/test_regress/t/t_timing_net_delay.out +++ /dev/null @@ -1,11 +0,0 @@ -%Warning-ASSIGNDLY: t/t_timing_net_delay.v:13:15: Unsupported: Ignoring timing control on this assignment. - : ... In instance t - 13 | wire[3:0] #4 val1 = cyc; - | ^ - ... For warning description see https://verilator.org/warn/ASSIGNDLY?v=latest - ... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message. -%Warning-ASSIGNDLY: t/t_timing_net_delay.v:17:12: Unsupported: Ignoring timing control on this assignment. - : ... In instance t - 17 | assign #4 val2 = cyc; - | ^ -%Error: Exiting due to diff --git a/test_regress/t/t_timing_off.pl b/test_regress/t/t_timing_off.pl new file mode 100755 index 000000000..f86c4b944 --- /dev/null +++ b/test_regress/t/t_timing_off.pl @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_off.v b/test_regress/t/t_timing_off.v new file mode 100644 index 000000000..1f25a7670 --- /dev/null +++ b/test_regress/t/t_timing_off.v @@ -0,0 +1,39 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t; + event e1; + event e2; + + initial begin + int x; + // verilator timing_off + #1 + fork @e1; @e2; join; + @e1 + wait(x == 4) + x = #1 8; + // verilator timing_on + if (x != 8) $stop; + if ($time != 0) $stop; + // verilator timing_off + @e2; + // verilator timing_on + @e1; + if ((e1.triggered && e2.triggered) + || (!e1.triggered && !e2.triggered)) $stop; + if ($time != 2) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + + initial #2 ->e1; + // verilator timing_off + initial #2 ->e2; + // verilator timing_on + initial #3 $stop; // timeout + initial #1 @(e1, e2) #1 $stop; // timeout +endmodule diff --git a/test_regress/t/t_timing_pong.pl b/test_regress/t/t_timing_pong.pl new file mode 100755 index 000000000..f86c4b944 --- /dev/null +++ b/test_regress/t/t_timing_pong.pl @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_pong.v b/test_regress/t/t_timing_pong.v new file mode 100644 index 000000000..a9972a4a3 --- /dev/null +++ b/test_regress/t/t_timing_pong.v @@ -0,0 +1,35 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t; + event ping; + event pong; + + int cnt = 0; + + initial forever @ping begin +`ifdef TEST_VERBOSE + $write("ping\n"); +`endif + cnt++; + ->pong; + end + + initial forever @pong begin +`ifdef TEST_VERBOSE + $write("pong\n"); +`endif + if (cnt < 10) ->ping; + end + + initial #1 ->ping; + initial #2 + if (cnt == 10) begin + $write("*-* All Finished *-*\n"); + $finish; + end else $stop; + initial #3 $stop; // timeout +endmodule diff --git a/test_regress/t/t_timing_reentry.pl b/test_regress/t/t_timing_reentry.pl index dec83b460..f86c4b944 100755 --- a/test_regress/t/t_timing_reentry.pl +++ b/test_regress/t/t_timing_reentry.pl @@ -2,7 +2,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } # DESCRIPTION: Verilator: Verilog Test driver/expect definition # -# Copyright 2019 by Wilson Snyder. This program is free software; you +# Copyright 2022 by Antmicro Ltd. This program is free software; you # can redistribute it and/or modify it under the terms of either the GNU # Lesser General Public License Version 3 or the Perl Artistic License # Version 2.0. @@ -10,18 +10,19 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -compile( - #verilator_flags2 => ['--exe --build --main --timing'], # Unsupported - verilator_flags2 => ['--exe --build --main --bbox-unsup -Wno-STMTDLY -Wno-INITIALDLY'], - verilator_make_cmake => 0, - verilator_make_gmake => 0, - make_main => 0, - make_top => 1, - ); +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); -execute( - check_finished => 1, - ) if !$Self->{vlt_all}; + execute( + check_finished => 1, + ); +} ok(1); 1; diff --git a/test_regress/t/t_timing_sched.pl b/test_regress/t/t_timing_sched.pl new file mode 100755 index 000000000..f86c4b944 --- /dev/null +++ b/test_regress/t/t_timing_sched.pl @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_sched.v b/test_regress/t/t_timing_sched.v new file mode 100644 index 000000000..57fa10fcd --- /dev/null +++ b/test_regress/t/t_timing_sched.v @@ -0,0 +1,61 @@ +// 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; + logic clk1 = 0; + + assign #3 clk1 = ~clk1; + + logic clk2 = 0; + assign #11 clk2 = ~clk2; + + int a1 = 0; + int b1 = 0; + always @(posedge clk1) #4 a1 = a1 + 1; + always @(posedge clk1) @(posedge clk2) b1 = b1 + 1; + + int a2 = 0; + always_comb begin + a2 = a1 << 1; +`ifdef TEST_VERBOSE + $display("[%0t] a2 = %0d", $time, a2); +`endif + end + + int b2 = 0; + always_comb begin + b2 = b1 << 2; +`ifdef TEST_VERBOSE + $display("[%0t] b2 = %0d", $time, b2); +`endif + end + + // verilator lint_off UNOPTFLAT + int c1 = 0; + int c2 = 0; + always @(b2, c1) begin + c2 = c1 >> 3; + c1 = b2 << 3; + end + // verilator lint_on UNOPTFLAT + + always @(posedge clk1) if (a2 != a1 << 1) $stop; + always @(posedge clk2) #1 if (b2 != b1 << 2) $stop; + + initial #78 begin +`ifdef TEST_VERBOSE + $display("a1=%0d, b1=%0d, a2=%0d, b2=%0d, c1=%0d, c2=%0d", a1, b1, a2, b2, c1, c2); +`endif + if (a1 != 12) $stop; + if (b1 != 4) $stop; + if (a2 != a1 << 1) $stop; + if (b2 != b1 << 2) $stop; + if (c1 != b2 << 3) $stop; + if (c2 != c1 >> 3) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_timing_sched_if.pl b/test_regress/t/t_timing_sched_if.pl new file mode 100755 index 000000000..f86c4b944 --- /dev/null +++ b/test_regress/t/t_timing_sched_if.pl @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_sched_if.v b/test_regress/t/t_timing_sched_if.v new file mode 100644 index 000000000..faa84e266 --- /dev/null +++ b/test_regress/t/t_timing_sched_if.v @@ -0,0 +1,69 @@ +// 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; + logic clk1 = 0; + + assign #3 clk1 = ~clk1; + + logic clk2 = 0; + assign #11 clk2 = ~clk2; + + logic flag = 0; + int a1 = 0; + int b1 = 0; + int c1 = 0; + always @(posedge clk1) begin + if (flag) #4 a1 = a1 + 1; + else @(posedge clk2) b1 = b1 + 1; + c1 = c1 + 1; + flag = ~flag; + end + + int a2 = 0; + always_comb begin + a2 = a1 << 1; +`ifdef TEST_VERBOSE + $display("[%0t] a2 = %0d", $time, a2); +`endif + end + + int b2 = 0; + always_comb begin + b2 = b1 << 2; +`ifdef TEST_VERBOSE + $display("[%0t] b2 = %0d", $time, b2); +`endif + end + + int c2 = 0; + always_comb begin + c2 = c1 << 3; +`ifdef TEST_VERBOSE + $display("[%0t] c2 = %0d", $time, c2); +`endif + end + + always @(posedge clk1) begin + #1 if (c2 != c1 << 3) $stop; + #5 if (a2 != a1 << 1) $stop; + end + always @(posedge clk2) #1 if (b2 != b1 << 2) $stop; + + initial #78 begin +`ifdef TEST_VERBOSE + $display("a1=%0d, b1=%0d, c1=%0d, a2=%0d, b2=%0d, c2=%0d", a1, b1, c1, a2, b2, c2); +`endif + if (a1 != 3) $stop; + if (b1 != 4) $stop; + if (c1 != a1 + b1) $stop; + if (a2 != a1 << 1) $stop; + if (b2 != b1 << 2) $stop; + if (c2 != c1 << 3) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_timing_sched_nba.pl b/test_regress/t/t_timing_sched_nba.pl new file mode 100755 index 000000000..f86c4b944 --- /dev/null +++ b/test_regress/t/t_timing_sched_nba.pl @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_sched_nba.v b/test_regress/t/t_timing_sched_nba.v new file mode 100644 index 000000000..4106d755c --- /dev/null +++ b/test_regress/t/t_timing_sched_nba.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, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t; + logic clk1 = 0; + + assign #3 clk1 = ~clk1; + + logic clk2 = 0; + assign #11 clk2 = ~clk2; + + int a1 = 0; + int b1 = 0; + always @(posedge clk1) #4 a1 <= a1 + 1; + always @(posedge clk1) @(posedge clk2) b1 <= b1 + 1; + + int a2 = 0; + always_comb begin + a2 = a1 << 1; +`ifdef TEST_VERBOSE + $display("[%0t] a2 = %0d", $time, a2); +`endif + end + + int b2 = 0; + always_comb begin + b2 = b1 << 2; +`ifdef TEST_VERBOSE + $display("[%0t] b2 = %0d", $time, b2); +`endif + end + + always @(posedge clk1) #5 if (a2 != a1 << 1) $stop; + always @(posedge clk2) #1 if (b2 != b1 << 2) $stop; + + initial #78 begin +`ifdef TEST_VERBOSE + $display("a1=%0d, b1=%0d, a2=%0d, b2=%0d", a1, b1, a2, b2); +`endif + if (a1 != 12) $stop; + if (b1 != 4) $stop; + if (a2 != a1 << 1) $stop; + if (b2 != b1 << 2) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_timing_unset1.out b/test_regress/t/t_timing_unset1.out new file mode 100644 index 000000000..4f3b14171 --- /dev/null +++ b/test_regress/t/t_timing_unset1.out @@ -0,0 +1,34 @@ +%Error-NEEDTIMINGOPT: t/t_notiming.v:12:9: Use --timing or --no-timing to specify how delays should be handled + : ... In instance t + 12 | #1 + | ^ + ... For error description see https://verilator.org/warn/NEEDTIMINGOPT?v=latest +%Error-NEEDTIMINGOPT: t/t_notiming.v:13:8: Use --timing or --no-timing to specify how forks should be handled + : ... In instance t + 13 | fork @e; @e; join; + | ^~~~ +%Error-NEEDTIMINGOPT: t/t_notiming.v:14:8: Use --timing or --no-timing to specify how event controls should be handled + : ... In instance t + 14 | @e + | ^ +%Error-NEEDTIMINGOPT: t/t_notiming.v:15:8: Use --timing or --no-timing to specify how wait statements should be handled + : ... In instance t + 15 | wait(x == 4) + | ^~~~ +%Error-NEEDTIMINGOPT: t/t_notiming.v:16:13: Use --timing or --no-timing to specify how timing controls should be handled + : ... In instance t + 16 | x = #1 8; + | ^ +%Error-NEEDTIMINGOPT: t/t_notiming.v:19:8: Use --timing or --no-timing to specify how event controls should be handled + : ... In instance t + 19 | @e + | ^ +%Error-NEEDTIMINGOPT: t/t_notiming.v:26:13: Use --timing or --no-timing to specify how delays should be handled + : ... In instance t + 26 | initial #1 ->e; + | ^ +%Error-NEEDTIMINGOPT: t/t_notiming.v:27:13: Use --timing or --no-timing to specify how delays should be handled + : ... In instance t + 27 | initial #2 $stop; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_timing_intra_assign_delay.pl b/test_regress/t/t_timing_unset1.pl similarity index 87% rename from test_regress/t/t_timing_intra_assign_delay.pl rename to test_regress/t/t_timing_unset1.pl index d61820774..167a6cf70 100755 --- a/test_regress/t/t_timing_intra_assign_delay.pl +++ b/test_regress/t/t_timing_unset1.pl @@ -10,8 +10,10 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -lint( - verilator_flags2 => ['-Wall -Wno-DECLFILENAME'], +top_filename("t/t_notiming.v"); + +compile( + # --timing/--no-timing not specified fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_timing_unset2.out b/test_regress/t/t_timing_unset2.out new file mode 100644 index 000000000..7d8dd8304 --- /dev/null +++ b/test_regress/t/t_timing_unset2.out @@ -0,0 +1,26 @@ +%Error-NEEDTIMINGOPT: t/t_timing_off.v:25:8: Use --timing or --no-timing to specify how event controls should be handled + : ... In instance t + 25 | @e1; + | ^ + ... For error description see https://verilator.org/warn/NEEDTIMINGOPT?v=latest +%Error-NEEDTIMINGOPT: t/t_timing_off.v:33:13: Use --timing or --no-timing to specify how delays should be handled + : ... In instance t + 33 | initial #2 ->e1; + | ^ +%Error-NEEDTIMINGOPT: t/t_timing_off.v:37:13: Use --timing or --no-timing to specify how delays should be handled + : ... In instance t + 37 | initial #3 $stop; + | ^ +%Error-NEEDTIMINGOPT: t/t_timing_off.v:38:13: Use --timing or --no-timing to specify how delays should be handled + : ... In instance t + 38 | initial #1 @(e1, e2) #1 $stop; + | ^ +%Error-NEEDTIMINGOPT: t/t_timing_off.v:38:15: Use --timing or --no-timing to specify how event controls should be handled + : ... In instance t + 38 | initial #1 @(e1, e2) #1 $stop; + | ^ +%Error-NEEDTIMINGOPT: t/t_timing_off.v:38:26: Use --timing or --no-timing to specify how delays should be handled + : ... In instance t + 38 | initial #1 @(e1, e2) #1 $stop; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_timing_unset2.pl b/test_regress/t/t_timing_unset2.pl new file mode 100755 index 000000000..be9ccffa3 --- /dev/null +++ b/test_regress/t/t_timing_unset2.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +top_filename("t/t_timing_off.v"); + +compile( + # --timing/--no-timing not specified + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_timing_wait.pl b/test_regress/t/t_timing_wait.pl new file mode 100755 index 000000000..ecf974b24 --- /dev/null +++ b/test_regress/t/t_timing_wait.pl @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --main --timing -Wno-WAITCONST"], + make_main => 0, + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_wait.v b/test_regress/t/t_timing_wait.v new file mode 100644 index 000000000..abfda1c09 --- /dev/null +++ b/test_regress/t/t_timing_wait.v @@ -0,0 +1,55 @@ +// 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 + +`ifdef TEST_VERBOSE + `define WRITE_VERBOSE(msg) $write(msg) +`else + `define WRITE_VERBOSE(msg) +`endif + +module t; + int a = 0; + int b = 0; + int c = 0; + + initial begin + `WRITE_VERBOSE("start with a==0, b==0, c==0\n"); + #2 a = 1; `WRITE_VERBOSE("assign 1 to a\n"); + #1 a = 2; `WRITE_VERBOSE("assign 2 to a\n"); // a==2 + #1 a = 0; `WRITE_VERBOSE("assign 0 to a\n"); + #1 a = 2; `WRITE_VERBOSE("assign 2 to a\n"); // 1a + #1 c = 3; `WRITE_VERBOSE("assign 3 to c\n"); + #1 c = 4; `WRITE_VERBOSE("assign 4 to c\n"); // a+bc + b = 5; + end + + initial begin + #1 `WRITE_VERBOSE("waiting for a==2\n"); + wait(a == 2) if (a != 2) $stop; + `WRITE_VERBOSE("waiting for a<2\n"); + wait(a < 2) if (a >= 2) $stop; + `WRITE_VERBOSE("waiting for a==0\n"); + wait(a == 0) if (a != 0) $stop; + `WRITE_VERBOSE("waiting for 1 1 && a < 3) if (a <= 1 || a >= 3) $stop; + `WRITE_VERBOSE("waiting for b>a\n"); + wait(b > a) if (b <= a) $stop; + `WRITE_VERBOSE("waiting for a+b= c) $stop; + `WRITE_VERBOSE("waiting for ac\n"); + wait(a < b && b > c) if (a >= b || b <= c) $stop; + wait(0 < 1) $write("*-* All Finished *-*\n"); + $finish; + end + + initial wait(0) $stop; + initial wait(1 == 0) $stop; + + initial #11 $stop; // timeout +endmodule diff --git a/test_regress/t/t_timing_zerodly_unsup.out b/test_regress/t/t_timing_zerodly_unsup.out new file mode 100644 index 000000000..fc3a2f5b0 --- /dev/null +++ b/test_regress/t/t_timing_zerodly_unsup.out @@ -0,0 +1,5 @@ +%Error-ZERODLY: t/t_timing_zerodly_unsup.v:12:14: Unsupported: #0 delays do not schedule process resumption in the Inactive region + 12 | #0 if (v) $finish; + | ^ + ... For error description see https://verilator.org/warn/ZERODLY?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_timing_zerodly_unsup.pl b/test_regress/t/t_timing_zerodly_unsup.pl new file mode 100755 index 000000000..8ab3c0995 --- /dev/null +++ b/test_regress/t/t_timing_zerodly_unsup.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 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + verilator_flags2 => ["--timing"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_timing_zerodly_unsup.v b/test_regress/t/t_timing_zerodly_unsup.v new file mode 100644 index 000000000..7fba70252 --- /dev/null +++ b/test_regress/t/t_timing_zerodly_unsup.v @@ -0,0 +1,18 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t; + event e; + logic v = 0; + initial #1 begin + fork + #0 if (v) $finish; + else $stop; + join_none + ->e; + end + initial @e v = 1; +endmodule diff --git a/test_regress/t/t_verilated_all.pl b/test_regress/t/t_verilated_all.pl index 402f834d4..4cdd44194 100755 --- a/test_regress/t/t_verilated_all.pl +++ b/test_regress/t/t_verilated_all.pl @@ -18,6 +18,7 @@ compile( "--coverage-toggle --coverage-line --coverage-user", "--trace --vpi ", "--trace-threads 1", + $Self->have_coroutines ? "--timing" : "--no-timing -Wno-STMTDLY", "--prof-exec", "--prof-pgo", "$root/include/verilated_save.cpp"], threads => 2 @@ -56,6 +57,7 @@ foreach my $file (sort keys %hit) { && $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_verilated_all.v b/test_regress/t/t_verilated_all.v index 8edabe38a..2030b8ba8 100644 --- a/test_regress/t/t_verilated_all.v +++ b/test_regress/t/t_verilated_all.v @@ -17,7 +17,7 @@ module t (/*AUTOARG*/ cyc <= cyc + 1; if (cyc!=0) begin if (cyc==10) begin - $write("*-* All Finished *-*\n"); + #5 $write("*-* All Finished *-*\n"); $finish; end end diff --git a/test_regress/t/t_verilated_all_newest.pl b/test_regress/t/t_verilated_all_newest.pl index 221f84ad7..7ea15b92d 100755 --- a/test_regress/t/t_verilated_all_newest.pl +++ b/test_regress/t/t_verilated_all_newest.pl @@ -16,7 +16,8 @@ my $root = ".."; compile( # Can't use --coverage and --savable together, so cheat and compile inline - verilator_flags2 => ["--cc --coverage-toggle --coverage-line --coverage-user --trace --prof-exec --prof-pgo --vpi $root/include/verilated_save.cpp"], + verilator_flags2 => ["--cc --coverage-toggle --coverage-line --coverage-user --trace --prof-exec --prof-pgo --vpi $root/include/verilated_save.cpp", + $Self->have_coroutines ? "--timing" : "--no-timing -Wno-STMTDLY"], make_flags => 'DRIVER_STD=newest', ); diff --git a/test_regress/t/t_verilated_threaded.pl b/test_regress/t/t_verilated_threaded.pl index a11df1cfe..a012b4529 100755 --- a/test_regress/t/t_verilated_threaded.pl +++ b/test_regress/t/t_verilated_threaded.pl @@ -16,7 +16,8 @@ my $root = ".."; compile( # Can't use --coverage and --savable together, so cheat and compile inline - verilator_flags2 => ["--cc --coverage-toggle --coverage-line --coverage-user --trace --vpi $root/include/verilated_save.cpp"], + verilator_flags2 => ["--cc --coverage-toggle --coverage-line --coverage-user --trace --vpi $root/include/verilated_save.cpp", + $Self->have_coroutines ? "--timing" : "--no-timing -Wno-STMTDLY"], threads => 1 ); diff --git a/test_regress/t/t_vlt_timing.pl b/test_regress/t/t_vlt_timing.pl new file mode 100755 index 000000000..0b172f726 --- /dev/null +++ b/test_regress/t/t_vlt_timing.pl @@ -0,0 +1,30 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +top_filename("t/t_timing_off.v"); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --main --timing t/t_vlt_timing.vlt"], + make_main => 0, + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_vlt_timing.vlt b/test_regress/t/t_vlt_timing.vlt new file mode 100644 index 000000000..f5ed20a92 --- /dev/null +++ b/test_regress/t/t_vlt_timing.vlt @@ -0,0 +1,11 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +`verilator_config + +timing_on --file "t/t_timing_off.v" --lines 23 +timing_off -file "t/t_timing_off.v" -lines 26-34 +timing_on -file "t/t_timing_off.v" -lines 35-38 diff --git a/test_regress/t/t_wait.out b/test_regress/t/t_wait.out index 409170e8e..f60b978eb 100644 --- a/test_regress/t/t_wait.out +++ b/test_regress/t/t_wait.out @@ -1,14 +1,39 @@ -%Error-UNSUPPORTED: t/t_wait.v:12:7: Unsupported: wait statements +%Error-NOTIMING: t/t_wait.v:12:7: Wait statements require --timing + : ... In instance t 12 | wait (value == 1); | ^~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_wait.v:14:7: Unsupported: wait statements + ... For error description see https://verilator.org/warn/NOTIMING?v=latest +%Error-NOTIMING: t/t_wait.v:14:7: Wait statements require --timing + : ... In instance t 14 | wait (0); | ^~~~ -%Error-UNSUPPORTED: t/t_wait.v:17:7: Unsupported: wait statements +%Error-NOTIMING: t/t_wait.v:17:7: Wait statements require --timing + : ... In instance t 17 | wait (value == 2); | ^~~~ -%Error-UNSUPPORTED: t/t_wait.v:20:7: Unsupported: wait statements +%Error-NOTIMING: t/t_wait.v:20:7: Wait statements require --timing + : ... In instance t 20 | wait (value == 3) if (value != 3) $stop; | ^~~~ +%Warning-STMTDLY: t/t_wait.v:25:8: Ignoring delay on this statement due to --no-timing + : ... In instance t + 25 | #10; + | ^~ + ... Use "/* verilator lint_off STMTDLY */" and lint_on around source to disable this message. +%Warning-STMTDLY: t/t_wait.v:27:8: Ignoring delay on this statement due to --no-timing + : ... In instance t + 27 | #10; + | ^~ +%Warning-STMTDLY: t/t_wait.v:29:8: Ignoring delay on this statement due to --no-timing + : ... In instance t + 29 | #10; + | ^~ +%Warning-STMTDLY: t/t_wait.v:31:8: Ignoring delay on this statement due to --no-timing + : ... In instance t + 31 | #10; + | ^~ +%Warning-STMTDLY: t/t_wait.v:33:8: Ignoring delay on this statement due to --no-timing + : ... In instance t + 33 | #10; + | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_wait.pl b/test_regress/t/t_wait.pl index 89ffd046b..c586a8d47 100755 --- a/test_regress/t/t_wait.pl +++ b/test_regress/t/t_wait.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(linter => 1); lint( - verilator_flags2 => ['--lint-only'], + verilator_flags2 => ['--lint-only --no-timing'], fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_wait_timing.pl b/test_regress/t/t_wait_timing.pl new file mode 100755 index 000000000..8c852569f --- /dev/null +++ b/test_regress/t/t_wait_timing.pl @@ -0,0 +1,30 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Antmicro Ltd. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + top_filename("t/t_wait.v"); + + compile( + timing_loop => 1, + verilator_flags2 => ["--timing -Wno-WAITCONST"], + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/verilator-config.cmake.in b/verilator-config.cmake.in index 2125341b8..2210b3297 100644 --- a/verilator-config.cmake.in +++ b/verilator-config.cmake.in @@ -89,6 +89,12 @@ define_property(TARGET FULL_DOCS "Verilator multithread tracing enabled" ) +define_property(TARGET + PROPERTY VERILATOR_TIMING + BRIEF_DOCS "Verilator timing enabled" + FULL_DOCS "Verilator timing enabled" +) + define_property(TARGET PROPERTY VERILATOR_COVERAGE BRIEF_DOCS "Verilator coverage enabled" @@ -337,6 +343,11 @@ function(verilate TARGET) endif() target_compile_features(${TARGET} PRIVATE cxx_std_11) + + if (${VERILATE_PREFIX}_TIMING) + check_cxx_compiler_flag(-fcoroutines-ts COROUTINES_TS_FLAG) + target_compile_options(${TARGET} PRIVATE $,-fcoroutines-ts,-fcoroutines>) + endif() endfunction() function(_verilator_find_systemc)