From 1607225063da9b58a2d95a590657675c29c98f95 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Feb 2023 16:16:39 -0500 Subject: [PATCH] Fix VPI upper interface scopes not found (#3937). --- Changes | 1 + src/V3EmitCSyms.cpp | 17 ++-- test_regress/t/t_vpi_module_empty.cpp | 123 ++++++++++++++++++++++++++ test_regress/t/t_vpi_module_empty.pl | 30 +++++++ test_regress/t/t_vpi_module_empty.v | 25 ++++++ 5 files changed, 188 insertions(+), 8 deletions(-) create mode 100644 test_regress/t/t_vpi_module_empty.cpp create mode 100755 test_regress/t/t_vpi_module_empty.pl create mode 100644 test_regress/t/t_vpi_module_empty.v diff --git a/Changes b/Changes index e960eea2b..338086737 100644 --- a/Changes +++ b/Changes @@ -25,6 +25,7 @@ Verilator 5.007 devel * Fix pattern assignment to unpacked structs (#3510). [Mostafa Garnal] * Fix single-element replication to dynarray/unpacked/queue (#3548). [Gustav Svensk] * Fix very long VPI signal names (#3929). [Marlon James] +* Fix VPI upper interface scopes not found (#3937). [David Stanford] Verilator 5.006 2023-01-22 diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index acdfea777..2ae694b48 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -186,7 +186,7 @@ class EmitCSyms final : EmitCBaseVisitor { void varHierarchyScopes(string scp) { while (!scp.empty()) { - const auto scpit = m_vpiScopeCandidates.find(scp); + const auto scpit = m_vpiScopeCandidates.find(scopeSymString(scp)); if ((scpit != m_vpiScopeCandidates.end()) && (m_scopeNames.find(scp) == m_scopeNames.end())) { const auto scopeNameit = m_scopeNames.find(scpit->second.m_symName); @@ -314,8 +314,9 @@ class EmitCSyms final : EmitCBaseVisitor { const string name = nodep->scopep()->shortName() + "__DOT__" + nodep->name(); const string name_pretty = AstNode::vpiName(name); const int timeunit = m_modp->timeunit().powerOfTen(); - m_vpiScopeCandidates.insert(std::make_pair( - name, ScopeData{scopeSymString(name), name_pretty, timeunit, type})); + m_vpiScopeCandidates.insert( + std::make_pair(scopeSymString(name), + ScopeData{scopeSymString(name), name_pretty, timeunit, type})); } } void visit(AstScope* nodep) override { @@ -328,15 +329,15 @@ class EmitCSyms final : EmitCBaseVisitor { const string type = VN_IS(nodep->modp(), Package) ? "SCOPE_OTHER" : "SCOPE_MODULE"; const string name_pretty = AstNode::vpiName(nodep->shortName()); const int timeunit = m_modp->timeunit().powerOfTen(); - m_vpiScopeCandidates.insert( - std::make_pair(nodep->name(), ScopeData{scopeSymString(nodep->name()), name_pretty, - timeunit, type})); + m_vpiScopeCandidates.insert(std::make_pair( + scopeSymString(nodep->name()), + ScopeData{scopeSymString(nodep->name()), name_pretty, timeunit, type})); } } void visit(AstScopeName* nodep) override { const string name = nodep->scopeSymName(); - // UINFO(9,"scnameins sp "<name()<<" sp "<scopePrettySymName() - // <<" ss"<name() << " sp " << nodep->scopePrettySymName() + // << " ss" << name << endl); const int timeunit = m_modp ? m_modp->timeunit().powerOfTen() : 0; m_scopeNames.emplace( name, ScopeData{name, nodep->scopePrettySymName(), timeunit, "SCOPE_OTHER"}); diff --git a/test_regress/t/t_vpi_module_empty.cpp b/test_regress/t/t_vpi_module_empty.cpp new file mode 100644 index 000000000..139ff4cce --- /dev/null +++ b/test_regress/t/t_vpi_module_empty.cpp @@ -0,0 +1,123 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2010-2023 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 +// +//************************************************************************* + +#ifdef IS_VPI + +#include "vpi_user.h" + +#include + +#else + +#include "verilated.h" +#include "verilated_vcd_c.h" +#include "verilated_vpi.h" + +#include "Vt_vpi_module_empty.h" +#include "Vt_vpi_module_empty__Dpi.h" +#include "svdpi.h" + +#endif + +#include +#include +#include + +// These require the above. Comment prevents clang-format moving them +#include "TestSimulator.h" +#include "TestVpi.h" + +// __FILE__ is too long +#define FILENM "t_vpi_module_empty.cpp" + +#define DEBUG \ + if (0) printf + +#define CHECK_RESULT_NZ(got) \ + if (!(got)) { \ + printf("%%Error: %s:%d: GOT = NULL EXP = !NULL\n", FILENM, __LINE__); \ + return __LINE__; \ + } + +extern "C" { +int mon_check() { +#ifdef TEST_VERBOSE + printf("-mon_check()\n"); +#endif + + TestVpiHandle it = vpi_iterate(vpiModule, NULL); + CHECK_RESULT_NZ(it); + return 0; // Ok +} +} +//====================================================================== + +#ifdef IS_VPI + +static int mon_check_vpi() { + TestVpiHandle href = vpi_handle(vpiSysTfCall, 0); + s_vpi_value vpi_value; + + vpi_value.format = vpiIntVal; + vpi_value.value.integer = mon_check(); + vpi_put_value(href, &vpi_value, NULL, vpiNoDelay); + + return 0; +} + +static s_vpi_systf_data vpi_systf_data[] = {{vpiSysFunc, vpiIntFunc, (PLI_BYTE8*)"$mon_check", + (PLI_INT32(*)(PLI_BYTE8*))mon_check_vpi, 0, 0, 0}, + 0}; + +// cver entry +void vpi_compat_bootstrap(void) { + p_vpi_systf_data systf_data_p; + systf_data_p = &(vpi_systf_data[0]); + while (systf_data_p->type != 0) vpi_register_systf(systf_data_p++); +} + +// icarus entry +void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0}; + +#else + +int main(int argc, char** argv) { + const std::unique_ptr contextp{new VerilatedContext}; + + uint64_t sim_time = 1100; + contextp->debug(0); + contextp->commandArgs(argc, argv); + // we're going to be checking for these errors do don't crash out + contextp->fatalOnVpiError(0); + + // Test second construction + const std::unique_ptr topp{new VM_PREFIX{contextp.get(), + // Note null name - we're flattening it out + ""}}; + +#ifdef VERILATOR +#ifdef TEST_VERBOSE + contextp->scopesDump(); +#endif +#endif + + topp->eval(); + VerilatedVpi::callValueCbs(); + TestVpiHandle vh = vpi_handle_by_name((PLI_BYTE8*)"top.sv_if_i.a", NULL); + CHECK_RESULT_NZ(vh); + TestVpiHandle it = vpi_iterate(vpiModule, NULL); + CHECK_RESULT_NZ(it); + + topp->final(); + return 0; +} + +#endif diff --git a/test_regress/t/t_vpi_module_empty.pl b/test_regress/t/t_vpi_module_empty.pl new file mode 100755 index 000000000..d9362b696 --- /dev/null +++ b/test_regress/t/t_vpi_module_empty.pl @@ -0,0 +1,30 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2010 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); + +skip("Known compiler limitation") + if $Self->cxx_version =~ /\(GCC\) 4.4/; + +compile( + make_top_shell => 0, + make_main => 0, + make_pli => 1, + iv_flags2 => ["-g2005-sv"], + verilator_flags2 => ["+define+USE_DOLLAR_C32 --exe --vpi --no-l2name $Self->{t_dir}/t_vpi_module_empty.cpp"], + ); + +execute( + use_libvpi => 1, + check_finished => 1 + ); + +ok(1); +1; diff --git a/test_regress/t/t_vpi_module_empty.v b/test_regress/t/t_vpi_module_empty.v new file mode 100644 index 000000000..cd0f78d34 --- /dev/null +++ b/test_regress/t/t_vpi_module_empty.v @@ -0,0 +1,25 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2023 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 + +interface sv_if(); + logic a /*verilator public_flat_rw*/; +endinterface + +module top (); + + sv_if sv_if_i(); + + // Workaround for bug3937: + // logic d /*verilator public_flat_rw*/; + + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule