From 5ec9bfc47d4fbe828e8b088b045dd0e9adbc2605 Mon Sep 17 00:00:00 2001 From: Todd Strader Date: Fri, 15 Dec 2023 17:32:23 -0500 Subject: [PATCH] Support packages in vpi_handle_by_name() (#4768) --- include/verilated_vpi.cpp | 16 +++++++++++++--- test_regress/t/t_vpi_package.cpp | 14 ++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index cca51db67..89701f42a 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -1744,15 +1744,19 @@ vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) { const VerilatedVpioScope* const voScopep = VerilatedVpioScope::castp(scope); std::string scopeAndName = namep; if (voScopep) { - scopeAndName = std::string{voScopep->fullname()} + "." + namep; + const bool scopeIsPackage = VerilatedVpioPackage::castp(scope) != nullptr; + scopeAndName = std::string{voScopep->fullname()} + (scopeIsPackage ? "" : ".") + namep; namep = const_cast(scopeAndName.c_str()); } { // This doesn't yet follow the hierarchy in the proper way + bool isPackage = false; scopep = Verilated::threadContextp()->scopeFind(namep); if (scopep) { // Whole thing found as a scope if (scopep->type() == VerilatedScope::SCOPE_MODULE) { return (new VerilatedVpioModule{scopep})->castVpiHandle(); + } else if (scopep->type() == VerilatedScope::SCOPE_PACKAGE) { + return (new VerilatedVpioPackage{scopep})->castVpiHandle(); } else { return (new VerilatedVpioScope{scopep})->castVpiHandle(); } @@ -1768,17 +1772,23 @@ vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) { while (i < scopeAndName.length() && scopeAndName[i] != ' ') ++i; ++i; // Proc ' ', it should always be there. Then grab '.' on next cycle } else { - while (i < scopeAndName.length() && scopeAndName[i] != '.') ++i; + while (i < scopeAndName.length() + && (scopeAndName[i] != '.' + && (i + 1 >= scopeAndName.length() || scopeAndName[i] != ':' + || scopeAndName[i + 1] != ':'))) + ++i; if (i < scopeAndName.length()) { prevpos = pos; pos = i++; + if (scopeAndName[i - 1] == ':') isPackage = true; } } } // Do the split if (VL_LIKELY(pos != std::string::npos)) { - basename.erase(0, pos + 1); + basename.erase(0, pos + (isPackage ? 2 : 1)); scopename = scopeAndName.substr(0, pos); + if (scopename == "$unit") scopename = "\\$unit "; } if (prevpos == std::string::npos) { // scopename is a toplevel (no '.' separator), so search in our TOP ports first. diff --git a/test_regress/t/t_vpi_package.cpp b/test_regress/t/t_vpi_package.cpp index 41568fca7..b171b3fbe 100644 --- a/test_regress/t/t_vpi_package.cpp +++ b/test_regress/t/t_vpi_package.cpp @@ -84,6 +84,12 @@ int count_params(TestVpiHandle& handle, int expectedParams) { return 0; } +int check_handle(char* name, vpiHandle scopeHandle) { + const TestVpiHandle handle = vpi_handle_by_name(name, scopeHandle); + CHECK_RESULT_NZ(handle) + return 0; +} + int mon_check() { #ifdef TEST_VERBOSE printf("-mon_check()\n"); @@ -142,6 +148,14 @@ int mon_check() { CHECK_RESULT_Z(count_params(pkgHandle, 2)); CHECK_RESULT_Z(count_params(tHandle, 3)); + CHECK_RESULT_Z(check_handle(const_cast("someOtherInt"), tHandle)) + CHECK_RESULT_Z(check_handle(const_cast("t.someOtherInt"), NULL)) + CHECK_RESULT_Z(check_handle(const_cast("someInt"), pkgHandle)) + CHECK_RESULT_Z(check_handle(const_cast("somepackage::someInt"), NULL)) + CHECK_RESULT_Z(check_handle(const_cast("dollarUnitInt"), unitHandle)) + CHECK_RESULT_Z(check_handle(const_cast("$unit::dollarUnitInt"), NULL)) + CHECK_RESULT_Z(check_handle(const_cast("somepackage"), NULL)) + return 0; // Ok } }