From b50e8bb9c137fc834e0f93d6be58829f6e799c58 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 26 Dec 2025 12:59:35 -0500 Subject: [PATCH] Internals: Add '--debug-runtime-timeout' --- bin/verilator | 1 + src/V3EmitCMain.cpp | 19 ++++++++++++++++++ src/V3Options.cpp | 1 + src/V3Options.h | 2 ++ test_regress/t/t_flag_runtime_timeout_bad.out | 4 ++++ test_regress/t/t_flag_runtime_timeout_bad.py | 20 +++++++++++++++++++ test_regress/t/t_flag_runtime_timeout_bad.v | 14 +++++++++++++ 7 files changed, 61 insertions(+) create mode 100644 test_regress/t/t_flag_runtime_timeout_bad.out create mode 100755 test_regress/t/t_flag_runtime_timeout_bad.py create mode 100644 test_regress/t/t_flag_runtime_timeout_bad.v diff --git a/bin/verilator b/bin/verilator index 721356ea1..d2af58a88 100755 --- a/bin/verilator +++ b/bin/verilator @@ -42,6 +42,7 @@ if ($#ARGV < 0) { } # Insert debugging options up front +# (VERILATOR_TEST_FLAGS is not a documented nor official supported feature) push @ARGV, (split ' ', $ENV{VERILATOR_TEST_FLAGS} || ""); # We sneak a look at the flags so we can do some pre-environment checks diff --git a/src/V3EmitCMain.cpp b/src/V3EmitCMain.cpp index 2315d5c16..5ecec684a 100644 --- a/src/V3EmitCMain.cpp +++ b/src/V3EmitCMain.cpp @@ -56,9 +56,22 @@ private: puts("#include \"verilated.h\"\n"); puts("#include \"" + EmitCUtil::topClassName() + ".h\"\n"); + if (v3Global.opt.debugRuntimeTimeout()) { + puts("\n"); + puts("#include \n"); + } puts("\n//======================\n\n"); + if (v3Global.opt.debugRuntimeTimeout()) { + puts("void alarmHandler(int signum) {\n"); + puts(" VL_FATAL_MT(\"\", 0, \"\", \"Alarm signal received,"s + + " '--debug-runtime-timeout "s + + std::to_string(v3Global.opt.debugRuntimeTimeout()) + "' exceeded\\n\");\n"); + puts("}\n"); + puts("\n"); + } + puts("int main(int argc, char** argv, char**) {\n"); puts("// Setup context, defaults, and parse command line\n"); puts("Verilated::debug(0);\n"); @@ -68,6 +81,12 @@ private: puts("contextp->commandArgs(argc, argv);\n"); puts("\n"); + if (v3Global.opt.debugRuntimeTimeout()) { + puts("signal(SIGALRM, alarmHandler);\n"); + puts("alarm("s + std::to_string(v3Global.opt.debugRuntimeTimeout()) + ");\n"); + puts("\n"); + } + puts("// Construct the Verilated model, from Vtop.h generated from Verilating\n"); puts("const std::unique_ptr<" + EmitCUtil::topClassName() + "> topp{new " + EmitCUtil::topClassName() + "{contextp.get(), \"" + topName + "\"}};\n"); diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 5e3558321..111d0127b 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -1391,6 +1391,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, DECL_OPTION("-debug-partition", OnOff, &m_debugPartition).undocumented(); DECL_OPTION("-debug-preproc-passthru", OnOff, &m_debugPreprocPassthru).undocumented(); DECL_OPTION("-debug-protect", OnOff, &m_debugProtect).undocumented(); + DECL_OPTION("-debug-runtime-timeout", Set, &m_debugRuntimeTimeout).undocumented(); DECL_OPTION("-debug-self-test", OnOff, &m_debugSelfTest).undocumented(); DECL_OPTION("-debug-sigsegv", CbCall, throwSigsegv).undocumented(); // See also --debug-abort DECL_OPTION("-debug-stack-check", OnOff, &m_debugStackCheck).undocumented(); diff --git a/src/V3Options.h b/src/V3Options.h index 0c2960383..83869f5ba 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -246,6 +246,7 @@ private: bool m_debugProtect = false; // main switch: --debug-protect bool m_debugSelfTest = false; // main switch: --debug-self-test bool m_debugStackCheck = false; // main switch: --debug-stack-check + int m_debugRuntimeTimeout = 0; // main switch: --debug-runtime-timeout bool m_debugWidth = false; // main switch: --debug-width bool m_decoration = true; // main switch: --decoration bool m_decorationNodes = false; // main switch: --decoration=nodes @@ -525,6 +526,7 @@ public: bool debugPartition() const { return m_debugPartition; } bool debugPreprocPassthru() const VL_MT_SAFE { return m_debugPreprocPassthru; } bool debugProtect() const VL_MT_SAFE { return m_debugProtect; } + int debugRuntimeTimeout() const { return m_debugRuntimeTimeout; } bool debugSelfTest() const { return m_debugSelfTest; } bool debugStackCheck() const { return m_debugStackCheck; } bool debugWidth() const VL_PURE { return m_debugWidth; } diff --git a/test_regress/t/t_flag_runtime_timeout_bad.out b/test_regress/t/t_flag_runtime_timeout_bad.out new file mode 100644 index 000000000..2566e4d39 --- /dev/null +++ b/test_regress/t/t_flag_runtime_timeout_bad.out @@ -0,0 +1,4 @@ +Sleeping.... +%Error: Alarm signal received, '--debug-runtime-timeout 1' exceeded + +Aborting... diff --git a/test_regress/t/t_flag_runtime_timeout_bad.py b/test_regress/t/t_flag_runtime_timeout_bad.py new file mode 100755 index 000000000..9f223c3cd --- /dev/null +++ b/test_regress/t/t_flag_runtime_timeout_bad.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2025 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 + +import vltest_bootstrap + +test.scenarios('simulator') + +# TODO if make this general purpose, consider an e.g. VERILATOR_RUNTIME_FLAGS +# envvar so can set for test suites. Make sure runtime-debug prints such options. +test.compile(verilator_flags2=['--binary', '--debug-runtime-timeout 1']) + +test.execute(fails=True, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_flag_runtime_timeout_bad.v b/test_regress/t/t_flag_runtime_timeout_bad.v new file mode 100644 index 000000000..c996f9c8a --- /dev/null +++ b/test_regress/t/t_flag_runtime_timeout_bad.v @@ -0,0 +1,14 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + initial begin + $display("Sleeping...."); + $system("sleep 20"); + $display("%%Error: Sleep done (should have timed out)...."); + $stop; + end +endmodule