diff --git a/include/verilated.cpp b/include/verilated.cpp index 4511b37af..3c966a811 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -164,7 +164,10 @@ void vl_finish(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE #ifndef VL_USER_STOP ///< Define this to override the vl_stop function void vl_stop(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE { // $stop or $fatal reporting; would break current API to add param as to which - if (Verilated::threadContextp()->gotFinish()) return; + if (Verilated::threadContextp()->gotFinish() + && !Verilated::threadContextp()->executingFinal()) { + return; + } const char* const msg = "Verilog $stop"; Verilated::threadContextp()->gotError(true); Verilated::threadContextp()->gotFinish(true); @@ -2831,6 +2834,14 @@ void VerilatedContext::gotFinish(bool flag) VL_MT_SAFE { const VerilatedLockGuard lock{m_mutex}; m_s.m_gotFinish = flag; } +bool VerilatedContext::executingFinal() const VL_MT_SAFE { + const VerilatedLockGuard lock{m_mutex}; + return m_ns.m_executingFinal; +} +void VerilatedContext::executingFinal(bool flag) VL_MT_SAFE { + const VerilatedLockGuard lock{m_mutex}; + m_ns.m_executingFinal = flag; +} void VerilatedContext::profExecStart(uint64_t flag) VL_MT_SAFE { const VerilatedLockGuard lock{m_mutex}; m_ns.m_profExecStart = flag; diff --git a/include/verilated.h b/include/verilated.h index 6369ccdaa..909956d82 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -408,6 +408,7 @@ protected: struct NonSerialized final { // Non-serialized information // These are reloaded from on command-line settings, so do not need to persist // Fast path + bool m_executingFinal = false; // Running generated final() code uint64_t m_profExecStart = 1; // +prof+exec+start time uint32_t m_profExecWindow = 2; // +prof+exec+window size // Slow path @@ -530,6 +531,10 @@ public: bool gotFinish() const VL_MT_SAFE { return m_s.m_gotFinish; } /// Set if got a $finish or $stop/error void gotFinish(bool flag) VL_MT_SAFE; + /// Check if generated final() code is executing + bool executingFinal() const VL_MT_SAFE; + /// Set if generated final() code is executing + void executingFinal(bool flag) VL_MT_SAFE; /// Return if quiet enabled bool quiet() const VL_MT_SAFE { return m_s.m_quiet; } /// Enable quiet (also prevents need for OS calls to get CPU time) diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp index 029f01941..340c0587a 100644 --- a/src/V3EmitCModel.cpp +++ b/src/V3EmitCModel.cpp @@ -489,7 +489,9 @@ class EmitCModel final : public EmitCFunc { "void " + topModNameProtected + "__" + protect("_eval_final") + selfDecl + ";\n"); // ::final puts("\nVL_ATTR_COLD void " + EmitCUtil::topClassName() + "::final() {\n"); + puts("contextp()->executingFinal(true);\n"); puts(/**/ topModNameProtected + "__" + protect("_eval_final") + "(&(vlSymsp->TOP));\n"); + puts("contextp()->executingFinal(false);\n"); puts("}\n"); putSectionDelimiter("Implementations of abstract methods from VerilatedModel\n"); diff --git a/test_regress/t/t_final_assert.out b/test_regress/t/t_final_assert.out new file mode 100755 index 000000000..5883b0a85 --- /dev/null +++ b/test_regress/t/t_final_assert.out @@ -0,0 +1,3 @@ +[10] %Error: t_final_assert.v:12: Assertion failed in top.tb: 'assert' failed. +%Error: t/t_final_assert.v:12: Verilog $stop +Aborting... diff --git a/test_regress/t/t_final_assert.py b/test_regress/t/t_final_assert.py new file mode 100755 index 000000000..0dbd253f9 --- /dev/null +++ b/test_regress/t/t_final_assert.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of either the GNU Lesser General Public License Version 3 +# or the Perl Artistic License Version 2.0. +# SPDX-FileCopyrightText: 2024 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile() + +test.execute(fails=True, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_final_assert.v b/test_regress/t/t_final_assert.v new file mode 100644 index 000000000..959be7141 --- /dev/null +++ b/test_regress/t/t_final_assert.v @@ -0,0 +1,14 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Antmicro +// SPDX-License-Identifier: CC0-1.0 + +module tb(); + initial begin + $finish(); + end + final begin + assert(1 == 0); + end +endmodule