Fix vpi_handle_by_name generated scope retrieval (#7187 repair) (#7214)

Co-authored-by: Christian Hecken <christian.hecken@ibm.com>
This commit is contained in:
Christian Hecken 2026-03-08 02:36:29 +01:00 committed by GitHub
parent 3097df46fa
commit 0019c12242
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 66 additions and 8 deletions

View File

@ -2233,11 +2233,6 @@ static bool vl_vpi_parse_indices(std::string& name, std::vector<PLI_INT32>& indi
VlVpiBitRange* bitRange = nullptr) {
if (name.empty() || name.back() != ']') return false;
// Collapse consecutive spaces into single spaces
name.erase(
std::unique(name.begin(), name.end(), [](char a, char b) { return a == ' ' && b == ' '; }),
name.end());
// Only parse brackets after the last escaped identifier's terminating space
size_t escapeSpacePos = std::string::npos;
const size_t backslashPos = name.rfind('\\');
@ -2307,12 +2302,16 @@ vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) {
if (VL_UNLIKELY(!namep)) return nullptr;
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_handle_by_name %s %p\n", namep, scope););
// Parse any array indices and optional bit range from the name
// e.g., "mem[0][3][2]" or "signal[15:8]" or "mem[0][3][15:8]"
std::string scopeAndName = namep;
// Collapse consecutive spaces into single spaces (can occur with escaped identifiers)
scopeAndName.erase(std::unique(scopeAndName.begin(), scopeAndName.end(),
[](char a, char b) { return a == ' ' && b == ' '; }),
scopeAndName.end());
static thread_local std::vector<PLI_INT32> indices;
VlVpiBitRange bitRange;
const bool hasIndices = vl_vpi_parse_indices(scopeAndName, indices, &bitRange);
bool hasIndices = false;
const VerilatedVar* varp = nullptr;
const VerilatedScope* scopep;
@ -2328,6 +2327,9 @@ vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) {
{
// This doesn't yet follow the hierarchy in the proper way
bool isPackage = false;
// Scopes in generate blocks can also end with an index, so look it up first before
// interpreting the trailing brackets as array indices or bit selects.
scopep = Verilated::threadContextp()->scopeFind(scopeAndName.c_str());
if (scopep) { // Whole thing found as a scope
if (scopep->type() == VerilatedScope::SCOPE_MODULE) {
@ -2367,6 +2369,11 @@ vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) {
scopename = scopeAndName.substr(0, pos);
if (scopename == "$unit") scopename = "\\$unit ";
}
// Parse any array indices and optional bit range from the name
// e.g., "mem[0][3][2]" or "signal[15:8]" or "mem[0][3][15:8]"
hasIndices = vl_vpi_parse_indices(basename, indices, &bitRange);
if (prevpos == std::string::npos) {
// scopename is a toplevel (no '.' separator), so search in our TOP ports first.
scopep = Verilated::threadContextp()->scopeFind("TOP");

View File

@ -9,6 +9,7 @@
//
//*************************************************************************
#include "vpi_user.h"
#ifdef IS_VPI
#include "sv_vpi_user.h"
@ -1215,6 +1216,38 @@ int _mon_check_multi_index() {
CHECK_RESULT(vpi_get(vpiSize, vh_two_escapes_ps), 4);
}
// vpi_handle_by_name with generated signal
{
// Retrieve signal
TestVpiHandle vh_generated = vpi_handle_by_name((PLI_BYTE8*)"t.gen[0].gen_sig", NULL);
CHECK_RESULT_NZ(vh_generated);
CHECK_RESULT(vpi_get(vpiType, vh_generated), vpiReg);
CHECK_RESULT(vpi_get(vpiSize, vh_generated), 8);
vpi_get_value(vh_generated, &v);
CHECK_RESULT(v.value.integer, 0xAB);
// Single bit indexing
TestVpiHandle vh_generated_bit
= vpi_handle_by_name((PLI_BYTE8*)"t.gen[0].gen_sig[3]", NULL);
CHECK_RESULT_NZ(vh_generated_bit);
CHECK_RESULT(vpi_get(vpiType, vh_generated_bit), vpiReg);
CHECK_RESULT(vpi_get(vpiSize, vh_generated_bit), 1);
vpi_get_value(vh_generated_bit, &v);
CHECK_RESULT(v.value.integer, 1);
// Generated scope
TestVpiHandle vh_generated_scope = vpi_handle_by_name((PLI_BYTE8*)"t.subs[1]", NULL);
CHECK_RESULT_NZ(vh_generated_scope);
CHECK_RESULT(vpi_get(vpiType, vh_generated_scope), vpiGenScope);
// Signal in generated instance
TestVpiHandle vh_generated_inst
= vpi_handle_by_name((PLI_BYTE8*)"t.subs[1].subsub.subsig1", NULL);
CHECK_RESULT_NZ(vh_generated_inst);
CHECK_RESULT(vpi_get(vpiType, vh_generated_inst), vpiReg);
CHECK_RESULT(vpi_get(vpiSize, vh_generated_inst), 1);
}
// vpi_handle_by_name with array indexing
{
TestVpiHandle vh_1d = vpi_handle_by_name((PLI_BYTE8*)"t.quads[2]", nullptr);

View File

@ -76,6 +76,12 @@ extern "C" int mon_check();
logic [31:0] some_mem [4] /* verilator public_flat_rd */ = {0, 0, 0, 432};
generate
for (genvar i = 0; i < 1; i++) begin : gen
wire [7:0] gen_sig /*verilator public_flat_rw*/ = 8'hAB;
end
endgenerate
sub sub();
// Test loop

View File

@ -94,6 +94,12 @@ extern "C" int mon_check();
logic [31:0] some_mem [4] = {0, 0, 0, 432};
/*verilator public_off*/
generate
for (genvar i = 0; i < 1; i++) begin : gen
wire [7:0] gen_sig /*verilator public_flat_rw*/ = 8'hAB;
end
endgenerate
sub sub();
// Test loop

View File

@ -74,6 +74,12 @@ extern "C" int mon_check();
localparam int nullptr = 123;
logic [31:0] some_mem [4] = {0, 0, 0, 432};
generate
for (genvar i = 0; i < 1; i++) begin : gen
wire [7:0] gen_sig /*verilator public_flat_rw*/ = 8'hAB;
end
endgenerate
sub sub();
// Test loop