Fix `$finish` to immediately stop executing code from non-final blocks (#7213 partial) (#7390)

Signed-off-by: Artur Bieniek <abieniek@antmicro.com>
This commit is contained in:
Artur Bieniek 2026-04-09 17:34:27 +02:00 committed by GitHub
parent fb66174d80
commit afd75ed1b8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 90 additions and 6 deletions

View File

@ -58,6 +58,12 @@ void VlDelayScheduler::resume() {
#ifdef VL_DEBUG
VL_DEBUG_IF(dump(); VL_DBG_MSGF(" Resuming delayed processes\n"););
#endif
if (VL_UNLIKELY(m_context.gotFinish())) {
m_queue.clear();
m_zeroDelayed.clear();
m_zeroDelayesSwap.clear();
return;
}
bool resumed = false;
while (!m_queue.empty() && (m_queue.cbegin()->first == m_context.time())) {
@ -80,6 +86,11 @@ void VlDelayScheduler::resume() {
}
void VlDelayScheduler::resumeZeroDelay() {
if (VL_UNLIKELY(m_context.gotFinish())) {
m_zeroDelayed.clear();
m_zeroDelayesSwap.clear();
return;
}
m_zeroDelayesSwap.swap(m_zeroDelayed);
for (VlCoroutineHandle& handle : m_zeroDelayesSwap) handle.resume();
m_zeroDelayesSwap.clear();
@ -120,6 +131,12 @@ void VlTriggerScheduler::resume(const char* eventDescription) {
VL_DEBUG_IF(dump(eventDescription);
VL_DBG_MSGF(" Resuming processes waiting for %s\n", eventDescription););
#endif
if (VL_UNLIKELY(Verilated::threadContextp()->gotFinish())) {
m_toResume.clear();
m_fired.clear();
m_awaiting.clear();
return;
}
for (VlCoroutineHandle& coro : m_toResume) coro.resume();
m_toResume.clear();
}
@ -136,6 +153,11 @@ void VlTriggerScheduler::moveToResumeQueue(const char* eventDescription) {
});
}
#endif
if (VL_UNLIKELY(Verilated::threadContextp()->gotFinish())) {
m_toResume.clear();
m_fired.clear();
return;
}
std::swap(m_fired, m_toResume);
}
@ -151,6 +173,11 @@ void VlTriggerScheduler::ready(const char* eventDescription) {
});
}
#endif
if (VL_UNLIKELY(Verilated::threadContextp()->gotFinish())) {
m_fired.clear();
m_awaiting.clear();
return;
}
const size_t expectedSize = m_fired.size() + m_awaiting.size();
if (m_fired.capacity() < expectedSize) m_fired.reserve(expectedSize * 2);
m_fired.insert(m_fired.end(), std::make_move_iterator(m_awaiting.begin()),
@ -190,6 +217,14 @@ void VlTriggerScheduler::dump(const char* eventDescription) const {
// VlDynamicTriggerScheduler:: Methods
bool VlDynamicTriggerScheduler::evaluate() {
if (VL_UNLIKELY(Verilated::threadContextp()->gotFinish())) {
m_anyTriggered = false;
m_suspended.clear();
m_evaluated.clear();
m_triggered.clear();
m_post.clear();
return false;
}
m_anyTriggered = false;
VL_DEBUG_IF(dump(););
std::swap(m_suspended, m_evaluated);
@ -206,6 +241,10 @@ void VlDynamicTriggerScheduler::doPostUpdates() {
VL_DBG_MSGF(" - ");
susp.dump();
});
if (VL_UNLIKELY(Verilated::threadContextp()->gotFinish())) {
m_post.clear();
return;
}
for (auto& coro : m_post) coro.resume();
m_post.clear();
}
@ -217,6 +256,10 @@ void VlDynamicTriggerScheduler::resume() {
VL_DBG_MSGF(" - ");
susp.dump();
});
if (VL_UNLIKELY(Verilated::threadContextp()->gotFinish())) {
m_triggered.clear();
return;
}
for (auto& coro : m_triggered) coro.resume();
m_triggered.clear();
}

View File

@ -190,10 +190,11 @@ public:
bool empty() const { return m_queue.empty() && m_zeroDelayed.empty(); }
// Are there coroutines to resume at the current simulation time?
bool awaitingCurrentTime() const {
return (!m_queue.empty() && (m_queue.cbegin()->first <= m_context.time()));
return !m_context.gotFinish()
&& (!m_queue.empty() && (m_queue.cbegin()->first <= m_context.time()));
}
// Are there coroutines to resume in the inactive region after a #0 delay?
bool awaitingZeroDelay() const { return !m_zeroDelayed.empty(); }
bool awaitingZeroDelay() const { return !m_context.gotFinish() && !m_zeroDelayed.empty(); }
#ifdef VL_DEBUG
void dump() const;
#endif

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: 2026 Wilson Snyder
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('simulator')
test.compile(make_main=False, verilator_flags2=["--binary"])
test.execute()
test.passes()

View File

@ -0,0 +1,26 @@
// 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 t;
bit clk = 0;
int cyc = 0;
initial forever #1 clk = ~clk;
always @(posedge clk) begin
cyc = cyc + 1;
if (cyc >= 10) $finish;
end
always @(posedge clk) begin
fork
begin
while ($sampled(cyc) != 99) #1;
if (cyc >= 10) $stop;
end
join_none
end
endmodule

View File

@ -4159,8 +4159,6 @@
-V{t#,#}+ Vt_timing_debug1___024root___trigger_anySet__act
-V{t#,#}+ Vt_timing_debug1___024root___timing_resume
-V{t#,#} No process to resume waiting for @(posedge t.clk1)
-V{t#,#} Not triggered 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#,#} No process to resume waiting for @(posedge t.clk2)
-V{t#,#} Resuming processes waiting for @(posedge t.clk2)

View File

@ -1666,7 +1666,6 @@
-V{t#,#}+ Vt_timing_debug2_t__03a__03aClkClass::__VnoInFunc_flip
-V{t#,#}+ Vt_timing_debug2___024root___eval_phase__act
-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers_vec__act
-V{t#,#} No suspended processes waiting for dynamic trigger evaluation
-V{t#,#}+ Vt_timing_debug2___024root___timing_ready
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act
@ -1681,7 +1680,6 @@
-V{t#,#}+ Vt_timing_debug2___024root___trigger_clear__act
-V{t#,#}+ Vt_timing_debug2___024root___eval_phase__act
-V{t#,#}+ Vt_timing_debug2___024root___eval_triggers_vec__act
-V{t#,#} No suspended processes waiting for dynamic trigger evaluation
-V{t#,#}+ Vt_timing_debug2___024root___timing_ready
-V{t#,#}+ Vt_timing_debug2___024root___trigger_orInto__act_vec_vec
-V{t#,#}+ Vt_timing_debug2___024root___dump_triggers__act