vpi_iterate packages with vpiInstance (#4726)

This commit is contained in:
Todd Strader 2023-12-01 07:34:09 -05:00 committed by GitHub
parent feae9ca4aa
commit 9a0748d8ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 359 additions and 9 deletions

View File

@ -627,8 +627,9 @@ class VerilatedScope final {
public:
enum Type : uint8_t {
SCOPE_MODULE,
SCOPE_OTHER
}; // Type of a scope, currently module is only interesting
SCOPE_OTHER,
SCOPE_PACKAGE
}; // Type of a scope, currently only module and package are interesting
private:
// Fastpath:
VerilatedSyms* m_symsp = nullptr; // Symbol table

View File

@ -474,12 +474,71 @@ public:
}
uint32_t type() const override { return vpiIterator; }
vpiHandle dovpi_scan() override {
if (m_it == m_vec->end()) {
delete this; // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle
return nullptr;
while (true) {
if (m_it == m_vec->end()) {
delete this; // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle
return nullptr;
}
const VerilatedScope::Type type = (*m_it)->type();
const VerilatedScope* const modp = *m_it++;
if (type == VerilatedScope::SCOPE_MODULE) {
return (new VerilatedVpioModule{modp})->castVpiHandle();
}
}
}
};
class VerilatedVpioPackage final : public VerilatedVpioScope {
std::string m_name;
std::string m_fullname;
public:
explicit VerilatedVpioPackage(const VerilatedScope* modulep)
: VerilatedVpioScope{modulep} {
const char* fullname = m_scopep->name();
if (std::strncmp(fullname, "TOP.", 4) == 0) fullname += 4;
m_fullname = std::string{fullname} + "::";
if (m_fullname == "\\$unit ::") m_fullname = "$unit::";
m_name = std::string(m_scopep->identifier());
if (m_name == "\\$unit ") m_name = "$unit";
}
static VerilatedVpioPackage* castp(vpiHandle h) {
return dynamic_cast<VerilatedVpioPackage*>(reinterpret_cast<VerilatedVpio*>(h));
}
uint32_t type() const override { return vpiPackage; }
const char* name() const override { return m_name.c_str(); }
const char* fullname() const override { return m_fullname.c_str(); }
};
class VerilatedVpioInstanceIter final : public VerilatedVpio {
const std::vector<const VerilatedScope*>* m_vec;
std::vector<const VerilatedScope*>::const_iterator m_it;
public:
explicit VerilatedVpioInstanceIter(const std::vector<const VerilatedScope*>& vec)
: m_vec{&vec} {
m_it = m_vec->begin();
}
~VerilatedVpioInstanceIter() override = default;
static VerilatedVpioInstanceIter* castp(vpiHandle h) {
return dynamic_cast<VerilatedVpioInstanceIter*>(reinterpret_cast<VerilatedVpio*>(h));
}
uint32_t type() const override { return vpiIterator; }
vpiHandle dovpi_scan() override {
while (true) {
if (m_it == m_vec->end()) {
delete this; // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle
return nullptr;
}
const VerilatedScope::Type type = (*m_it)->type();
const VerilatedScope* const modp = *m_it++;
if (type == VerilatedScope::SCOPE_MODULE) {
return (new VerilatedVpioModule{modp})->castVpiHandle();
}
if (type == VerilatedScope::SCOPE_PACKAGE) {
return (new VerilatedVpioPackage{modp})->castVpiHandle();
}
}
const VerilatedScope* const modp = *m_it++;
return (new VerilatedVpioModule{modp})->castVpiHandle();
}
};
@ -1857,6 +1916,13 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
if (it == map->end()) return nullptr;
return ((new VerilatedVpioModuleIter{it->second})->castVpiHandle());
}
case vpiInstance: {
if (object) return nullptr;
const VerilatedHierarchyMap* const map = VerilatedImp::hierarchyMap();
const auto it = vlstd::as_const(map)->find(nullptr);
if (it == map->end()) return nullptr;
return ((new VerilatedVpioInstanceIter{it->second})->castVpiHandle());
}
default:
VL_VPI_WARNING_(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
__func__, VerilatedVpiError::strFromVpiObjType(type));

View File

@ -318,7 +318,7 @@ class EmitCSyms final : EmitCBaseVisitorConst {
m_scopes.emplace_back(nodep, m_modp);
if (v3Global.opt.vpi() && !nodep->isTop()) {
const string type = VN_IS(nodep->modp(), Package) ? "SCOPE_OTHER" : "SCOPE_MODULE";
const string type = VN_IS(nodep->modp(), Package) ? "SCOPE_PACKAGE" : "SCOPE_MODULE";
const string name_pretty = AstNode::vpiName(nodep->shortName());
const int timeunit = m_modp->timeunit().powerOfTen();
m_vpiScopeCandidates.emplace(
@ -644,7 +644,9 @@ void EmitCSyms::emitScopeHier(bool destroy) {
++it) {
const string name = it->second.m_prettyName;
if (it->first == "TOP") continue;
if ((name.find('.') == string::npos) && (it->second.m_type == "SCOPE_MODULE")) {
const string scopeType = it->second.m_type;
if ((name.find('.') == string::npos)
&& (scopeType == "SCOPE_MODULE" || scopeType == "SCOPE_PACKAGE")) {
puts("__Vhier." + method + "(0, &" + protect("__Vscope_" + it->second.m_symName)
+ ");\n");
}

View File

@ -32,6 +32,7 @@ public:
TestVpiHandle& operator=(vpiHandle h) {
release();
m_handle = h;
m_freeit = true;
return *this;
}
void release() {

View File

@ -0,0 +1,217 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Copyright 2010-2011 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 "sv_vpi_user.h"
#include <cstdlib>
#else
#include "verilated.h"
#include "verilated_vcd_c.h"
#include "verilated_vpi.h"
#include "Vt_vpi_package.h"
#include "Vt_vpi_package__Dpi.h"
#include "svdpi.h"
#endif
#include <cstdio>
#include <cstring>
#include <iostream>
// These require the above. Comment prevents clang-format moving them
#include "TestSimulator.h"
#include "TestVpi.h"
// __FILE__ is too long
#define FILENM "t_vpi_package.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__; \
}
#define CHECK_RESULT_Z(got) \
if (got) { \
printf("%%Error: %s:%d: GOT = !NULL EXP = NULL\n", FILENM, __LINE__); \
return __LINE__; \
}
#define CHECK_RESULT(got, exp) \
if ((got) != (exp)) { \
std::cout << std::dec << "%Error: " << FILENM << ":" << __LINE__ << ": GOT = " << (got) \
<< " EXP = " << (exp) << std::endl; \
return __LINE__; \
}
#define CHECK_RESULT_CSTR(got, exp) \
if (std::strcmp((got), (exp))) { \
printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", FILENM, __LINE__, \
(got) ? (got) : "<null>", (exp) ? (exp) : "<null>"); \
return __LINE__; \
}
extern "C" {
int mon_check() {
#ifdef TEST_VERBOSE
printf("-mon_check()\n");
#endif
TestVpiHandle it = vpi_iterate(vpiModule, NULL);
bool found_t = false;
while (true) {
TestVpiHandle handle = vpi_scan(it);
if (handle == NULL) break;
if (strcmp("t", vpi_get_str(vpiName, handle))) {
return __LINE__;
} else {
if (found_t) return __LINE__;
found_t = true;
}
}
it.freed();
if (!found_t) return __LINE__;
it = vpi_iterate(vpiInstance, NULL);
found_t = false;
bool found_somepackage = false;
bool found_dollar_unit = false;
while (true) {
TestVpiHandle handle = vpi_scan(it);
if (handle == NULL) break;
const char* name = vpi_get_str(vpiName, handle);
const char* fullname = vpi_get_str(vpiFullName, handle);
if (!strcmp("t", name)) {
if (strcmp("t", fullname)) return __LINE__;
if (found_t) return __LINE__;
found_t = true;
} else if (!strcmp("somepackage", name)) {
if (strcmp("somepackage::", fullname)) return __LINE__;
if (found_somepackage) return __LINE__;
found_somepackage = true;
} else if (!strcmp("$unit", name)) {
if (strcmp("$unit::", fullname)) return __LINE__;
if (found_dollar_unit) return __LINE__;
found_dollar_unit = true;
} else {
return __LINE__;
}
}
it.freed();
if (!found_t) return __LINE__;
if (!found_somepackage) return __LINE__;
if (!found_dollar_unit) return __LINE__;
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<VerilatedContext> contextp{new VerilatedContext};
uint64_t sim_time = 1100;
contextp->debug(0);
contextp->commandArgs(argc, argv);
// We're going to be checking for these errors so don't crash out
contextp->fatalOnVpiError(0);
{
// Construct and destroy
const std::unique_ptr<VM_PREFIX> topp{
new VM_PREFIX{contextp.get(),
// Note null name - we're flattening it out
""}};
}
// Test second construction
const std::unique_ptr<VM_PREFIX> topp{new VM_PREFIX{contextp.get(),
// Note null name - we're flattening it out
""}};
#ifdef VERILATOR
#ifdef TEST_VERBOSE
contextp->scopesDump();
#endif
#endif
#if VM_TRACE
contextp->traceEverOn(true);
VL_PRINTF("Enabling waves...\n");
VerilatedVcdC* tfp = new VerilatedVcdC;
topp->trace(tfp, 99);
tfp->open(STRINGIFY(TEST_OBJ_DIR) "/simx.vcd");
#endif
topp->eval();
contextp->timeInc(10);
while (contextp->time() < sim_time && !contextp->gotFinish()) {
contextp->timeInc(1);
topp->eval();
VerilatedVpi::callValueCbs();
// mon_do();
#if VM_TRACE
if (tfp) tfp->dump(contextp->time());
#endif
}
if (!contextp->gotFinish()) {
vl_fatal(FILENM, __LINE__, "main", "%Error: Timeout; never got a $finish");
}
topp->final();
#if VM_TRACE
if (tfp) tfp->close();
#endif
return 0;
}
#endif

29
test_regress/t/t_vpi_package.pl Executable file
View File

@ -0,0 +1,29 @@
#!/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,
verilator_flags2 => ["--exe --vpi --no-l2name $Self->{t_dir}/t_vpi_package.cpp"],
);
execute(
use_libvpi => 1,
check_finished => 1
);
ok(1);
1;

View File

@ -0,0 +1,34 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// 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
import "DPI-C" context function int mon_check();
parameter int dollarUnitInt /*verilator public_flat_rd*/ = 3;
package somepackage;
parameter int someInt /*verilator public_flat_rd*/ = 5;
endpackage
module t (/*AUTOARG*/
); /*verilator public_module*/
parameter int someOtherInt /* verilator public_flat_rd*/ = 7;
integer status;
initial begin
status = mon_check();
if (status!=0) begin
$write("%%Error: t_vpi_package.cpp:%0d: C Test failed\n", status);
$stop;
end
$write("*-* All Finished *-*\n");
$finish;
end
endmodule : t