parent
62f475709f
commit
a2fae5eb4b
|
|
@ -597,6 +597,7 @@ description of these arguments.
|
|||
+verilator+debugi+<value> Enable debugging at a level
|
||||
+verilator+error+limit+<value> Set error limit
|
||||
+verilator+help Show help
|
||||
+verilator+log+file+<filename> Log stdout and stderr output to filename
|
||||
+verilator+noassert Disable assert checking
|
||||
+verilator+prof+exec+file+<filename> Set execution profile filename
|
||||
+verilator+prof+exec+start+<value> Set execution profile starting point
|
||||
|
|
|
|||
|
|
@ -48,6 +48,11 @@ Options:
|
|||
|
||||
Display help and exit.
|
||||
|
||||
.. option:: +verilator+log+file+<filename>
|
||||
|
||||
Log all stdout and stderr to the specified output filename. If not specified
|
||||
the normal stdout/stderr streams are used.
|
||||
|
||||
.. option:: +verilator+noassert
|
||||
|
||||
Disable assert checking per runtime argument. This is the same as
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@
|
|||
#include <chrono>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <fcntl.h>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <list>
|
||||
|
|
@ -73,6 +74,9 @@
|
|||
// clang-format off
|
||||
#if defined(_WIN32) || defined(__MINGW32__)
|
||||
# include <direct.h> // mkdir
|
||||
# include <io.h> // open, read, write, close
|
||||
# define STDOUT_FILENO _fileno(stdout)
|
||||
# define STDERR_FILENO _fileno(stderr)
|
||||
#endif
|
||||
#ifdef __GLIBC__
|
||||
# include <cxxabi.h>
|
||||
|
|
@ -2158,7 +2162,13 @@ IData VL_SYSTEM_IW(int lhswords, const WDataInP lhsp) VL_MT_SAFE {
|
|||
return VL_SYSTEM_IN(lhs);
|
||||
}
|
||||
IData VL_SYSTEM_IN(const std::string& lhs) VL_MT_SAFE {
|
||||
VerilatedContext* ctxp = Verilated::threadContextp();
|
||||
const bool sending = ctxp->logOutputToFile();
|
||||
// system() command may echo and read so restore default stdout and stderr if sending
|
||||
if (sending) ctxp->logRestoreOutput();
|
||||
const int code = std::system(lhs.c_str()); // Yes, std::system() is threadsafe
|
||||
// Log to file again if we were sending
|
||||
if (sending) ctxp->logOutputToFile(true /* append */);
|
||||
return code >> 8; // Want exit status
|
||||
}
|
||||
|
||||
|
|
@ -2868,6 +2878,9 @@ VerilatedContext::VerilatedContext()
|
|||
m_ns.m_profExecFilename = "profile_exec.dat";
|
||||
m_ns.m_profVltFilename = "profile.vlt";
|
||||
m_ns.m_solverProgram = VlOs::getenvStr("VERILATOR_SOLVER", VL_SOLVER_DEFAULT);
|
||||
m_ns.m_logFD = -1;
|
||||
m_ns.m_stdoutFD = -1;
|
||||
m_ns.m_stderrFD = -1;
|
||||
m_fdps.resize(31);
|
||||
std::fill(m_fdps.begin(), m_fdps.end(), static_cast<FILE*>(nullptr));
|
||||
m_fdFreeMct.resize(30);
|
||||
|
|
@ -2879,6 +2892,7 @@ VerilatedContext::VerilatedContext()
|
|||
VerilatedContext::~VerilatedContext() {
|
||||
checkMagic(this);
|
||||
m_magic = 0x1; // Arbitrary but 0x1 is what Verilator src uses for a deleted pointer
|
||||
logRestoreOutput();
|
||||
}
|
||||
|
||||
void VerilatedContext::checkMagic(const VerilatedContext* contextp) {
|
||||
|
|
@ -2948,6 +2962,52 @@ std::string VerilatedContext::coverageFilename() const VL_MT_SAFE {
|
|||
const VerilatedLockGuard lock{m_mutex};
|
||||
return m_ns.m_coverageFilename;
|
||||
}
|
||||
void VerilatedContext::logFilename(const std::string& flag) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock{m_mutex};
|
||||
assert(m_ns.m_logFD == -1);
|
||||
m_ns.m_logFilename = flag;
|
||||
}
|
||||
std::string VerilatedContext::logFilename() const VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock{m_mutex};
|
||||
return m_ns.m_logFilename;
|
||||
}
|
||||
bool VerilatedContext::logOutputToFile() const VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock{m_mutex};
|
||||
return m_ns.m_logFD >= 0;
|
||||
}
|
||||
void VerilatedContext::logOutputToFile(bool append) VL_MT_SAFE {
|
||||
int log_fd = ::open(m_ns.m_logFilename.c_str(),
|
||||
O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), 0666);
|
||||
std::string error_msg;
|
||||
if (log_fd >= 0) {
|
||||
const VerilatedLockGuard lock{m_mutex};
|
||||
m_ns.m_logFD = log_fd;
|
||||
// See https://man7.org/linux/man-pages/man2/dup.2.html
|
||||
m_ns.m_stdoutFD = ::dup(STDOUT_FILENO); // Save original fd
|
||||
::dup2(m_ns.m_logFD, STDOUT_FILENO); // Replace STDOUT_FILENO with m_logFD
|
||||
m_ns.m_stderrFD = ::dup(STDERR_FILENO); // Save original fd
|
||||
::dup2(m_ns.m_logFD, STDERR_FILENO); // Replace STDERR_FILENO with m_logFD
|
||||
} else {
|
||||
const VerilatedLockGuard lock{m_mutex};
|
||||
m_ns.m_logFD = -1;
|
||||
const std::string op_str = append ? "appended" : "created";
|
||||
error_msg = "Logfile " + m_ns.m_logFilename + " cannot be " + op_str;
|
||||
}
|
||||
if (!error_msg.empty()) { VL_FATAL_MT("", 0, "", error_msg.c_str()); }
|
||||
}
|
||||
void VerilatedContext::logRestoreOutput() VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock{m_mutex};
|
||||
if (m_ns.m_logFD >= 0) {
|
||||
std::fflush(stdout); // Flush logfile
|
||||
std::fflush(stderr);
|
||||
::dup2(m_ns.m_stdoutFD, STDOUT_FILENO); // Restore STDOUT_FILENO with saved m_stdoutFD
|
||||
::dup2(m_ns.m_stderrFD, STDERR_FILENO); // Restore STDERR_FILENO with saved m_stderrFD
|
||||
::close(m_ns.m_logFD); // Close logfile
|
||||
m_ns.m_logFD = -1;
|
||||
m_ns.m_stdoutFD = -1;
|
||||
m_ns.m_stderrFD = -1;
|
||||
}
|
||||
}
|
||||
void VerilatedContext::dumpfile(const std::string& flag) VL_MT_SAFE_EXCLUDES(m_timeDumpMutex) {
|
||||
const VerilatedLockGuard lock{m_timeDumpMutex};
|
||||
m_dumpfile = flag;
|
||||
|
|
@ -3277,6 +3337,9 @@ void VerilatedContextImp::commandArgVl(const std::string& arg) {
|
|||
VL_PRINTF_MT("For help, please see 'verilator --help'\n");
|
||||
VL_FATAL_MT("COMMAND_LINE", 0, "",
|
||||
"Exiting due to command line argument (not an error)");
|
||||
} else if (commandArgVlString(arg, "+verilator+log+file+", str)) {
|
||||
logFilename(str);
|
||||
logOutputToFile(false /* append */);
|
||||
} else if (arg == "+verilator+noassert") {
|
||||
assertOn(false);
|
||||
} else if (commandArgVlUint64(arg, "+verilator+prof+exec+start+", u64)) {
|
||||
|
|
|
|||
|
|
@ -409,6 +409,7 @@ protected:
|
|||
uint32_t m_profExecWindow = 2; // +prof+exec+window size
|
||||
// Slow path
|
||||
std::string m_coverageFilename; // +coverage+file filename
|
||||
std::string m_logFilename; // +log+file filename
|
||||
std::string m_profExecFilename; // +prof+exec+file filename
|
||||
std::string m_profVltFilename; // +prof+vlt filename
|
||||
std::string m_solverLogFilename; // SMT solver log filename
|
||||
|
|
@ -417,6 +418,9 @@ protected:
|
|||
VlOs::DeltaCpuTime m_cpuTimeStart{false}; // CPU time, starts when create first model
|
||||
VlOs::DeltaWallTime m_wallTimeStart{false}; // Wall time, starts when create first model
|
||||
std::vector<traceBaseModelCb_t> m_traceBaseModelCbs; // Callbacks to traceRegisterModel
|
||||
int m_stdoutFD; // Duplicated stdout file descriptor
|
||||
int m_stderrFD; // Duplicated stderr file descriptor
|
||||
int m_logFD; // Log file descriptor
|
||||
} m_ns;
|
||||
|
||||
mutable VerilatedMutex m_argMutex; // Protect m_argVec, m_argVecLoaded
|
||||
|
|
@ -650,6 +654,13 @@ public:
|
|||
std::string coverageFilename() const VL_MT_SAFE;
|
||||
void coverageFilename(const std::string& flag) VL_MT_SAFE;
|
||||
|
||||
// Internal: logfile
|
||||
std::string logFilename() const VL_MT_SAFE;
|
||||
void logFilename(const std::string& flag) VL_MT_SAFE;
|
||||
bool logOutputToFile() const VL_MT_SAFE;
|
||||
void logOutputToFile(bool append) VL_MT_SAFE;
|
||||
void logRestoreOutput() VL_MT_SAFE;
|
||||
|
||||
// Internal: $dumpfile
|
||||
std::string dumpfile() const VL_MT_SAFE_EXCLUDES(m_timeDumpMutex);
|
||||
void dumpfile(const std::string& flag) VL_MT_SAFE_EXCLUDES(m_timeDumpMutex);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
Hello World!
|
||||
Hello 3rd rock!
|
||||
Hello Mars!
|
||||
Hello Pluto!
|
||||
- t/t_runflag_logfile.v:20: Verilog $finish
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#!/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('vlt')
|
||||
|
||||
test.compile()
|
||||
|
||||
logfile = test.obj_dir + "/logfile.log"
|
||||
|
||||
test.execute(all_run_flags=['+verilator+log+file+' + logfile])
|
||||
|
||||
test.files_identical(logfile, test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
// DESCRIPTION: Verilator: Verilog example module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
int stdout_fd = 32'h8000_0001;
|
||||
int stderr_fd = 32'h8000_0002;
|
||||
|
||||
module top;
|
||||
initial begin
|
||||
// display
|
||||
$display("Hello World!");
|
||||
$system("echo In a shell now");
|
||||
$display("Hello 3rd rock!");
|
||||
// fdisplay with stdout and stderr
|
||||
$fdisplay(stdout_fd, "Hello Mars!");
|
||||
$system("echo In another shell now");
|
||||
$fdisplay(stderr_fd, "Hello Pluto!");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
#!/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('vlt')
|
||||
|
||||
have_gdb = 'VERILATOR_GDB' in os.environ
|
||||
if not have_gdb:
|
||||
if 'VERILATOR_TEST_NO_GDB' in os.environ:
|
||||
test.skip("Skipping due to VERILATOR_TEST_NO_GDB")
|
||||
if not test.have_gdb:
|
||||
test.skip("No gdb installed")
|
||||
|
||||
test.compile()
|
||||
|
||||
logfile = test.obj_dir + "/logfile.log"
|
||||
|
||||
test.execute(all_run_flags=['+verilator+log+file+' + logfile])
|
||||
|
||||
# $display checks
|
||||
test.file_grep(logfile, r'Hello World!')
|
||||
test.file_grep(logfile, r'Hello 3rd rock!')
|
||||
|
||||
# $fdisplay checks
|
||||
test.file_grep(logfile, r'Hello Mars!')
|
||||
test.file_grep(logfile, r'Hello Pluto!')
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// DESCRIPTION: Verilator: Verilog example module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// See also https://verilator.org/guide/latest/examples.html"
|
||||
|
||||
// Found on Stackoverflow
|
||||
int stdout_fd = 32'h8000_0001;
|
||||
int stderr_fd = 32'h8000_0002;
|
||||
|
||||
module top;
|
||||
initial begin
|
||||
// display
|
||||
$display("Hello World!");
|
||||
$system("echo In a shell now");
|
||||
$display("Hello 3rd rock!");
|
||||
// fdisplay with stdout and stderr
|
||||
$fdisplay(stdout_fd, "Hello Mars!");
|
||||
$system("echo In another shell now");
|
||||
$fdisplay(stderr_fd, "Hello Pluto!");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
[0] %Error: t_runflag_logfile_error.v:11: Assertion failed in top.top: This is a generated error!
|
||||
%Error: t/t_runflag_logfile_error.v:11: Verilog $stop
|
||||
Aborting...
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#!/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('vlt')
|
||||
|
||||
test.compile()
|
||||
|
||||
logfile = test.obj_dir + "/logfile.log"
|
||||
|
||||
test.execute(all_run_flags=['+verilator+log+file+' + logfile], fails=True)
|
||||
|
||||
test.files_identical(logfile, test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
// DESCRIPTION: Verilator: Verilog example module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// See also https://verilator.org/guide/latest/examples.html"
|
||||
|
||||
module top;
|
||||
initial begin
|
||||
$error("This is a generated error!");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
%Error: Logfile obj_vlt/t_runflag_logfile_open_bad/logfile.log cannot be created
|
||||
Aborting...
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
#!/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 os
|
||||
import stat
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.compile()
|
||||
|
||||
logfile = test.obj_dir + "/logfile.log"
|
||||
capturefile = test.obj_dir + "/capture.log"
|
||||
|
||||
# Create the logfile
|
||||
with open(logfile, 'w', encoding='utf8') as f:
|
||||
f.write("Read-only logfile\n")
|
||||
# Change permission to read only so execute() fail when creating the logfile
|
||||
os.chmod(logfile, stat.S_IREAD)
|
||||
|
||||
log_flags = '+verilator+log+file+' + logfile
|
||||
test.execute(all_run_flags=[log_flags, ">", capturefile, "2>&1"], fails=True)
|
||||
|
||||
# Set read + write so test does not fail next time it is run
|
||||
os.chmod(logfile, stat.S_IREAD | stat.S_IWRITE)
|
||||
|
||||
test.files_identical(capturefile, test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// DESCRIPTION: Verilator: Verilog example module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module top;
|
||||
initial begin
|
||||
$display("We should not see this message");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
Loading…
Reference in New Issue