forked from github/verilator
Support tracing through --hierarchical/--lib-create libraries (#3200).
This commit is contained in:
parent
833686446c
commit
04e0c7e4f1
1
Changes
1
Changes
@ -14,6 +14,7 @@ Verilator 4.215 devel
|
||||
**Major:**
|
||||
|
||||
* Add --lib-create, similar to --protect-lib but without protections.
|
||||
* Support tracing through --hierarchical/--lib-create libraries (#3200).
|
||||
|
||||
**Minor:**
|
||||
|
||||
|
@ -489,6 +489,13 @@ or "`ifdef`"'s may break other tools.
|
||||
Verilator) text that should be passed through to the XML output as a tag,
|
||||
for use by downstream applications.
|
||||
|
||||
.. option:: /*verilator&32;trace_init_task*/
|
||||
|
||||
Attached to a DPI import to indicate that function should be called when
|
||||
initializing tracing. This attribute is indented only to be used
|
||||
internally in code that Verilator generates when :vlopt:`--lib-create`
|
||||
or :vlopt:`--hierarchical` is used along with :vlopt:`--trace`.
|
||||
|
||||
.. option:: /*verilator&32;tracing_off*/
|
||||
|
||||
Disable waveform tracing for all future signals that are declared in
|
||||
|
@ -2737,6 +2737,7 @@ private:
|
||||
bool m_dpiContext : 1; // DPI import context
|
||||
bool m_dpiOpenChild : 1; // DPI import open array child wrapper
|
||||
bool m_dpiTask : 1; // DPI import task (vs. void function)
|
||||
bool m_dpiTraceInit : 1; // DPI trace_init
|
||||
bool m_isConstructor : 1; // Class constructor
|
||||
bool m_isHideLocal : 1; // Verilog local
|
||||
bool m_isHideProtected : 1; // Verilog protected
|
||||
@ -2760,6 +2761,7 @@ protected:
|
||||
, m_dpiContext{false}
|
||||
, m_dpiOpenChild{false}
|
||||
, m_dpiTask{false}
|
||||
, m_dpiTraceInit{false}
|
||||
, m_isConstructor{false}
|
||||
, m_isHideLocal{false}
|
||||
, m_isHideProtected{false}
|
||||
@ -2822,6 +2824,8 @@ public:
|
||||
bool dpiOpenChild() const { return m_dpiOpenChild; }
|
||||
void dpiTask(bool flag) { m_dpiTask = flag; }
|
||||
bool dpiTask() const { return m_dpiTask; }
|
||||
void dpiTraceInit(bool flag) { m_dpiTraceInit = flag; }
|
||||
bool dpiTraceInit() const { return m_dpiTraceInit; }
|
||||
void isConstructor(bool flag) { m_isConstructor = flag; }
|
||||
bool isConstructor() const { return m_isConstructor; }
|
||||
bool isHideLocal() const { return m_isHideLocal; }
|
||||
|
@ -8781,11 +8781,12 @@ private:
|
||||
bool m_isVirtual : 1; // Virtual function
|
||||
bool m_entryPoint : 1; // User may call into this top level function
|
||||
bool m_pure : 1; // Pure function
|
||||
bool m_dpiContext : 1; // Declared as 'context' DPI import/export function
|
||||
bool m_dpiExportDispatcher : 1; // This is the DPI export entry point (i.e.: called by user)
|
||||
bool m_dpiExportImpl : 1; // DPI export implementation (called from DPI dispatcher via lookup)
|
||||
bool m_dpiImportPrototype : 1; // This is the DPI import prototype (i.e.: provided by user)
|
||||
bool m_dpiImportWrapper : 1; // Wrapper for invoking DPI import prototype from generated code
|
||||
bool m_dpiContext : 1; // Declared as 'context' DPI import/export function
|
||||
bool m_dpiTraceInit : 1; // DPI trace_init
|
||||
public:
|
||||
AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType = "")
|
||||
: ASTGEN_SUPER_CFunc(fl) {
|
||||
@ -8808,11 +8809,12 @@ public:
|
||||
m_isVirtual = false;
|
||||
m_entryPoint = false;
|
||||
m_pure = false;
|
||||
m_dpiContext = false;
|
||||
m_dpiExportDispatcher = false;
|
||||
m_dpiExportImpl = false;
|
||||
m_dpiImportPrototype = false;
|
||||
m_dpiImportWrapper = false;
|
||||
m_dpiContext = false;
|
||||
m_dpiTraceInit = false;
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(CFunc)
|
||||
virtual string name() const override { return m_name; }
|
||||
@ -8880,6 +8882,8 @@ public:
|
||||
void entryPoint(bool flag) { m_entryPoint = flag; }
|
||||
bool pure() const { return m_pure; }
|
||||
void pure(bool flag) { m_pure = flag; }
|
||||
bool dpiContext() const { return m_dpiContext; }
|
||||
void dpiContext(bool flag) { m_dpiContext = flag; }
|
||||
bool dpiExportDispatcher() const { return m_dpiExportDispatcher; }
|
||||
void dpiExportDispatcher(bool flag) { m_dpiExportDispatcher = flag; }
|
||||
bool dpiExportImpl() const { return m_dpiExportImpl; }
|
||||
@ -8888,8 +8892,8 @@ public:
|
||||
void dpiImportPrototype(bool flag) { m_dpiImportPrototype = flag; }
|
||||
bool dpiImportWrapper() const { return m_dpiImportWrapper; }
|
||||
void dpiImportWrapper(bool flag) { m_dpiImportWrapper = flag; }
|
||||
bool dpiContext() const { return m_dpiContext; }
|
||||
void dpiContext(bool flag) { m_dpiContext = flag; }
|
||||
void dpiTraceInit(bool flag) { m_dpiTraceInit = flag; }
|
||||
bool dpiTraceInit() const { return m_dpiTraceInit; }
|
||||
//
|
||||
// If adding node accessors, see below emptyBody
|
||||
AstNode* argsp() const { return op1p(); }
|
||||
|
@ -23,14 +23,31 @@
|
||||
#include "V3UniqueNames.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
class EmitCModel final : public EmitCFunc {
|
||||
// TYPES
|
||||
using CFuncVector = std::vector<const AstCFunc*>;
|
||||
|
||||
// MEMBERS
|
||||
V3UniqueNames m_uniqueNames; // For generating unique file names
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC;
|
||||
|
||||
CFuncVector findFuncps(std::function<bool(const AstCFunc*)> cb) {
|
||||
CFuncVector funcps;
|
||||
for (AstNode* nodep = m_modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstCFunc* const funcp = VN_CAST(nodep, CFunc)) {
|
||||
if (cb(funcp)) funcps.push_back(funcp);
|
||||
}
|
||||
}
|
||||
stable_sort(funcps.begin(), funcps.end(),
|
||||
[](const AstNode* ap, const AstNode* bp) { return ap->name() < bp->name(); });
|
||||
return funcps;
|
||||
}
|
||||
|
||||
void putSectionDelimiter(const string& name) {
|
||||
puts("\n");
|
||||
puts("//============================================================\n");
|
||||
@ -187,22 +204,11 @@ class EmitCModel final : public EmitCFunc {
|
||||
|
||||
// Emit DPI export dispatcher declarations
|
||||
{
|
||||
std::vector<const AstCFunc*> funcps;
|
||||
|
||||
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (const AstCFunc* const funcp = VN_CAST(nodep, CFunc)) {
|
||||
if (!funcp->dpiExportDispatcher()) continue;
|
||||
funcps.push_back(funcp);
|
||||
}
|
||||
}
|
||||
|
||||
stable_sort(funcps.begin(), funcps.end(), [](const AstNode* ap, const AstNode* bp) {
|
||||
return ap->name() < bp->name();
|
||||
});
|
||||
|
||||
const CFuncVector funcps
|
||||
= findFuncps([](const AstCFunc* nodep) { return nodep->dpiExportDispatcher(); });
|
||||
if (!funcps.empty()) {
|
||||
puts("\n/// DPI Export functions\n");
|
||||
for (const AstCFunc* funcp : funcps) { emitCFuncDecl(funcp, modp); }
|
||||
for (const AstCFunc* funcp : funcps) emitCFuncDecl(funcp, modp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -568,12 +574,38 @@ class EmitCModel final : public EmitCFunc {
|
||||
+ topModNameProtected + "* vlSelf, " + v3Global.opt.traceClassBase()
|
||||
+ "* tracep);\n");
|
||||
|
||||
const CFuncVector traceInitFuncps
|
||||
= findFuncps([](const AstCFunc* nodep) { return nodep->dpiTraceInit(); });
|
||||
for (const AstCFunc* const funcp : traceInitFuncps) emitCFuncDecl(funcp, modp);
|
||||
|
||||
// ::trace
|
||||
puts("\nVL_ATTR_COLD void " + topClassName() + "::trace(");
|
||||
puts(v3Global.opt.traceClassBase() + "C* tfp, int, int) {\n");
|
||||
puts(v3Global.opt.traceClassBase() + "C* tfp, int levels, int options) {\n");
|
||||
puts(/**/ "if (false && levels && options) {} // Prevent unused\n");
|
||||
puts(/**/ "tfp->spTrace()->addInitCb(&" + protect("trace_init") + ", &(vlSymsp->TOP));\n");
|
||||
puts(/**/ topModNameProtected + "__" + protect("trace_register")
|
||||
+ "(&(vlSymsp->TOP), tfp->spTrace());\n");
|
||||
|
||||
if (!traceInitFuncps.empty()) {
|
||||
puts(/**/ "if (levels > 0) {\n");
|
||||
puts(/****/ "const QData tfpq = reinterpret_cast<QData>(tfp);\n");
|
||||
for (const AstCFunc* const funcp : traceInitFuncps) {
|
||||
// Some hackery to locate handle__V for trace_init_task
|
||||
// Considered a pragma on the handle, but that still doesn't help us attach it here
|
||||
string handle = funcp->name();
|
||||
const size_t wr_len = strlen("__Vdpiimwrap_");
|
||||
UASSERT_OBJ(handle.substr(0, wr_len) == "__Vdpiimwrap_", funcp,
|
||||
"Strange trace_init_task function name");
|
||||
handle = "vlSymsp->TOP." + handle.substr(wr_len);
|
||||
const string::size_type pos = handle.rfind("__DOT__");
|
||||
UASSERT_OBJ(pos != string::npos, funcp, "Strange trace_init_task function name");
|
||||
handle = handle.substr(0, pos) + "__DOT__handle___05FV";
|
||||
puts(funcNameProtect(funcp, modp) + "(" + handle
|
||||
+ ", tfpq, levels - 1, options);\n");
|
||||
}
|
||||
puts(/**/ "}\n");
|
||||
}
|
||||
|
||||
puts("}\n");
|
||||
}
|
||||
|
||||
|
@ -124,6 +124,11 @@ private:
|
||||
addComment(txtp, fl, "Evaluates the library module's final process");
|
||||
}
|
||||
|
||||
void traceComment(AstTextBlock* txtp, FileLine* fl) {
|
||||
addComment(txtp, fl, "Enables the library module's tracing");
|
||||
addComment(txtp, fl, "Only usable when used with called from Verilator");
|
||||
}
|
||||
|
||||
void createSvFile(FileLine* fl, AstNodeModule* modp) {
|
||||
// Comments
|
||||
AstTextBlock* const txtp = new AstTextBlock(fl);
|
||||
@ -197,6 +202,18 @@ private:
|
||||
txtp->addText(fl, "import \"DPI-C\" function void " + m_libName
|
||||
+ "_protectlib_final(chandle handle__V);\n\n");
|
||||
|
||||
if (v3Global.opt.trace() && !v3Global.opt.protectIds()) {
|
||||
txtp->addText(fl, "`ifdef verilator\n");
|
||||
traceComment(txtp, fl);
|
||||
txtp->addText(fl, "import \"DPI-C\" function void " + m_libName
|
||||
+ "_protectlib_trace(chandle handle__V, "
|
||||
"chandle tfp, int levels, int options)"
|
||||
+ " /*verilator trace_init_task*/;\n");
|
||||
// Note V3EmitCModel.cpp requires the name "handle__V".
|
||||
txtp->addText(fl, "`endif // verilator\n");
|
||||
txtp->addText(fl, "\n");
|
||||
}
|
||||
|
||||
// Local variables
|
||||
// Avoid tracing handle, as it is not a stable value, so breaks vcddiff
|
||||
// Likewise other internals aren't interesting to the user
|
||||
@ -387,6 +404,18 @@ private:
|
||||
txtp->addText(fl, /**/ "delete handlep__V;\n");
|
||||
txtp->addText(fl, "}\n\n");
|
||||
|
||||
if (v3Global.opt.trace() && !v3Global.opt.protectIds()) {
|
||||
traceComment(txtp, fl);
|
||||
txtp->addText(fl, "void " + m_libName
|
||||
+ "_protectlib_trace(void* vhandlep__V, void* tfp, int levels, "
|
||||
"int options) {\n");
|
||||
castPtr(fl, txtp);
|
||||
txtp->addText(
|
||||
fl,
|
||||
/**/ "handlep__V->trace(static_cast<VerilatedVcdC*>(tfp), levels, options);\n");
|
||||
txtp->addText(fl, "}\n\n");
|
||||
}
|
||||
|
||||
txtp->addText(fl, "}\n");
|
||||
m_cfilep->tblockp(txtp);
|
||||
}
|
||||
|
@ -933,8 +933,8 @@ private:
|
||||
: nodep->dpiTask() ? "int"
|
||||
: "";
|
||||
AstCFunc* const funcp = new AstCFunc(nodep->fileline(), nodep->cname(), m_scopep, rtnType);
|
||||
funcp->dpiImportPrototype(true);
|
||||
funcp->dpiContext(nodep->dpiContext());
|
||||
funcp->dpiImportPrototype(true);
|
||||
funcp->dontCombine(true);
|
||||
funcp->entryPoint(false);
|
||||
funcp->isMethod(false);
|
||||
@ -1201,9 +1201,10 @@ private:
|
||||
cfuncp->dontCombine(!nodep->dpiImport());
|
||||
cfuncp->entryPoint(!nodep->dpiImport());
|
||||
cfuncp->funcPublic(nodep->taskPublic());
|
||||
cfuncp->dpiContext(nodep->dpiContext());
|
||||
cfuncp->dpiExportImpl(nodep->dpiExport());
|
||||
cfuncp->dpiImportWrapper(nodep->dpiImport());
|
||||
cfuncp->dpiContext(nodep->dpiContext());
|
||||
cfuncp->dpiTraceInit(nodep->dpiTraceInit());
|
||||
if (nodep->dpiImport() || nodep->dpiExport()) {
|
||||
cfuncp->isStatic(true);
|
||||
cfuncp->isLoose(true);
|
||||
|
@ -745,6 +745,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
"/*verilator split_var*/" { FL; return yVL_SPLIT_VAR; }
|
||||
"/*verilator tag"[^*]*"*/" { FL; yylval.strp = PARSEP->newString(V3ParseImp::lexParseTag(yytext));
|
||||
return yVL_TAG; }
|
||||
"/*verilator trace_init_task*/" { FL; return yVL_TRACE_INIT_TASK; }
|
||||
"/*verilator tracing_off*/" { FL_FWD; PARSEP->lexFileline()->tracingOn(false); FL_BRK; }
|
||||
"/*verilator tracing_on*/" { FL_FWD; PARSEP->lexFileline()->tracingOn(true); FL_BRK; }
|
||||
|
||||
|
@ -829,6 +829,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
|
||||
%token<fl> yVL_SFORMAT "/*verilator sformat*/"
|
||||
%token<fl> yVL_SPLIT_VAR "/*verilator split_var*/"
|
||||
%token<strp> yVL_TAG "/*verilator tag*/"
|
||||
%token<fl> yVL_TRACE_INIT_TASK "/*verilator trace_init_task*/"
|
||||
|
||||
%token<fl> yP_TICK "'"
|
||||
%token<fl> yP_TICKBRA "'{"
|
||||
@ -4125,16 +4126,24 @@ array_methodWith<nodep>:
|
||||
;
|
||||
|
||||
dpi_import_export<nodep>: // ==IEEE: dpi_import_export
|
||||
yIMPORT yaSTRING dpi_tf_import_propertyE dpi_importLabelE function_prototype ';'
|
||||
{ $$ = $5; if (*$4 != "") $5->cname(*$4);
|
||||
$5->dpiContext($3==iprop_CONTEXT); $5->pure($3==iprop_PURE);
|
||||
$5->dpiImport(true); GRAMMARP->checkDpiVer($1,*$2); v3Global.dpi(true);
|
||||
yIMPORT yaSTRING dpi_tf_import_propertyE dpi_importLabelE function_prototype dpi_tf_TraceInitE ';'
|
||||
{ $$ = $5;
|
||||
if (*$4 != "") $5->cname(*$4);
|
||||
$5->dpiContext($3 == iprop_CONTEXT);
|
||||
$5->pure($3 == iprop_PURE);
|
||||
$5->dpiImport(true);
|
||||
$5->dpiTraceInit($6);
|
||||
GRAMMARP->checkDpiVer($1, *$2); v3Global.dpi(true);
|
||||
if ($$->prettyName()[0]=='$') SYMP->reinsert($$,nullptr,$$->prettyName()); // For $SysTF overriding
|
||||
SYMP->reinsert($$); }
|
||||
| yIMPORT yaSTRING dpi_tf_import_propertyE dpi_importLabelE task_prototype ';'
|
||||
{ $$ = $5; if (*$4 != "") $5->cname(*$4);
|
||||
$5->dpiContext($3==iprop_CONTEXT); $5->pure($3==iprop_PURE);
|
||||
$5->dpiImport(true); $5->dpiTask(true); GRAMMARP->checkDpiVer($1,*$2); v3Global.dpi(true);
|
||||
{ $$ = $5;
|
||||
if (*$4 != "") $5->cname(*$4);
|
||||
$5->dpiContext($3 == iprop_CONTEXT);
|
||||
$5->pure($3 == iprop_PURE);
|
||||
$5->dpiImport(true);
|
||||
$5->dpiTask(true);
|
||||
GRAMMARP->checkDpiVer($1, *$2); v3Global.dpi(true);
|
||||
if ($$->prettyName()[0]=='$') SYMP->reinsert($$,nullptr,$$->prettyName()); // For $SysTF overriding
|
||||
SYMP->reinsert($$); }
|
||||
| yEXPORT yaSTRING dpi_importLabelE yFUNCTION idAny ';'
|
||||
@ -4156,6 +4165,12 @@ dpi_tf_import_propertyE<iprop>: // IEEE: [ dpi_function_import_property + dpi_ta
|
||||
| yPURE { $$ = iprop_PURE; }
|
||||
;
|
||||
|
||||
dpi_tf_TraceInitE<cbool>: // Verilator extension
|
||||
/* empty */ { $$ = false; }
|
||||
| yVL_TRACE_INIT_TASK { $$ = true; $<fl>$ = $<fl>1; }
|
||||
;
|
||||
|
||||
|
||||
//************************************************
|
||||
// Expressions
|
||||
//
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user