From 39af5d020e6913dcb0d696c57bf80dab29241e30 Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Mon, 22 Aug 2022 14:26:32 +0200 Subject: [PATCH] Timing support (#3363) Adds timing support to Verilator. It makes it possible to use delays, event controls within processes (not just at the start), wait statements, and forks. Building a design with those constructs requires a compiler that supports C++20 coroutines (GCC 10, Clang 5). The basic idea is to have processes and tasks with delays/event controls implemented as C++20 coroutines. This allows us to suspend and resume them at any time. There are five main runtime classes responsible for managing suspended coroutines: * `VlCoroutineHandle`, a wrapper over C++20's `std::coroutine_handle` with move semantics and automatic cleanup. * `VlDelayScheduler`, for coroutines suspended by delays. It resumes them at a proper simulation time. * `VlTriggerScheduler`, for coroutines suspended by event controls. It resumes them if its corresponding trigger was set. * `VlForkSync`, used for syncing `fork..join` and `fork..join_any` blocks. * `VlCoroutine`, the return type of all verilated coroutines. It allows for suspending a stack of coroutines (normally, C++ coroutines are stackless). There is a new visitor in `V3Timing.cpp` which: * scales delays according to the timescale, * simplifies intra-assignment timing controls and net delays into regular timing controls and assignments, * simplifies wait statements into loops with event controls, * marks processes and tasks with timing controls in them as suspendable, * creates delay, trigger scheduler, and fork sync variables, * transforms timing controls and fork joins into C++ awaits There are new functions in `V3SchedTiming.cpp` (used by `V3Sched.cpp`) that integrate static scheduling with timing. This involves providing external domains for variables, so that the necessary combinational logic gets triggered after coroutine resumption, as well as statements that need to be injected into the design eval function to perform this resumption at the correct time. There is also a function that transforms forked processes into separate functions. See the comments in `verilated_timing.h`, `verilated_timing.cpp`, `V3Timing.cpp`, and `V3SchedTiming.cpp`, as well as the internals documentation for more details. Signed-off-by: Krzysztof Bieganski --- Changes | 2 + bin/verilator | 3 + ci/docker/buildenv/Dockerfile | 2 +- ci/docker/buildenv/README.rst | 2 +- ci/docker/run/Dockerfile | 2 +- configure.ac | 30 + docs/CONTRIBUTORS | 1 + docs/gen/ex_STMTDLY_msg.rst | 2 +- docs/guide/connecting.rst | 23 +- docs/guide/exe_verilator.rst | 33 + docs/guide/extensions.rst | 16 + docs/guide/languages.rst | 72 +- docs/guide/warnings.rst | 79 +- docs/internals.rst | 183 ++ include/verilated.mk.in | 8 + include/verilated_timing.cpp | 180 ++ include/verilated_timing.h | 354 +++ include/verilated_types.h | 4 + src/Makefile_obj.in | 2 + src/V3Active.cpp | 46 +- src/V3Ast.h | 84 +- src/V3AstNodes.cpp | 37 +- src/V3AstNodes.h | 80 +- src/V3Begin.cpp | 27 +- src/V3Cast.cpp | 3 +- src/V3Const.cpp | 6 +- src/V3Dead.cpp | 1 + src/V3Delayed.cpp | 135 +- src/V3EmitCFunc.cpp | 6 + src/V3EmitCFunc.h | 5 + src/V3EmitCHeaders.cpp | 1 + src/V3EmitCImp.cpp | 4 + src/V3EmitCMain.cpp | 7 +- src/V3EmitCMake.cpp | 5 + src/V3EmitCModel.cpp | 50 +- src/V3EmitMk.cpp | 5 + src/V3Error.h | 18 +- src/V3FileLine.h | 2 + src/V3Gate.cpp | 11 + src/V3Global.h | 3 + src/V3Hasher.cpp | 5 + src/V3InstrCount.cpp | 46 +- src/V3Life.cpp | 21 +- src/V3LinkInc.cpp | 19 + src/V3LinkJump.cpp | 11 - src/V3LinkParse.cpp | 4 +- src/V3Options.cpp | 10 + src/V3Options.h | 3 + src/V3Order.cpp | 16 +- src/V3Sched.cpp | 81 +- src/V3Sched.h | 36 + src/V3SchedReplicate.cpp | 4 + src/V3SchedTiming.cpp | 361 ++++ src/V3Split.cpp | 4 + src/V3Timing.cpp | 659 ++++++ src/V3Timing.h | 32 + src/V3Unknown.cpp | 22 +- src/V3Width.cpp | 111 +- src/Verilator.cpp | 9 + src/config_build.h.in | 1 + src/verilog.l | 4 + src/verilog.y | 129 +- test_regress/driver.pl | 81 +- test_regress/t/t_altera_lpm_counter.pl | 2 +- test_regress/t/t_delay.pl | 2 +- test_regress/t/t_delay.v | 2 + test_regress/t/t_delay_func_bad.out | 9 - test_regress/t/t_delay_func_bad.v | 27 - test_regress/t/t_delay_stmtdly_bad.out | 28 +- test_regress/t/t_delay_stmtdly_bad.pl | 2 +- test_regress/t/t_delay_timing.pl | 32 + test_regress/t/t_event_control.out | 12 + ...nt_control_unsup.pl => t_event_control.pl} | 5 +- ...vent_control_unsup.v => t_event_control.v} | 0 test_regress/t/t_event_control_timing.out | 3 + test_regress/t/t_event_control_timing.pl | 30 + test_regress/t/t_event_control_unsup.out | 12 - test_regress/t/t_fork.out | 6 +- test_regress/t/t_fork.pl | 1 + test_regress/t/t_fork_bbox.pl | 2 +- test_regress/t/t_fork_disable.out | 6 +- test_regress/t/t_fork_disable.pl | 2 +- test_regress/t/t_fork_label.pl | 4 +- test_regress/t/t_fork_label_timing.pl | 30 + test_regress/t/t_fork_timing.pl | 29 + test_regress/t/t_func_lib_sub.pl | 1 + test_regress/t/t_func_lib_sub_timing.pl | 25 + test_regress/t/t_func_rand.pl | 2 +- test_regress/t/t_gate_basic.pl | 1 + test_regress/t/t_gate_basic_timing.pl | 32 + test_regress/t/t_gate_delay_unsup.out | 12 +- test_regress/t/t_gate_delay_unsup.pl | 2 +- test_regress/t/t_gen_forif.pl | 1 + test_regress/t/t_gen_intdot.pl | 1 + test_regress/t/t_lib.pl | 2 + test_regress/t/t_lib_nolib.pl | 2 +- test_regress/t/t_lib_prot.pl | 2 + test_regress/t/t_lib_prot_clk_gated.pl | 2 + test_regress/t/t_lib_prot_shared.pl | 2 + test_regress/t/t_lint_stmtdly_bad.out | 2 +- test_regress/t/t_lint_stmtdly_bad.pl | 1 + test_regress/t/t_lint_wait_bad.out | 12 + test_regress/t/t_lint_wait_bad.pl | 22 + test_regress/t/t_math_signed5.pl | 1 + test_regress/t/t_math_signed5_timing.pl | 30 + test_regress/t/t_mem_slot.pl | 2 +- test_regress/t/t_mod_dollar$.pl | 2 +- test_regress/t/t_net_delay.out | 11 + ...g_intra_assign_event.pl => t_net_delay.pl} | 2 +- .../t/{t_timing_net_delay.v => t_net_delay.v} | 2 +- test_regress/t/t_net_delay_timing.pl | 30 + test_regress/t/t_net_delay_timing_sc.pl | 34 + test_regress/t/t_notiming.out | 33 + .../{t_timing_net_delay.pl => t_notiming.pl} | 4 +- test_regress/t/t_notiming.v | 28 + test_regress/t/t_notiming_off.out | 29 + test_regress/t/t_notiming_off.pl | 22 + test_regress/t/t_order.pl | 3 + test_regress/t/t_order_timing.pl | 32 + test_regress/t/t_package_ddecl.pl | 1 + test_regress/t/t_package_ddecl_timing.pl | 30 + test_regress/t/t_parse_delay.pl | 5 +- test_regress/t/t_parse_delay_timing.pl | 25 + test_regress/t/t_timing_always.pl | 28 + test_regress/t/t_timing_always.v | 43 + test_regress/t/t_timing_class.pl | 28 + test_regress/t/t_timing_class.v | 166 ++ test_regress/t/t_timing_class_unsup.out | 6 + ...ay_func_bad.pl => t_timing_class_unsup.pl} | 3 +- test_regress/t/t_timing_class_unsup.v | 12 + test_regress/t/t_timing_clkgen1.pl | 27 +- test_regress/t/t_timing_clkgen2.pl | 28 + test_regress/t/t_timing_clkgen2.v | 42 + test_regress/t/t_timing_clkgen3.pl | 28 + test_regress/t/t_timing_clkgen3.v | 46 + test_regress/t/t_timing_clkgen_sc.pl | 32 + test_regress/t/t_timing_clkgen_unsup.out | 6 + test_regress/t/t_timing_clkgen_unsup.pl | 22 + test_regress/t/t_timing_cmake.pl | 28 + test_regress/t/t_timing_debug1.out | 1909 +++++++++++++++++ test_regress/t/t_timing_debug1.pl | 35 + test_regress/t/t_timing_debug2.out | 616 ++++++ test_regress/t/t_timing_debug2.pl | 35 + test_regress/t/t_timing_delay_callstack.pl | 28 + test_regress/t/t_timing_delay_callstack.v | 61 + test_regress/t/t_timing_events.pl | 28 + test_regress/t/t_timing_events.v | 32 + test_regress/t/t_timing_fork_comb.pl | 36 + test_regress/t/t_timing_fork_comb.v | 58 + test_regress/t/t_timing_fork_join.out | 25 + test_regress/t/t_timing_fork_join.pl | 29 + test_regress/t/t_timing_fork_join.v | 80 + test_regress/t/t_timing_fork_many.pl | 28 + test_regress/t/t_timing_fork_many.v | 43 + test_regress/t/t_timing_fork_unsup.out | 34 + test_regress/t/t_timing_fork_unsup.pl | 20 + test_regress/t/t_timing_fork_unsup.v | 31 + test_regress/t/t_timing_func_bad.out | 25 + test_regress/t/t_timing_func_bad.pl | 20 + test_regress/t/t_timing_func_bad.v | 46 + test_regress/t/t_timing_intra_assign.out | 15 + test_regress/t/t_timing_intra_assign.pl | 40 + test_regress/t/t_timing_intra_assign.v | 56 + .../t/t_timing_intra_assign_delay.out | 31 - test_regress/t/t_timing_intra_assign_delay.v | 24 - .../t/t_timing_intra_assign_event.out | 32 - test_regress/t/t_timing_intra_assign_event.v | 34 - test_regress/t/t_timing_long.pl | 17 +- test_regress/t/t_timing_nba.pl | 28 + test_regress/t/t_timing_nba.v | 41 + test_regress/t/t_timing_net_delay.out | 11 - test_regress/t/t_timing_off.pl | 28 + test_regress/t/t_timing_off.v | 39 + test_regress/t/t_timing_pong.pl | 28 + test_regress/t/t_timing_pong.v | 35 + test_regress/t/t_timing_reentry.pl | 25 +- test_regress/t/t_timing_sched.pl | 28 + test_regress/t/t_timing_sched.v | 61 + test_regress/t/t_timing_sched_if.pl | 28 + test_regress/t/t_timing_sched_if.v | 69 + test_regress/t/t_timing_sched_nba.pl | 28 + test_regress/t/t_timing_sched_nba.v | 50 + test_regress/t/t_timing_unset1.out | 34 + ...tra_assign_delay.pl => t_timing_unset1.pl} | 6 +- test_regress/t/t_timing_unset2.out | 26 + test_regress/t/t_timing_unset2.pl | 22 + test_regress/t/t_timing_wait.pl | 28 + test_regress/t/t_timing_wait.v | 55 + test_regress/t/t_timing_zerodly_unsup.out | 5 + test_regress/t/t_timing_zerodly_unsup.pl | 20 + test_regress/t/t_timing_zerodly_unsup.v | 18 + test_regress/t/t_verilated_all.pl | 2 + test_regress/t/t_verilated_all.v | 2 +- test_regress/t/t_verilated_all_newest.pl | 3 +- test_regress/t/t_verilated_threaded.pl | 3 +- test_regress/t/t_vlt_timing.pl | 30 + test_regress/t/t_vlt_timing.vlt | 11 + test_regress/t/t_wait.out | 35 +- test_regress/t/t_wait.pl | 2 +- test_regress/t/t_wait_timing.pl | 30 + verilator-config.cmake.in | 11 + 201 files changed, 8216 insertions(+), 538 deletions(-) create mode 100644 include/verilated_timing.cpp create mode 100644 include/verilated_timing.h create mode 100644 src/V3SchedTiming.cpp create mode 100644 src/V3Timing.cpp create mode 100644 src/V3Timing.h delete mode 100644 test_regress/t/t_delay_func_bad.out delete mode 100644 test_regress/t/t_delay_func_bad.v create mode 100755 test_regress/t/t_delay_timing.pl create mode 100644 test_regress/t/t_event_control.out rename test_regress/t/{t_event_control_unsup.pl => t_event_control.pl} (90%) rename test_regress/t/{t_event_control_unsup.v => t_event_control.v} (100%) create mode 100644 test_regress/t/t_event_control_timing.out create mode 100755 test_regress/t/t_event_control_timing.pl delete mode 100644 test_regress/t/t_event_control_unsup.out create mode 100755 test_regress/t/t_fork_label_timing.pl create mode 100755 test_regress/t/t_fork_timing.pl create mode 100755 test_regress/t/t_func_lib_sub_timing.pl create mode 100755 test_regress/t/t_gate_basic_timing.pl create mode 100644 test_regress/t/t_lint_wait_bad.out create mode 100755 test_regress/t/t_lint_wait_bad.pl create mode 100755 test_regress/t/t_math_signed5_timing.pl create mode 100644 test_regress/t/t_net_delay.out rename test_regress/t/{t_timing_intra_assign_event.pl => t_net_delay.pl} (89%) rename test_regress/t/{t_timing_net_delay.v => t_net_delay.v} (91%) create mode 100755 test_regress/t/t_net_delay_timing.pl create mode 100755 test_regress/t/t_net_delay_timing_sc.pl create mode 100644 test_regress/t/t_notiming.out rename test_regress/t/{t_timing_net_delay.pl => t_notiming.pl} (90%) create mode 100644 test_regress/t/t_notiming.v create mode 100644 test_regress/t/t_notiming_off.out create mode 100755 test_regress/t/t_notiming_off.pl create mode 100755 test_regress/t/t_order_timing.pl create mode 100755 test_regress/t/t_package_ddecl_timing.pl create mode 100755 test_regress/t/t_parse_delay_timing.pl create mode 100755 test_regress/t/t_timing_always.pl create mode 100644 test_regress/t/t_timing_always.v create mode 100755 test_regress/t/t_timing_class.pl create mode 100644 test_regress/t/t_timing_class.v create mode 100644 test_regress/t/t_timing_class_unsup.out rename test_regress/t/{t_delay_func_bad.pl => t_timing_class_unsup.pl} (82%) create mode 100644 test_regress/t/t_timing_class_unsup.v create mode 100755 test_regress/t/t_timing_clkgen2.pl create mode 100644 test_regress/t/t_timing_clkgen2.v create mode 100755 test_regress/t/t_timing_clkgen3.pl create mode 100644 test_regress/t/t_timing_clkgen3.v create mode 100755 test_regress/t/t_timing_clkgen_sc.pl create mode 100644 test_regress/t/t_timing_clkgen_unsup.out create mode 100755 test_regress/t/t_timing_clkgen_unsup.pl create mode 100755 test_regress/t/t_timing_cmake.pl create mode 100644 test_regress/t/t_timing_debug1.out create mode 100755 test_regress/t/t_timing_debug1.pl create mode 100644 test_regress/t/t_timing_debug2.out create mode 100755 test_regress/t/t_timing_debug2.pl create mode 100755 test_regress/t/t_timing_delay_callstack.pl create mode 100644 test_regress/t/t_timing_delay_callstack.v create mode 100755 test_regress/t/t_timing_events.pl create mode 100644 test_regress/t/t_timing_events.v create mode 100755 test_regress/t/t_timing_fork_comb.pl create mode 100644 test_regress/t/t_timing_fork_comb.v create mode 100644 test_regress/t/t_timing_fork_join.out create mode 100755 test_regress/t/t_timing_fork_join.pl create mode 100644 test_regress/t/t_timing_fork_join.v create mode 100755 test_regress/t/t_timing_fork_many.pl create mode 100644 test_regress/t/t_timing_fork_many.v create mode 100644 test_regress/t/t_timing_fork_unsup.out create mode 100755 test_regress/t/t_timing_fork_unsup.pl create mode 100644 test_regress/t/t_timing_fork_unsup.v create mode 100644 test_regress/t/t_timing_func_bad.out create mode 100755 test_regress/t/t_timing_func_bad.pl create mode 100644 test_regress/t/t_timing_func_bad.v create mode 100644 test_regress/t/t_timing_intra_assign.out create mode 100755 test_regress/t/t_timing_intra_assign.pl create mode 100644 test_regress/t/t_timing_intra_assign.v delete mode 100644 test_regress/t/t_timing_intra_assign_delay.out delete mode 100644 test_regress/t/t_timing_intra_assign_delay.v delete mode 100644 test_regress/t/t_timing_intra_assign_event.out delete mode 100644 test_regress/t/t_timing_intra_assign_event.v create mode 100755 test_regress/t/t_timing_nba.pl create mode 100644 test_regress/t/t_timing_nba.v delete mode 100644 test_regress/t/t_timing_net_delay.out create mode 100755 test_regress/t/t_timing_off.pl create mode 100644 test_regress/t/t_timing_off.v create mode 100755 test_regress/t/t_timing_pong.pl create mode 100644 test_regress/t/t_timing_pong.v create mode 100755 test_regress/t/t_timing_sched.pl create mode 100644 test_regress/t/t_timing_sched.v create mode 100755 test_regress/t/t_timing_sched_if.pl create mode 100644 test_regress/t/t_timing_sched_if.v create mode 100755 test_regress/t/t_timing_sched_nba.pl create mode 100644 test_regress/t/t_timing_sched_nba.v create mode 100644 test_regress/t/t_timing_unset1.out rename test_regress/t/{t_timing_intra_assign_delay.pl => t_timing_unset1.pl} (87%) create mode 100644 test_regress/t/t_timing_unset2.out create mode 100755 test_regress/t/t_timing_unset2.pl create mode 100755 test_regress/t/t_timing_wait.pl create mode 100644 test_regress/t/t_timing_wait.v create mode 100644 test_regress/t/t_timing_zerodly_unsup.out create mode 100755 test_regress/t/t_timing_zerodly_unsup.pl create mode 100644 test_regress/t/t_timing_zerodly_unsup.v create mode 100755 test_regress/t/t_vlt_timing.pl create mode 100644 test_regress/t/t_vlt_timing.vlt create mode 100755 test_regress/t/t_wait_timing.pl 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)