Fix `final` asserts and $stop (#7249)

This commit is contained in:
Artur Bieniek 2026-03-12 18:09:54 +01:00 committed by GitHub
parent 4b53f5f978
commit c0d0180918
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 54 additions and 1 deletions

View File

@ -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;

View File

@ -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)

View File

@ -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");

View File

@ -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...

View File

@ -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()

View File

@ -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