Support $stacktrace
This commit is contained in:
parent
96306b7630
commit
e8a1e4745c
|
|
@ -554,3 +554,14 @@ or "`ifdef`"'s may break other tools.
|
|||
|
||||
Re-enable waveform tracing for all future signals or instances that are
|
||||
declared.
|
||||
|
||||
.. option:: $stacktrace
|
||||
|
||||
Called as a task, orint a stack trace. Called as a function, return a
|
||||
string with a stack trace. This relies on the C++ system trace, which
|
||||
may give less meaningful results if the model was not compiled with
|
||||
debug symbols. Also the data represents the C++ stack, the
|
||||
SystemVerilog functions/tasks involved may be renamed and/or inlined
|
||||
before becoming the C++ functions that may be visible in the stack
|
||||
trace. This extension is experimental and may be removed without
|
||||
deprecation.
|
||||
|
|
|
|||
|
|
@ -67,6 +67,10 @@
|
|||
#if defined(_WIN32) || defined(__MINGW32__)
|
||||
# include <direct.h> // mkdir
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
# include <execinfo.h>
|
||||
# define _VL_HAVE_STACKTRACE
|
||||
#endif
|
||||
|
||||
#include "verilated_threads.h"
|
||||
// clang-format on
|
||||
|
|
@ -1623,6 +1627,33 @@ IData VL_FREAD_I(int width, int array_lsb, int array_size, void* memp, IData fpi
|
|||
return read_count;
|
||||
}
|
||||
|
||||
std::string VL_STACKTRACE_N() VL_MT_SAFE {
|
||||
static VerilatedMutex s_stackTraceMutex;
|
||||
const VerilatedLockGuard lock{s_stackTraceMutex};
|
||||
|
||||
constexpr int BT_BUF_SIZE = 100;
|
||||
void *buffer[BT_BUF_SIZE];
|
||||
int nptrs = 0;
|
||||
char ** strings = nullptr;
|
||||
|
||||
#ifdef _VL_HAVE_STACKTRACE
|
||||
nptrs = backtrace(buffer, BT_BUF_SIZE);
|
||||
strings = backtrace_symbols(buffer, nptrs);
|
||||
#endif
|
||||
|
||||
if (!strings) return "Unable to backtrace\n";
|
||||
|
||||
std::string out = "Backtrace:\n";
|
||||
for (int j = 0; j < nptrs; j++) out += std::string{strings[j]} + std::string{"\n"};
|
||||
free(strings);
|
||||
return out;
|
||||
}
|
||||
|
||||
void VL_STACKTRACE() VL_MT_SAFE {
|
||||
const std::string out = VL_STACKTRACE_N();
|
||||
VL_PRINTF("%s", out.c_str());
|
||||
}
|
||||
|
||||
IData VL_SYSTEM_IQ(QData lhs) VL_MT_SAFE {
|
||||
VlWide<VL_WQ_WORDS_E> lhsw;
|
||||
VL_SET_WQ(lhsw, lhs);
|
||||
|
|
|
|||
|
|
@ -138,6 +138,8 @@ extern void VL_SFORMAT_X(int obits, IData& destr, const char* formatp, ...);
|
|||
extern void VL_SFORMAT_X(int obits, QData& destr, const char* formatp, ...);
|
||||
extern void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...);
|
||||
|
||||
extern void VL_STACKTRACE() VL_MT_SAFE;
|
||||
extern std::string VL_STACKTRACE_N() VL_MT_SAFE;
|
||||
extern IData VL_SYSTEM_IW(int lhswords, WDataInP const lhsp);
|
||||
extern IData VL_SYSTEM_IQ(QData lhs);
|
||||
inline IData VL_SYSTEM_II(IData lhs) VL_MT_SAFE { return VL_SYSTEM_IQ(lhs); }
|
||||
|
|
|
|||
|
|
@ -1525,6 +1525,25 @@ public:
|
|||
int instrCount() const override { return widthInstrs(); }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstStackTraceF final : public AstNodeExpr {
|
||||
// $stacktrace used as function
|
||||
public:
|
||||
AstStackTraceF(FileLine* fl)
|
||||
: ASTGEN_SUPER_StackTraceF(fl) {
|
||||
dtypeSetString();
|
||||
}
|
||||
ASTGEN_MEMBERS_AstStackTraceF;
|
||||
string verilogKwd() const override { return "$stacktrace"; }
|
||||
string emitVerilog() override { return verilogKwd(); }
|
||||
string emitC() override { return "VL_STACKTRACE_N()"; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstSysIgnore final : public AstNodeExpr {
|
||||
// @astgen op1 := exprsp : List[AstNode] // Expressions to output (???)
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -3092,6 +3092,20 @@ public:
|
|||
int instrCount() const override { return INSTR_COUNT_PLI; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstStackTraceT final : public AstNodeStmt {
|
||||
// $stacktrace used as task
|
||||
public:
|
||||
AstStackTraceT(FileLine* fl)
|
||||
: ASTGEN_SUPER_StackTraceT(fl) { }
|
||||
ASTGEN_MEMBERS_AstStackTraceT;
|
||||
string verilogKwd() const override { return "$stacktrace"; }
|
||||
bool isGateOptimizable() const override { return false; }
|
||||
bool isPredictOptimizable() const override { return false; }
|
||||
bool isPure() const override { return false; }
|
||||
bool isOutputter() const override { return true; }
|
||||
bool isUnlikely() const override { return true; }
|
||||
bool same(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstStmtExpr final : public AstNodeStmt {
|
||||
// Expression in statement position
|
||||
// @astgen op1 := exprp : AstNodeExpr
|
||||
|
|
|
|||
|
|
@ -775,6 +775,12 @@ public:
|
|||
iterateAndNextNull(nodep->lhsp());
|
||||
if (!nodep->lhsp()->isWide()) puts(";");
|
||||
}
|
||||
void visit(AstStackTraceF* nodep) override {
|
||||
puts("VL_STACKTRACE_N()");
|
||||
}
|
||||
void visit(AstStackTraceT* nodep) override {
|
||||
puts("VL_STACKTRACE();\n");
|
||||
}
|
||||
void visit(AstSystemT* nodep) override {
|
||||
puts("(void)VL_SYSTEM_I");
|
||||
emitIQW(nodep->lhsp());
|
||||
|
|
|
|||
|
|
@ -4676,6 +4676,9 @@ private:
|
|||
userIterateAndNext(nodep->exprsp(), WidthVP(SELF, BOTH).p());
|
||||
}
|
||||
}
|
||||
void visit(AstStackTraceF* nodep) override {
|
||||
nodep->dtypeSetString();
|
||||
}
|
||||
void visit(AstSysIgnore* nodep) override {
|
||||
userIterateAndNext(nodep->exprsp(), WidthVP(SELF, BOTH).p());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -265,6 +265,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
|||
"$skew" { FL; return yaTIMINGSPEC; }
|
||||
"$sqrt" { FL; return yD_SQRT; }
|
||||
"$sscanf" { FL; return yD_SSCANF; }
|
||||
"$stacktrace" { FL; return yD_STACKTRACE; }
|
||||
"$stime" { FL; return yD_STIME; }
|
||||
"$stop" { FL; return yD_STOP; }
|
||||
"$strobe" { FL; return yD_STROBE; }
|
||||
|
|
|
|||
|
|
@ -860,6 +860,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
|
|||
%token<fl> yD_SQRT "$sqrt"
|
||||
%token<fl> yD_SSCANF "$sscanf"
|
||||
%token<fl> yD_STABLE "$stable"
|
||||
%token<fl> yD_STACKTRACE "$stacktrace"
|
||||
%token<fl> yD_STIME "$stime"
|
||||
%token<fl> yD_STOP "$stop"
|
||||
%token<fl> yD_STROBE "$strobe"
|
||||
|
|
@ -3788,6 +3789,7 @@ system_t_call<nodep>: // IEEE: system_tf_call (as task)
|
|||
| yD_DUMPON '(' expr ')' { $$ = new AstDumpCtl($<fl>1, VDumpCtlType::ON); DEL($3); }
|
||||
//
|
||||
| yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? nullptr : new AstUCStmt($1,$3)); }
|
||||
| yD_STACKTRACE parenE { $$ = new AstStackTraceT{$1}; }
|
||||
| yD_SYSTEM '(' expr ')' { $$ = new AstSystemT($1, $3); }
|
||||
//
|
||||
| yD_EXIT parenE { $$ = new AstFinish($1); }
|
||||
|
|
@ -3897,6 +3899,7 @@ system_f_call<nodeExprp>: // IEEE: system_tf_call (as func)
|
|||
//
|
||||
| yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? nullptr : new AstUCFunc($1,$3)); }
|
||||
| yD_CAST '(' expr ',' expr ')' { $$ = new AstCastDynamic($1, $5, $3); }
|
||||
| yD_STACKTRACE parenE { $$ = new AstStackTraceF{$1}; }
|
||||
| yD_SYSTEM '(' expr ')' { $$ = new AstSystemF($1,$3); }
|
||||
//
|
||||
| system_f_call_or_t { $$ = $1; }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 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
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
|
||||
1;
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under The Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2022 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t;
|
||||
|
||||
task t;
|
||||
// verilator no_inline_task
|
||||
string trace;
|
||||
|
||||
$display("== Trace Func");
|
||||
trace = $stacktrace();
|
||||
if (trace == "") $stop;
|
||||
$display("%s", trace);
|
||||
|
||||
$display("== Trace Task");
|
||||
$stacktrace;
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
endtask
|
||||
|
||||
initial t();
|
||||
|
||||
endmodule
|
||||
Loading…
Reference in New Issue