vpi_iterate packages with vpiInstance (#4726)
This commit is contained in:
parent
feae9ca4aa
commit
9a0748d8ed
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ public:
|
|||
TestVpiHandle& operator=(vpiHandle h) {
|
||||
release();
|
||||
m_handle = h;
|
||||
m_freeit = true;
|
||||
return *this;
|
||||
}
|
||||
void release() {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue