Fix finding single DPI exports from other scopes
This commit is contained in:
parent
e976424efa
commit
9bc88ff1bc
|
|
@ -3464,11 +3464,10 @@ void Verilated::mkdir(const char* dirname) VL_MT_UNSAFE {
|
|||
|
||||
void Verilated::quiesce() VL_MT_SAFE {
|
||||
// Wait until all threads under this evaluation are quiet
|
||||
// THREADED-TODO
|
||||
}
|
||||
|
||||
int Verilated::exportFuncNum(const char* namep) VL_MT_SAFE {
|
||||
return VerilatedImp::exportFind(namep);
|
||||
return VerilatedImp::exportFindNum(namep);
|
||||
}
|
||||
|
||||
void Verilated::endOfThreadMTaskGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
|
||||
|
|
@ -3573,7 +3572,7 @@ VerilatedScope::~VerilatedScope() {
|
|||
void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE {
|
||||
// Slowpath - called once/scope*export at construction
|
||||
// Insert a exported function into scope table
|
||||
const int funcnum = VerilatedImp::exportInsert(namep);
|
||||
const int funcnum = VerilatedImp::exportInsert(namep, cb);
|
||||
if (!finalize) {
|
||||
// Need two passes so we know array size to create
|
||||
// Alternative is to dynamically stretch the array, which is more code, and slower.
|
||||
|
|
@ -3630,6 +3629,25 @@ VerilatedVar* VerilatedScope::varFind(const char* namep) const VL_MT_SAFE_POSTIN
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void* VerilatedScope::exportFind(const VerilatedScope* scopep, int funcnum) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(!scopep)) return exportFindNullError(funcnum);
|
||||
// If function is registered only once across all scopes, fast path it.
|
||||
// UVM for example expects to find uvm_polling_value_change_notify
|
||||
// from a different scope than where decared.
|
||||
VL_DEBUG_IFDEF(assert(funcnum < VerilatedImp::exportFlatCbs().size()););
|
||||
{
|
||||
void* const cbp = VerilatedImp::exportFlatCbs()[funcnum];
|
||||
if (VL_LIKELY(cbp)) return cbp;
|
||||
}
|
||||
// Else specific scope-based export call
|
||||
if (VL_LIKELY(funcnum < scopep->m_funcnumMax)) {
|
||||
// m_callbacksp must be declared, as Max'es are > 0
|
||||
void* const cbp = scopep->m_callbacksp[funcnum];
|
||||
if (VL_LIKELY(cbp)) return cbp;
|
||||
}
|
||||
return scopep->exportFindError(funcnum); // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
void* VerilatedScope::exportFindNullError(int funcnum) VL_MT_SAFE {
|
||||
// Slowpath - Called only when find has failed
|
||||
const std::string msg = ("Testbench C called '"s + VerilatedImp::exportName(funcnum)
|
||||
|
|
|
|||
|
|
@ -744,15 +744,7 @@ public: // But internals only - called from verilated modules, VerilatedSyms
|
|||
void scopeDump() const;
|
||||
void* exportFindError(int funcnum) const VL_MT_SAFE;
|
||||
static void* exportFindNullError(int funcnum) VL_MT_SAFE;
|
||||
static void* exportFind(const VerilatedScope* scopep, int funcnum) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(!scopep)) return exportFindNullError(funcnum);
|
||||
if (VL_LIKELY(funcnum < scopep->m_funcnumMax)) {
|
||||
// m_callbacksp must be declared, as Max'es are > 0
|
||||
return scopep->m_callbacksp[funcnum];
|
||||
} else { // LCOV_EXCL_LINE
|
||||
return scopep->exportFindError(funcnum); // LCOV_EXCL_LINE
|
||||
}
|
||||
}
|
||||
static void* exportFind(const VerilatedScope* scopep, int funcnum) VL_MT_SAFE;
|
||||
Type type() const { return m_type; }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -433,6 +433,10 @@ protected:
|
|||
ExportNameMap m_exportMap VL_GUARDED_BY(m_exportMutex);
|
||||
int m_exportNext VL_GUARDED_BY(m_exportMutex) = 0; // Next export funcnum
|
||||
|
||||
// No guard, as init-time loaded
|
||||
std::vector<void*> m_exportFlatCbs; // Exports when only single scope registered
|
||||
std::vector<bool> m_exportFlatMulti; // Multiple scopes registerd; cannot use m_exportScopes
|
||||
|
||||
// CONSTRUCTORS
|
||||
VerilatedImpData() = default;
|
||||
};
|
||||
|
|
@ -542,8 +546,8 @@ public:
|
|||
// in the design that also happen to have our same callback function.
|
||||
// Rather than a 2D map, the integer scheme saves 500ish ns on a likely
|
||||
// miss at the cost of a multiply, and all lookups move to slowpath.
|
||||
static int exportInsert(const char* namep) VL_MT_SAFE {
|
||||
// Slow ok - called once/function at creation
|
||||
private:
|
||||
static int exportInsertName(const char* namep) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock{s().m_exportMutex};
|
||||
const auto it = s().m_exportMap.find(namep);
|
||||
if (it == s().m_exportMap.end()) {
|
||||
|
|
@ -553,15 +557,37 @@ public:
|
|||
return it->second;
|
||||
}
|
||||
}
|
||||
static int exportFind(const char* namep) VL_MT_SAFE {
|
||||
|
||||
public:
|
||||
static int exportInsert(const char* namep, void* cb) VL_MT_SAFE {
|
||||
const int funcnum = VerilatedImp::exportInsertName(namep);
|
||||
const VerilatedLockGuard lock{s().m_exportMutex};
|
||||
// Slow ok - called once/function at creation
|
||||
if (funcnum >= s().m_exportFlatCbs.size()) {
|
||||
s().m_exportFlatCbs.resize(funcnum + 1);
|
||||
s().m_exportFlatMulti.resize(funcnum + 1);
|
||||
}
|
||||
if (!s().m_exportFlatMulti[funcnum]) {
|
||||
if (s().m_exportFlatCbs[funcnum] == cb) { // Duplicate
|
||||
} else if (!s().m_exportFlatCbs[funcnum]) { // First
|
||||
s().m_exportFlatCbs[funcnum] = cb;
|
||||
} else { // Multiple registrants
|
||||
s().m_exportFlatCbs[funcnum] = nullptr;
|
||||
s().m_exportFlatMulti[funcnum] = true;
|
||||
}
|
||||
}
|
||||
return funcnum;
|
||||
}
|
||||
static int exportFindNum(const char* namep) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock{s().m_exportMutex};
|
||||
const auto& it = s().m_exportMap.find(namep);
|
||||
if (VL_LIKELY(it != s().m_exportMap.end())) return it->second;
|
||||
const std::string msg = ("%Error: Testbench C called "s + namep
|
||||
+ " but no such DPI export function name exists in ANY model");
|
||||
const std::string msg = "%Error: Testbench C called "s + namep
|
||||
+ " but no such DPI export function name exists in ANY model";
|
||||
VL_FATAL_MT("unknown", 0, "", msg.c_str());
|
||||
return -1;
|
||||
}
|
||||
static const std::vector<void*>& exportFlatCbs() VL_MT_SAFE { return s().m_exportFlatCbs; }
|
||||
static const char* exportName(int funcnum) VL_MT_SAFE {
|
||||
// Slowpath; find name for given export; errors only so no map to reverse-map it
|
||||
const VerilatedLockGuard lock{s().m_exportMutex};
|
||||
|
|
|
|||
|
|
@ -7,15 +7,23 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
module t;
|
||||
s s();
|
||||
s s ();
|
||||
other other ();
|
||||
|
||||
import "DPI-C" context function void dpix_run_tests();
|
||||
initial dpix_run_tests();
|
||||
import "DPI-C" context function void dpix_run_tests();
|
||||
initial dpix_run_tests();
|
||||
endmodule
|
||||
|
||||
module s;
|
||||
export "DPI-C" task dpix_task;
|
||||
task dpix_task();
|
||||
$write("Hello in %m\n");
|
||||
endtask
|
||||
export "DPI-C" task dpix_task;
|
||||
task dpix_task();
|
||||
$write("Hello in %m\n");
|
||||
endtask
|
||||
endmodule
|
||||
|
||||
module other;
|
||||
export "DPI-C" task dpix_task;
|
||||
task dpix_task();
|
||||
$write("Hello in %m\n");
|
||||
endtask
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2010 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
#include <verilated.h>
|
||||
|
||||
//======================================================================
|
||||
|
||||
#include "Vt_dpi_export_scope_flat__Dpi.h"
|
||||
|
||||
#ifdef NEED_EXTERNS
|
||||
extern "C" {
|
||||
extern void dpix_task();
|
||||
}
|
||||
#endif
|
||||
|
||||
//======================================================================
|
||||
|
||||
void dpix_run_tests() {
|
||||
dpix_task(); // Wrong scope
|
||||
}
|
||||
|
|
@ -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: 2024 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile(v_flags2=["--binary", test.pli_filename])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// 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: 2020 Wilson Snyder
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
module t;
|
||||
s s ();
|
||||
|
||||
import "DPI-C" context function void dpix_run_tests();
|
||||
initial dpix_run_tests();
|
||||
endmodule
|
||||
|
||||
module s;
|
||||
export "DPI-C" task dpix_task;
|
||||
task dpix_task();
|
||||
$write("Hello in %m\n");
|
||||
endtask
|
||||
endmodule
|
||||
Loading…
Reference in New Issue