2012-04-13 01:08:20 +00:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2010-12-25 19:39:41 +00:00
|
|
|
//*************************************************************************
|
|
|
|
//
|
2021-01-01 15:29:54 +00:00
|
|
|
// Copyright 2009-2021 by Wilson Snyder. This program is free software; you can
|
2010-12-25 19:39:41 +00:00
|
|
|
// redistribute it and/or modify it under the terms of either the GNU
|
2020-03-21 15:24:24 +00:00
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
2010-12-25 19:39:41 +00:00
|
|
|
// Version 2.0.
|
2020-03-21 15:24:24 +00:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
2010-12-25 19:39:41 +00:00
|
|
|
//
|
|
|
|
//=========================================================================
|
|
|
|
///
|
|
|
|
/// \file
|
|
|
|
/// \brief Verilator: VPI implementation code
|
|
|
|
///
|
2019-05-09 01:13:38 +00:00
|
|
|
/// This file must be compiled and linked against all objects
|
|
|
|
/// created from Verilator or called by Verilator that use the VPI.
|
2010-12-25 19:39:41 +00:00
|
|
|
///
|
2015-09-26 02:57:28 +00:00
|
|
|
/// Use "verilator --vpi" to add this to the Makefile for the linker.
|
|
|
|
///
|
2019-11-08 03:33:59 +00:00
|
|
|
/// Code available from: https://verilator.org
|
2010-12-25 19:39:41 +00:00
|
|
|
///
|
|
|
|
//=========================================================================
|
2019-10-02 01:57:45 +00:00
|
|
|
|
2021-03-04 02:57:07 +00:00
|
|
|
#define VERILATOR_VERILATED_VPI_CPP_
|
2015-09-26 02:57:28 +00:00
|
|
|
|
|
|
|
#include "verilated.h"
|
2010-12-25 19:39:41 +00:00
|
|
|
#include "verilated_vpi.h"
|
2019-10-02 01:57:45 +00:00
|
|
|
#include "verilated_imp.h"
|
2010-12-25 19:39:41 +00:00
|
|
|
|
2017-10-20 01:33:22 +00:00
|
|
|
#include <list>
|
|
|
|
#include <map>
|
2018-10-14 11:04:18 +00:00
|
|
|
#include <set>
|
2017-10-20 01:33:22 +00:00
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
// Internal constants
|
|
|
|
|
|
|
|
#define VL_DEBUG_IF_PLI VL_DEBUG_IF
|
2021-03-04 03:53:50 +00:00
|
|
|
constexpr unsigned VL_VPI_LINE_SIZE_ = 8192;
|
2017-10-20 01:33:22 +00:00
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
// Internal macros
|
|
|
|
|
2021-03-04 03:53:50 +00:00
|
|
|
#define VL_VPI_INTERNAL_ VerilatedVpiImp::error_info()->setMessage(vpiInternal)->setMessage
|
|
|
|
#define VL_VPI_SYSTEM_ VerilatedVpiImp::error_info()->setMessage(vpiSystem)->setMessage
|
|
|
|
#define VL_VPI_ERROR_ VerilatedVpiImp::error_info()->setMessage(vpiError)->setMessage
|
|
|
|
#define VL_VPI_WARNING_ VerilatedVpiImp::error_info()->setMessage(vpiWarning)->setMessage
|
|
|
|
#define VL_VPI_NOTICE_ VerilatedVpiImp::error_info()->setMessage(vpiNotice)->setMessage
|
|
|
|
#define VL_VPI_ERROR_RESET_ VerilatedVpiImp::error_info()->resetError
|
2017-10-20 01:33:22 +00:00
|
|
|
|
|
|
|
// Not supported yet
|
2021-03-04 03:53:50 +00:00
|
|
|
#define VL_VPI_UNIMP_() \
|
|
|
|
(VL_VPI_ERROR_(__FILE__, __LINE__, Verilated::catName("Unsupported VPI function: ", VL_FUNC)))
|
2017-10-20 01:33:22 +00:00
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
// Implementation
|
|
|
|
|
|
|
|
// Base VPI handled object
|
2020-11-19 02:32:16 +00:00
|
|
|
class VerilatedVpio VL_NOT_FINAL {
|
2020-12-17 00:10:17 +00:00
|
|
|
// CONSTANTS
|
|
|
|
/// Magic value stored in front of object to detect double free etc
|
|
|
|
/// Must be odd, as aligned pointer can never be odd
|
|
|
|
static constexpr vluint32_t activeMagic() { return 0xfeed100f; }
|
|
|
|
|
2017-10-20 01:33:22 +00:00
|
|
|
// MEM MANGLEMENT
|
2021-03-05 00:23:40 +00:00
|
|
|
// Internal note: Globals may multi-construct, see verilated.cpp top.
|
2017-10-27 01:51:51 +00:00
|
|
|
static VL_THREAD_LOCAL vluint8_t* t_freeHead;
|
2017-10-20 01:33:22 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
// CONSTRUCTORS
|
2020-11-17 00:56:16 +00:00
|
|
|
VerilatedVpio() = default;
|
|
|
|
virtual ~VerilatedVpio() = default;
|
2020-12-01 23:49:03 +00:00
|
|
|
static void* operator new(size_t size) VL_MT_SAFE {
|
2017-10-20 01:33:22 +00:00
|
|
|
// We new and delete tons of vpi structures, so keep them around
|
|
|
|
// To simplify our free list, we use a size large enough for all derived types
|
|
|
|
// We reserve word zero for the next pointer, as that's safer in case a
|
|
|
|
// dangling reference to the original remains around.
|
2017-10-27 01:51:51 +00:00
|
|
|
static const size_t chunk = 96;
|
2020-04-14 02:51:35 +00:00
|
|
|
if (VL_UNCOVERABLE(size > chunk)) VL_FATAL_MT(__FILE__, __LINE__, "", "increase chunk");
|
2017-10-27 01:51:51 +00:00
|
|
|
if (VL_LIKELY(t_freeHead)) {
|
|
|
|
vluint8_t* newp = t_freeHead;
|
2020-04-04 02:31:54 +00:00
|
|
|
t_freeHead = *(reinterpret_cast<vluint8_t**>(newp));
|
2020-12-17 00:10:17 +00:00
|
|
|
*(reinterpret_cast<vluint32_t*>(newp)) = activeMagic();
|
2020-04-14 02:51:35 +00:00
|
|
|
return newp + 8;
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
2018-10-14 22:39:33 +00:00
|
|
|
// +8: 8 bytes for next
|
2020-04-14 02:51:35 +00:00
|
|
|
vluint8_t* newp = reinterpret_cast<vluint8_t*>(::operator new(chunk + 8));
|
2020-12-17 00:10:17 +00:00
|
|
|
*(reinterpret_cast<vluint32_t*>(newp)) = activeMagic();
|
2020-04-14 02:51:35 +00:00
|
|
|
return newp + 8;
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
2020-12-01 23:49:03 +00:00
|
|
|
static void operator delete(void* obj, size_t /*size*/)VL_MT_SAFE {
|
2020-04-04 02:31:54 +00:00
|
|
|
vluint8_t* oldp = (static_cast<vluint8_t*>(obj)) - 8;
|
2020-12-17 00:10:17 +00:00
|
|
|
if (VL_UNLIKELY(*(reinterpret_cast<vluint32_t*>(oldp)) != activeMagic())) {
|
|
|
|
VL_FATAL_MT(__FILE__, __LINE__, "",
|
|
|
|
"vpi_release_handle() called on same object twice, or on non-Verilator "
|
|
|
|
"VPI object");
|
|
|
|
}
|
2020-12-19 02:16:57 +00:00
|
|
|
#ifdef VL_VPI_IMMEDIATE_FREE // Define to aid in finding leaky handles
|
|
|
|
::operator delete(oldp);
|
|
|
|
#else
|
2020-04-04 02:31:54 +00:00
|
|
|
*(reinterpret_cast<void**>(oldp)) = t_freeHead;
|
2017-10-27 01:51:51 +00:00
|
|
|
t_freeHead = oldp;
|
2020-12-19 02:16:57 +00:00
|
|
|
#endif
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
|
|
|
// MEMBERS
|
2020-12-01 23:49:03 +00:00
|
|
|
static VerilatedVpio* castp(vpiHandle h) {
|
2020-04-04 02:31:54 +00:00
|
|
|
return dynamic_cast<VerilatedVpio*>(reinterpret_cast<VerilatedVpio*>(h));
|
|
|
|
}
|
2017-10-20 01:33:22 +00:00
|
|
|
inline vpiHandle castVpiHandle() { return reinterpret_cast<vpiHandle>(this); }
|
|
|
|
// ACCESSORS
|
|
|
|
virtual const char* name() const { return "<null>"; }
|
|
|
|
virtual const char* fullname() const { return "<null>"; }
|
|
|
|
virtual const char* defname() const { return "<null>"; }
|
|
|
|
virtual vluint32_t type() const { return 0; }
|
|
|
|
virtual vluint32_t size() const { return 0; }
|
2020-08-15 14:12:55 +00:00
|
|
|
virtual const VerilatedRange* rangep() const { return nullptr; }
|
2020-11-11 02:40:14 +00:00
|
|
|
virtual vpiHandle dovpi_scan() { return nullptr; }
|
2020-12-19 02:16:57 +00:00
|
|
|
virtual PLI_INT32 dovpi_remove_cb() { return 0; }
|
2017-10-20 01:33:22 +00:00
|
|
|
};
|
|
|
|
|
2020-12-19 02:16:57 +00:00
|
|
|
class VerilatedVpioTimedCb final : public VerilatedVpio {
|
|
|
|
// A handle to a timed callback created with vpi_register_cb
|
|
|
|
// User can call vpi_remove_cb or vpi_release_handle on it
|
|
|
|
vluint64_t m_id; // Unique id/sequence number to find schedule's event
|
2020-04-14 02:51:35 +00:00
|
|
|
QData m_time;
|
|
|
|
|
2017-10-20 01:33:22 +00:00
|
|
|
public:
|
2020-12-19 02:16:57 +00:00
|
|
|
VerilatedVpioTimedCb(vluint64_t id, QData time)
|
|
|
|
: m_id(id)
|
|
|
|
, m_time{time} {}
|
|
|
|
virtual ~VerilatedVpioTimedCb() override = default;
|
|
|
|
static VerilatedVpioTimedCb* castp(vpiHandle h) {
|
|
|
|
return dynamic_cast<VerilatedVpioTimedCb*>(reinterpret_cast<VerilatedVpioTimedCb*>(h));
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
2020-12-19 02:16:57 +00:00
|
|
|
virtual vluint32_t type() const override { return vpiCallback; }
|
|
|
|
virtual PLI_INT32 dovpi_remove_cb() override;
|
|
|
|
};
|
|
|
|
|
|
|
|
class VerilatedVpioReasonCb final : public VerilatedVpio {
|
|
|
|
// A handle to a non-timed callback created with vpi_register_cb
|
|
|
|
// User can call vpi_remove_cb or vpi_release_handle on it
|
|
|
|
vluint64_t m_id; // Unique id/sequence number to find schedule's event
|
|
|
|
PLI_INT32 m_reason; // VPI callback reason code
|
|
|
|
|
|
|
|
public:
|
|
|
|
// cppcheck-suppress uninitVar // m_value
|
|
|
|
VerilatedVpioReasonCb(vluint64_t id, PLI_INT32 reason)
|
|
|
|
: m_id(id)
|
|
|
|
, m_reason{reason} {}
|
|
|
|
virtual ~VerilatedVpioReasonCb() override = default;
|
|
|
|
static VerilatedVpioReasonCb* castp(vpiHandle h) {
|
|
|
|
return dynamic_cast<VerilatedVpioReasonCb*>(reinterpret_cast<VerilatedVpioReasonCb*>(h));
|
2020-04-04 02:31:54 +00:00
|
|
|
}
|
2020-08-15 15:44:10 +00:00
|
|
|
virtual vluint32_t type() const override { return vpiCallback; }
|
2020-12-19 02:16:57 +00:00
|
|
|
virtual PLI_INT32 dovpi_remove_cb() override;
|
2017-10-20 01:33:22 +00:00
|
|
|
};
|
|
|
|
|
2020-11-19 02:32:16 +00:00
|
|
|
class VerilatedVpioConst final : public VerilatedVpio {
|
2020-04-14 02:51:35 +00:00
|
|
|
vlsint32_t m_num;
|
|
|
|
|
2017-10-20 01:33:22 +00:00
|
|
|
public:
|
2020-04-14 02:51:35 +00:00
|
|
|
explicit VerilatedVpioConst(vlsint32_t num)
|
2020-08-16 13:55:36 +00:00
|
|
|
: m_num{num} {}
|
2020-11-17 00:56:16 +00:00
|
|
|
virtual ~VerilatedVpioConst() override = default;
|
2020-12-01 23:49:03 +00:00
|
|
|
static VerilatedVpioConst* castp(vpiHandle h) {
|
2020-04-04 02:31:54 +00:00
|
|
|
return dynamic_cast<VerilatedVpioConst*>(reinterpret_cast<VerilatedVpio*>(h));
|
|
|
|
}
|
2020-08-15 15:44:10 +00:00
|
|
|
virtual vluint32_t type() const override { return vpiConstant; }
|
2017-10-20 01:33:22 +00:00
|
|
|
vlsint32_t num() const { return m_num; }
|
|
|
|
};
|
|
|
|
|
2020-11-19 02:32:16 +00:00
|
|
|
class VerilatedVpioParam final : public VerilatedVpio {
|
2020-06-12 22:38:01 +00:00
|
|
|
const VerilatedVar* m_varp;
|
|
|
|
const VerilatedScope* m_scopep;
|
|
|
|
|
|
|
|
public:
|
|
|
|
VerilatedVpioParam(const VerilatedVar* varp, const VerilatedScope* scopep)
|
2020-08-16 13:55:36 +00:00
|
|
|
: m_varp{varp}
|
|
|
|
, m_scopep{scopep} {}
|
2020-11-17 00:56:16 +00:00
|
|
|
virtual ~VerilatedVpioParam() override = default;
|
2020-06-12 22:38:01 +00:00
|
|
|
|
2020-12-01 23:49:03 +00:00
|
|
|
static VerilatedVpioParam* castp(vpiHandle h) {
|
2020-06-12 22:38:01 +00:00
|
|
|
return dynamic_cast<VerilatedVpioParam*>(reinterpret_cast<VerilatedVpio*>(h));
|
|
|
|
}
|
2020-08-15 15:44:10 +00:00
|
|
|
virtual vluint32_t type() const override { return vpiParameter; }
|
2020-06-12 22:38:01 +00:00
|
|
|
const VerilatedVar* varp() const { return m_varp; }
|
|
|
|
void* varDatap() const { return m_varp->datap(); }
|
|
|
|
const VerilatedScope* scopep() const { return m_scopep; }
|
2020-08-15 15:44:10 +00:00
|
|
|
virtual const char* name() const override { return m_varp->name(); }
|
|
|
|
virtual const char* fullname() const override {
|
2020-12-02 00:01:20 +00:00
|
|
|
static VL_THREAD_LOCAL std::string t_out;
|
|
|
|
t_out = std::string(m_scopep->name()) + "." + name();
|
|
|
|
return t_out.c_str();
|
2020-06-12 22:38:01 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-11-19 02:32:16 +00:00
|
|
|
class VerilatedVpioRange final : public VerilatedVpio {
|
2017-10-20 01:33:22 +00:00
|
|
|
const VerilatedRange* m_range;
|
2020-04-14 02:51:35 +00:00
|
|
|
|
2017-10-20 01:33:22 +00:00
|
|
|
public:
|
2020-04-14 02:51:35 +00:00
|
|
|
explicit VerilatedVpioRange(const VerilatedRange* range)
|
2020-08-16 13:55:36 +00:00
|
|
|
: m_range{range} {}
|
2020-11-17 00:56:16 +00:00
|
|
|
virtual ~VerilatedVpioRange() override = default;
|
2020-12-01 23:49:03 +00:00
|
|
|
static VerilatedVpioRange* castp(vpiHandle h) {
|
2020-04-04 02:31:54 +00:00
|
|
|
return dynamic_cast<VerilatedVpioRange*>(reinterpret_cast<VerilatedVpio*>(h));
|
|
|
|
}
|
2020-08-15 15:44:10 +00:00
|
|
|
virtual vluint32_t type() const override { return vpiRange; }
|
|
|
|
virtual vluint32_t size() const override { return m_range->elements(); }
|
|
|
|
virtual const VerilatedRange* rangep() const override { return m_range; }
|
2020-12-12 13:11:08 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class VerilatedVpioRangeIter final : public VerilatedVpio {
|
|
|
|
// Only supports 1 dimension
|
|
|
|
const VerilatedRange* m_range;
|
|
|
|
bool m_done = false;
|
|
|
|
|
|
|
|
public:
|
|
|
|
explicit VerilatedVpioRangeIter(const VerilatedRange* range)
|
|
|
|
: m_range{range} {}
|
|
|
|
virtual ~VerilatedVpioRangeIter() override = default;
|
|
|
|
static VerilatedVpioRangeIter* castp(vpiHandle h) {
|
|
|
|
return dynamic_cast<VerilatedVpioRangeIter*>(reinterpret_cast<VerilatedVpio*>(h));
|
|
|
|
}
|
|
|
|
virtual vluint32_t type() const override { return vpiIterator; }
|
2020-08-15 15:44:10 +00:00
|
|
|
virtual vpiHandle dovpi_scan() override {
|
2020-12-19 02:16:57 +00:00
|
|
|
if (VL_UNLIKELY(m_done)) {
|
|
|
|
delete this; // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle
|
|
|
|
return nullptr;
|
|
|
|
}
|
2020-12-12 13:11:08 +00:00
|
|
|
m_done = true;
|
|
|
|
return ((new VerilatedVpioRange(m_range))->castVpiHandle());
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-11-19 02:32:16 +00:00
|
|
|
class VerilatedVpioScope VL_NOT_FINAL : public VerilatedVpio {
|
2019-10-02 22:47:12 +00:00
|
|
|
protected:
|
2020-04-14 02:51:35 +00:00
|
|
|
const VerilatedScope* m_scopep;
|
|
|
|
|
2017-10-20 01:33:22 +00:00
|
|
|
public:
|
|
|
|
explicit VerilatedVpioScope(const VerilatedScope* scopep)
|
2020-08-16 13:55:36 +00:00
|
|
|
: m_scopep{scopep} {}
|
2020-11-17 00:56:16 +00:00
|
|
|
virtual ~VerilatedVpioScope() override = default;
|
2020-12-01 23:49:03 +00:00
|
|
|
static VerilatedVpioScope* castp(vpiHandle h) {
|
2020-04-04 02:31:54 +00:00
|
|
|
return dynamic_cast<VerilatedVpioScope*>(reinterpret_cast<VerilatedVpio*>(h));
|
|
|
|
}
|
2020-08-15 15:44:10 +00:00
|
|
|
virtual vluint32_t type() const override { return vpiScope; }
|
2017-10-20 01:33:22 +00:00
|
|
|
const VerilatedScope* scopep() const { return m_scopep; }
|
2020-08-15 15:44:10 +00:00
|
|
|
virtual const char* name() const override { return m_scopep->name(); }
|
|
|
|
virtual const char* fullname() const override { return m_scopep->name(); }
|
2017-10-20 01:33:22 +00:00
|
|
|
};
|
|
|
|
|
2020-11-19 02:32:16 +00:00
|
|
|
class VerilatedVpioVar VL_NOT_FINAL : public VerilatedVpio {
|
2020-12-19 02:16:57 +00:00
|
|
|
const VerilatedVar* m_varp = nullptr;
|
|
|
|
const VerilatedScope* m_scopep = nullptr;
|
2020-11-15 20:40:35 +00:00
|
|
|
vluint8_t* m_prevDatap = nullptr; // Previous value of data, for cbValueChange
|
2017-10-20 01:33:22 +00:00
|
|
|
union {
|
|
|
|
vluint8_t u8[4];
|
|
|
|
vluint32_t u32;
|
2020-04-14 02:51:35 +00:00
|
|
|
} m_mask; // memoized variable mask
|
2020-12-19 02:16:57 +00:00
|
|
|
vluint32_t m_entSize = 0; // memoized variable size
|
2017-10-20 01:33:22 +00:00
|
|
|
protected:
|
2020-12-19 02:16:57 +00:00
|
|
|
void* m_varDatap = nullptr; // varp()->datap() adjusted for array entries
|
2020-11-15 20:40:35 +00:00
|
|
|
vlsint32_t m_index = 0;
|
2019-05-09 01:13:38 +00:00
|
|
|
const VerilatedRange& get_range() const {
|
2017-10-20 01:33:22 +00:00
|
|
|
// Determine number of dimensions and return outermost
|
2020-04-14 02:51:35 +00:00
|
|
|
return (m_varp->dims() > 1) ? m_varp->unpacked() : m_varp->packed();
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
2020-04-14 02:51:35 +00:00
|
|
|
|
2017-10-20 01:33:22 +00:00
|
|
|
public:
|
|
|
|
VerilatedVpioVar(const VerilatedVar* varp, const VerilatedScope* scopep)
|
2020-08-16 13:55:36 +00:00
|
|
|
: m_varp{varp}
|
2020-11-15 20:40:35 +00:00
|
|
|
, m_scopep{scopep} {
|
2017-12-16 15:52:43 +00:00
|
|
|
m_mask.u32 = VL_MASK_I(varp->packed().elements());
|
2017-10-20 01:33:22 +00:00
|
|
|
m_entSize = varp->entSize();
|
|
|
|
m_varDatap = varp->datap();
|
|
|
|
}
|
2020-12-23 20:21:33 +00:00
|
|
|
explicit VerilatedVpioVar(const VerilatedVpioVar* varp) {
|
2020-12-19 02:16:57 +00:00
|
|
|
if (varp) {
|
|
|
|
m_varp = varp->m_varp;
|
|
|
|
m_scopep = varp->m_scopep;
|
|
|
|
m_mask.u32 = varp->m_mask.u32;
|
|
|
|
m_entSize = varp->m_entSize;
|
|
|
|
m_varDatap = varp->m_varDatap;
|
|
|
|
m_index = varp->m_index;
|
|
|
|
// Not copying m_prevDatap, must be nullptr
|
|
|
|
} else {
|
|
|
|
m_mask.u32 = 0;
|
|
|
|
}
|
|
|
|
}
|
2020-08-15 15:44:10 +00:00
|
|
|
virtual ~VerilatedVpioVar() override {
|
2020-08-15 14:12:55 +00:00
|
|
|
if (m_prevDatap) VL_DO_CLEAR(delete[] m_prevDatap, m_prevDatap = nullptr);
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
2020-12-01 23:49:03 +00:00
|
|
|
static VerilatedVpioVar* castp(vpiHandle h) {
|
2020-04-04 02:31:54 +00:00
|
|
|
return dynamic_cast<VerilatedVpioVar*>(reinterpret_cast<VerilatedVpio*>(h));
|
|
|
|
}
|
2017-10-20 01:33:22 +00:00
|
|
|
const VerilatedVar* varp() const { return m_varp; }
|
|
|
|
const VerilatedScope* scopep() const { return m_scopep; }
|
|
|
|
vluint32_t mask() const { return m_mask.u32; }
|
|
|
|
vluint8_t mask_byte(int idx) { return m_mask.u8[idx & 3]; }
|
|
|
|
vluint32_t entSize() const { return m_entSize; }
|
2020-08-16 18:55:46 +00:00
|
|
|
vluint32_t index() const { return m_index; }
|
2020-08-15 15:44:10 +00:00
|
|
|
virtual vluint32_t type() const override {
|
2020-04-14 02:51:35 +00:00
|
|
|
return (varp()->dims() > 1) ? vpiMemory : vpiReg; // but might be wire, logic
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
2020-08-15 15:44:10 +00:00
|
|
|
virtual vluint32_t size() const override { return get_range().elements(); }
|
|
|
|
virtual const VerilatedRange* rangep() const override { return &get_range(); }
|
|
|
|
virtual const char* name() const override { return m_varp->name(); }
|
|
|
|
virtual const char* fullname() const override {
|
2020-12-02 00:01:20 +00:00
|
|
|
static VL_THREAD_LOCAL std::string t_out;
|
|
|
|
t_out = std::string(m_scopep->name()) + "." + name();
|
|
|
|
return t_out.c_str();
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
|
|
|
void* prevDatap() const { return m_prevDatap; }
|
|
|
|
void* varDatap() const { return m_varDatap; }
|
|
|
|
void createPrevDatap() {
|
|
|
|
if (VL_UNLIKELY(!m_prevDatap)) {
|
2020-04-14 02:51:35 +00:00
|
|
|
m_prevDatap = new vluint8_t[entSize()];
|
2017-10-20 01:33:22 +00:00
|
|
|
memcpy(prevDatap(), varp()->datap(), entSize());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-11-19 02:32:16 +00:00
|
|
|
class VerilatedVpioMemoryWord final : public VerilatedVpioVar {
|
2017-10-20 01:33:22 +00:00
|
|
|
public:
|
|
|
|
VerilatedVpioMemoryWord(const VerilatedVar* varp, const VerilatedScope* scopep,
|
|
|
|
vlsint32_t index, int offset)
|
2020-08-16 13:55:36 +00:00
|
|
|
: VerilatedVpioVar{varp, scopep} {
|
2017-10-20 01:33:22 +00:00
|
|
|
m_index = index;
|
2020-04-04 02:31:54 +00:00
|
|
|
m_varDatap = (static_cast<vluint8_t*>(varp->datap())) + entSize() * offset;
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
2020-11-17 00:56:16 +00:00
|
|
|
virtual ~VerilatedVpioMemoryWord() override = default;
|
2020-12-01 23:49:03 +00:00
|
|
|
static VerilatedVpioMemoryWord* castp(vpiHandle h) {
|
2020-04-04 02:31:54 +00:00
|
|
|
return dynamic_cast<VerilatedVpioMemoryWord*>(reinterpret_cast<VerilatedVpio*>(h));
|
|
|
|
}
|
2020-08-15 15:44:10 +00:00
|
|
|
virtual vluint32_t type() const override { return vpiMemoryWord; }
|
|
|
|
virtual vluint32_t size() const override { return varp()->packed().elements(); }
|
|
|
|
virtual const VerilatedRange* rangep() const override { return &(varp()->packed()); }
|
|
|
|
virtual const char* fullname() const override {
|
2020-12-02 00:01:20 +00:00
|
|
|
static VL_THREAD_LOCAL std::string t_out;
|
2021-03-06 15:33:43 +00:00
|
|
|
char num[25];
|
|
|
|
VL_SNPRINTF(num, 25, "%d", m_index);
|
2020-12-02 00:01:20 +00:00
|
|
|
t_out = std::string(scopep()->name()) + "." + name() + "[" + num + "]";
|
|
|
|
return t_out.c_str();
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-11-19 02:32:16 +00:00
|
|
|
class VerilatedVpioVarIter final : public VerilatedVpio {
|
2020-04-14 02:51:35 +00:00
|
|
|
const VerilatedScope* m_scopep;
|
2017-10-20 01:33:22 +00:00
|
|
|
VerilatedVarNameMap::const_iterator m_it;
|
2020-08-16 13:55:36 +00:00
|
|
|
bool m_started = false;
|
2020-04-14 02:51:35 +00:00
|
|
|
|
2017-10-20 01:33:22 +00:00
|
|
|
public:
|
|
|
|
explicit VerilatedVpioVarIter(const VerilatedScope* scopep)
|
2020-08-16 13:55:36 +00:00
|
|
|
: m_scopep{scopep} {}
|
2020-11-17 00:56:16 +00:00
|
|
|
virtual ~VerilatedVpioVarIter() override = default;
|
2020-12-01 23:49:03 +00:00
|
|
|
static VerilatedVpioVarIter* castp(vpiHandle h) {
|
2020-04-04 02:31:54 +00:00
|
|
|
return dynamic_cast<VerilatedVpioVarIter*>(reinterpret_cast<VerilatedVpio*>(h));
|
|
|
|
}
|
2020-08-15 15:44:10 +00:00
|
|
|
virtual vluint32_t type() const override { return vpiIterator; }
|
|
|
|
virtual vpiHandle dovpi_scan() override {
|
2017-10-20 01:33:22 +00:00
|
|
|
if (VL_LIKELY(m_scopep->varsp())) {
|
|
|
|
VerilatedVarNameMap* varsp = m_scopep->varsp();
|
2020-04-14 02:51:35 +00:00
|
|
|
if (VL_UNLIKELY(!m_started)) {
|
|
|
|
m_it = varsp->begin();
|
|
|
|
m_started = true;
|
|
|
|
} else if (VL_UNLIKELY(m_it == varsp->end())) {
|
2020-12-19 02:16:57 +00:00
|
|
|
delete this; // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle
|
2020-11-11 02:40:14 +00:00
|
|
|
return nullptr;
|
2020-04-14 02:51:35 +00:00
|
|
|
} else {
|
|
|
|
++m_it;
|
|
|
|
}
|
2020-12-19 02:16:57 +00:00
|
|
|
if (VL_UNLIKELY(m_it == varsp->end())) {
|
|
|
|
delete this; // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle
|
|
|
|
return nullptr;
|
|
|
|
}
|
2020-04-14 02:51:35 +00:00
|
|
|
return ((new VerilatedVpioVar(&(m_it->second), m_scopep))->castVpiHandle());
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
2020-12-19 02:16:57 +00:00
|
|
|
delete this; // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle
|
2020-11-11 02:40:14 +00:00
|
|
|
return nullptr; // End of list - only one deep
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-11-19 02:32:16 +00:00
|
|
|
class VerilatedVpioMemoryWordIter final : public VerilatedVpio {
|
2020-04-14 02:51:35 +00:00
|
|
|
const vpiHandle m_handle;
|
|
|
|
const VerilatedVar* m_varp;
|
|
|
|
vlsint32_t m_iteration;
|
|
|
|
vlsint32_t m_direction;
|
2020-08-16 13:55:36 +00:00
|
|
|
bool m_done = false;
|
2020-04-14 02:51:35 +00:00
|
|
|
|
2017-10-20 01:33:22 +00:00
|
|
|
public:
|
|
|
|
VerilatedVpioMemoryWordIter(const vpiHandle handle, const VerilatedVar* varp)
|
2020-08-16 13:55:36 +00:00
|
|
|
: m_handle{handle}
|
|
|
|
, m_varp{varp}
|
|
|
|
, m_iteration{varp->unpacked().right()}
|
|
|
|
, m_direction{VL_LIKELY(varp->unpacked().left() > varp->unpacked().right()) ? 1 : -1} {}
|
2020-11-17 00:56:16 +00:00
|
|
|
virtual ~VerilatedVpioMemoryWordIter() override = default;
|
2020-12-01 23:49:03 +00:00
|
|
|
static VerilatedVpioMemoryWordIter* castp(vpiHandle h) {
|
2020-04-04 02:31:54 +00:00
|
|
|
return dynamic_cast<VerilatedVpioMemoryWordIter*>(reinterpret_cast<VerilatedVpio*>(h));
|
|
|
|
}
|
2020-08-15 15:44:10 +00:00
|
|
|
virtual vluint32_t type() const override { return vpiIterator; }
|
2017-10-20 01:33:22 +00:00
|
|
|
void iterationInc() {
|
2020-04-14 02:51:35 +00:00
|
|
|
if (!(m_done = (m_iteration == m_varp->unpacked().left()))) m_iteration += m_direction;
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
2020-08-15 15:44:10 +00:00
|
|
|
virtual vpiHandle dovpi_scan() override {
|
2020-12-19 02:16:57 +00:00
|
|
|
if (VL_UNLIKELY(m_done)) {
|
|
|
|
delete this; // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
vpiHandle result = vpi_handle_by_index(m_handle, m_iteration);
|
2017-10-20 01:33:22 +00:00
|
|
|
iterationInc();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-11-19 02:32:16 +00:00
|
|
|
class VerilatedVpioModule final : public VerilatedVpioScope {
|
2019-10-02 01:57:45 +00:00
|
|
|
const char* m_name;
|
|
|
|
const char* m_fullname;
|
2020-04-14 02:51:35 +00:00
|
|
|
|
2019-10-02 01:57:45 +00:00
|
|
|
public:
|
|
|
|
explicit VerilatedVpioModule(const VerilatedScope* modulep)
|
2020-08-16 13:55:36 +00:00
|
|
|
: VerilatedVpioScope{modulep} {
|
2019-10-02 22:47:12 +00:00
|
|
|
m_fullname = m_scopep->name();
|
2019-10-02 01:57:45 +00:00
|
|
|
if (strncmp(m_fullname, "TOP.", 4) == 0) m_fullname += 4;
|
2019-10-02 22:47:12 +00:00
|
|
|
m_name = m_scopep->identifier();
|
2019-10-02 01:57:45 +00:00
|
|
|
}
|
2020-12-01 23:49:03 +00:00
|
|
|
static VerilatedVpioModule* castp(vpiHandle h) {
|
2020-04-04 02:31:54 +00:00
|
|
|
return dynamic_cast<VerilatedVpioModule*>(reinterpret_cast<VerilatedVpio*>(h));
|
|
|
|
}
|
2020-08-15 15:44:10 +00:00
|
|
|
virtual vluint32_t type() const override { return vpiModule; }
|
|
|
|
virtual const char* name() const override { return m_name; }
|
|
|
|
virtual const char* fullname() const override { return m_fullname; }
|
2019-10-02 01:57:45 +00:00
|
|
|
};
|
|
|
|
|
2020-11-19 02:32:16 +00:00
|
|
|
class VerilatedVpioModuleIter final : public VerilatedVpio {
|
2020-04-14 02:51:35 +00:00
|
|
|
const std::vector<const VerilatedScope*>* m_vec;
|
2019-10-02 01:57:45 +00:00
|
|
|
std::vector<const VerilatedScope*>::const_iterator m_it;
|
2020-04-14 02:51:35 +00:00
|
|
|
|
2019-10-02 01:57:45 +00:00
|
|
|
public:
|
2020-04-14 02:51:35 +00:00
|
|
|
explicit VerilatedVpioModuleIter(const std::vector<const VerilatedScope*>& vec)
|
2020-08-16 13:55:36 +00:00
|
|
|
: m_vec{&vec} {
|
2019-10-02 01:57:45 +00:00
|
|
|
m_it = m_vec->begin();
|
|
|
|
}
|
2020-11-17 00:56:16 +00:00
|
|
|
virtual ~VerilatedVpioModuleIter() override = default;
|
2020-12-01 23:49:03 +00:00
|
|
|
static VerilatedVpioModuleIter* castp(vpiHandle h) {
|
2020-04-04 02:31:54 +00:00
|
|
|
return dynamic_cast<VerilatedVpioModuleIter*>(reinterpret_cast<VerilatedVpio*>(h));
|
|
|
|
}
|
2020-08-15 15:44:10 +00:00
|
|
|
virtual vluint32_t type() const override { return vpiIterator; }
|
|
|
|
virtual vpiHandle dovpi_scan() override {
|
2020-12-19 02:16:57 +00:00
|
|
|
if (m_it == m_vec->end()) {
|
|
|
|
delete this; // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle
|
|
|
|
return nullptr;
|
|
|
|
}
|
2019-10-02 01:57:45 +00:00
|
|
|
const VerilatedScope* modp = *m_it++;
|
|
|
|
return (new VerilatedVpioModule(modp))->castVpiHandle();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-10-20 01:33:22 +00:00
|
|
|
//======================================================================
|
|
|
|
|
2020-12-19 02:16:57 +00:00
|
|
|
typedef PLI_INT32 (*VerilatedPliCb)(struct t_cb_data*);
|
|
|
|
|
|
|
|
class VerilatedVpiCbHolder final {
|
|
|
|
// Holds information needed to call a callback
|
|
|
|
vluint64_t m_id;
|
|
|
|
s_cb_data m_cbData;
|
|
|
|
s_vpi_value m_value;
|
|
|
|
VerilatedVpioVar m_varo; // If a cbValueChange callback, the object we will return
|
|
|
|
|
|
|
|
public:
|
|
|
|
// cppcheck-suppress uninitVar // m_value
|
|
|
|
VerilatedVpiCbHolder(vluint64_t id, const s_cb_data* cbDatap, const VerilatedVpioVar* varop)
|
|
|
|
: m_id(id)
|
|
|
|
, m_cbData(*cbDatap)
|
|
|
|
, m_varo(varop) {
|
|
|
|
m_value.format = cbDatap->value ? cbDatap->value->format : vpiSuppressVal;
|
|
|
|
m_cbData.value = &m_value;
|
|
|
|
if (varop) {
|
|
|
|
m_cbData.obj = m_varo.castVpiHandle();
|
|
|
|
m_varo.createPrevDatap();
|
|
|
|
} else {
|
|
|
|
m_cbData.obj = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
~VerilatedVpiCbHolder() = default;
|
|
|
|
VerilatedPliCb cb_rtnp() const { return m_cbData.cb_rtn; }
|
|
|
|
s_cb_data* cb_datap() { return &m_cbData; }
|
|
|
|
vluint64_t id() const { return m_id; }
|
|
|
|
bool invalid() const { return !m_id; }
|
|
|
|
void invalidate() { m_id = 0; }
|
|
|
|
};
|
|
|
|
|
2017-10-20 01:33:22 +00:00
|
|
|
struct VerilatedVpiTimedCbsCmp {
|
2020-12-19 02:16:57 +00:00
|
|
|
/// Ordering sets keyed by time, then callback unique id
|
|
|
|
bool operator()(const std::pair<QData, vluint64_t>& a,
|
|
|
|
const std::pair<QData, vluint64_t>& b) const {
|
2020-06-02 03:16:02 +00:00
|
|
|
if (a.first < b.first) return true;
|
|
|
|
if (a.first > b.first) return false;
|
2017-10-20 01:33:22 +00:00
|
|
|
return a.second < b.second;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class VerilatedVpiError;
|
|
|
|
|
2020-11-19 02:32:16 +00:00
|
|
|
class VerilatedVpiImp final {
|
2020-04-14 02:51:35 +00:00
|
|
|
enum { CB_ENUM_MAX_VALUE = cbAtEndOfSimTime + 1 }; // Maxium callback reason
|
2020-12-19 02:16:57 +00:00
|
|
|
typedef std::list<VerilatedVpiCbHolder> VpioCbList;
|
|
|
|
typedef std::map<std::pair<QData, vluint64_t>, VerilatedVpiCbHolder> VpioTimedCbs;
|
2017-10-20 01:33:22 +00:00
|
|
|
|
2021-03-05 00:23:40 +00:00
|
|
|
// All only medium-speed, so use singleton function
|
2020-04-14 02:51:35 +00:00
|
|
|
VpioCbList m_cbObjLists[CB_ENUM_MAX_VALUE]; // Callbacks for each supported reason
|
|
|
|
VpioTimedCbs m_timedCbs; // Time based callbacks
|
2020-08-15 17:11:27 +00:00
|
|
|
VerilatedVpiError* m_errorInfop = nullptr; // Container for vpi error info
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
2020-12-19 02:16:57 +00:00
|
|
|
vluint64_t m_nextCallbackId = 1; // Id to identify callback
|
2017-10-20 01:33:22 +00:00
|
|
|
|
2021-03-05 00:23:40 +00:00
|
|
|
static VerilatedVpiImp& s() { // Singleton
|
|
|
|
static VerilatedVpiImp s_s;
|
|
|
|
return s_s;
|
|
|
|
}
|
2017-10-20 01:33:22 +00:00
|
|
|
|
|
|
|
public:
|
2021-03-05 00:23:40 +00:00
|
|
|
static void assertOneCheck() { s().m_assertOne.check(); }
|
|
|
|
static vluint64_t nextCallbackId() { return ++s().m_nextCallbackId; }
|
2020-12-19 02:16:57 +00:00
|
|
|
|
|
|
|
static void cbReasonAdd(vluint64_t id, const s_cb_data* cb_data_p) {
|
|
|
|
// The passed cb_data_p was property of the user, so need to recreate
|
|
|
|
if (VL_UNCOVERABLE(cb_data_p->reason >= CB_ENUM_MAX_VALUE)) {
|
2019-05-09 01:13:38 +00:00
|
|
|
VL_FATAL_MT(__FILE__, __LINE__, "", "vpi bb reason too large");
|
2018-03-10 21:32:04 +00:00
|
|
|
}
|
2020-12-19 02:16:57 +00:00
|
|
|
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_register_cb reason=%d id=%" VL_PRI64 "d obj=%p\n",
|
|
|
|
cb_data_p->reason, id, cb_data_p->obj););
|
|
|
|
VerilatedVpioVar* varop = nullptr;
|
|
|
|
if (cb_data_p->reason == cbValueChange) varop = VerilatedVpioVar::castp(cb_data_p->obj);
|
2021-03-05 00:23:40 +00:00
|
|
|
s().m_cbObjLists[cb_data_p->reason].emplace_back(id, cb_data_p, varop);
|
2020-12-19 02:16:57 +00:00
|
|
|
}
|
|
|
|
static void cbTimedAdd(vluint64_t id, const s_cb_data* cb_data_p, QData time) {
|
|
|
|
// The passed cb_data_p was property of the user, so need to recreate
|
|
|
|
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_register_cb reason=%d id=%" VL_PRI64
|
|
|
|
"d delay=%" VL_PRI64 "u\n",
|
|
|
|
cb_data_p->reason, id, time););
|
2021-03-05 00:23:40 +00:00
|
|
|
s().m_timedCbs.emplace(std::piecewise_construct,
|
2020-12-19 02:16:57 +00:00
|
|
|
std::forward_as_tuple(std::make_pair(time, id)),
|
|
|
|
std::forward_as_tuple(id, cb_data_p, nullptr));
|
|
|
|
}
|
|
|
|
static void cbReasonRemove(vluint64_t id, vluint32_t reason) {
|
|
|
|
// Id might no longer exist, if already removed due to call after event, or teardown
|
2021-03-05 00:23:40 +00:00
|
|
|
VpioCbList& cbObjList = s().m_cbObjLists[reason];
|
2017-10-20 01:33:22 +00:00
|
|
|
// We do not remove it now as we may be iterating the list,
|
2020-08-15 14:12:55 +00:00
|
|
|
// instead set to nullptr and will cleanup later
|
2020-08-16 15:43:49 +00:00
|
|
|
for (auto& ir : cbObjList) {
|
2020-12-19 02:16:57 +00:00
|
|
|
if (ir.id() == id) ir.invalidate();
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
|
|
|
}
|
2020-12-19 02:16:57 +00:00
|
|
|
static void cbTimedRemove(vluint64_t id, QData time) {
|
|
|
|
// Id might no longer exist, if already removed due to call after event, or teardown
|
2021-03-05 00:23:40 +00:00
|
|
|
const auto it = s().m_timedCbs.find(std::make_pair(time, id));
|
|
|
|
if (VL_LIKELY(it != s().m_timedCbs.end())) it->second.invalidate();
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
2017-10-27 01:51:51 +00:00
|
|
|
static void callTimedCbs() VL_MT_UNSAFE_ONE {
|
|
|
|
assertOneCheck();
|
2017-10-20 01:33:22 +00:00
|
|
|
QData time = VL_TIME_Q();
|
2021-03-05 00:23:40 +00:00
|
|
|
for (auto it = s().m_timedCbs.begin(); it != s().m_timedCbs.end();) {
|
2020-12-19 02:16:57 +00:00
|
|
|
if (VL_UNLIKELY(it->first.first <= time)) {
|
|
|
|
VerilatedVpiCbHolder& ho = it->second;
|
2020-08-16 15:43:49 +00:00
|
|
|
const auto last_it = it;
|
2020-12-19 02:16:57 +00:00
|
|
|
++it;
|
|
|
|
if (VL_UNLIKELY(!ho.invalid())) {
|
|
|
|
VL_DEBUG_IF_PLI(
|
|
|
|
VL_DBG_MSGF("- vpi: timed_callback id=%" VL_PRI64 "d\n", ho.id()););
|
|
|
|
ho.invalidate(); // Timed callbacks are one-shot
|
|
|
|
(ho.cb_rtnp())(ho.cb_datap());
|
|
|
|
}
|
2021-03-05 00:23:40 +00:00
|
|
|
s().m_timedCbs.erase(last_it);
|
2020-04-14 02:51:35 +00:00
|
|
|
} else {
|
|
|
|
++it;
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static QData cbNextDeadline() {
|
2021-03-05 00:23:40 +00:00
|
|
|
const auto it = s().m_timedCbs.cbegin();
|
|
|
|
if (VL_LIKELY(it != s().m_timedCbs.cend())) return it->first.first;
|
2020-05-29 00:32:07 +00:00
|
|
|
return ~0ULL; // maxquad
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
2019-09-21 11:43:20 +00:00
|
|
|
static bool callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE {
|
2021-03-05 00:23:40 +00:00
|
|
|
VpioCbList& cbObjList = s().m_cbObjLists[reason];
|
2019-09-21 11:43:20 +00:00
|
|
|
bool called = false;
|
2020-11-17 22:19:51 +00:00
|
|
|
if (cbObjList.empty()) return called;
|
|
|
|
const auto last = std::prev(cbObjList.end()); // prevent looping over newly added elements
|
|
|
|
for (auto it = cbObjList.begin(); true;) {
|
|
|
|
// cbReasonRemove sets to nullptr, so we know on removal the old end() will still exist
|
|
|
|
bool was_last = it == last;
|
2020-12-19 02:16:57 +00:00
|
|
|
if (VL_UNLIKELY(it->invalid())) { // Deleted earlier, cleanup
|
2017-10-20 01:33:22 +00:00
|
|
|
it = cbObjList.erase(it);
|
2020-11-17 22:19:51 +00:00
|
|
|
if (was_last) break;
|
2017-10-20 01:33:22 +00:00
|
|
|
continue;
|
|
|
|
}
|
2020-12-19 02:16:57 +00:00
|
|
|
VerilatedVpiCbHolder& ho = *it;
|
|
|
|
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: reason_callback reason=%d id=%" VL_PRI64 "d\n",
|
|
|
|
reason, ho.id()););
|
|
|
|
(ho.cb_rtnp())(ho.cb_datap());
|
2019-09-21 11:43:20 +00:00
|
|
|
called = true;
|
2020-11-17 22:19:51 +00:00
|
|
|
if (was_last) break;
|
2020-12-19 02:16:57 +00:00
|
|
|
++it;
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
2019-09-21 11:43:20 +00:00
|
|
|
return called;
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
2020-10-27 01:55:27 +00:00
|
|
|
static bool callValueCbs() VL_MT_UNSAFE_ONE {
|
2017-10-27 01:51:51 +00:00
|
|
|
assertOneCheck();
|
2021-03-05 00:23:40 +00:00
|
|
|
VpioCbList& cbObjList = s().m_cbObjLists[cbValueChange];
|
2020-10-27 01:55:27 +00:00
|
|
|
bool called = false;
|
2020-11-26 01:57:30 +00:00
|
|
|
typedef std::unordered_set<VerilatedVpioVar*> VpioVarSet;
|
2017-10-20 01:33:22 +00:00
|
|
|
VpioVarSet update; // set of objects to update after callbacks
|
2020-11-17 22:19:51 +00:00
|
|
|
if (cbObjList.empty()) return called;
|
|
|
|
const auto last = std::prev(cbObjList.end()); // prevent looping over newly added elements
|
|
|
|
for (auto it = cbObjList.begin(); true;) {
|
|
|
|
// cbReasonRemove sets to nullptr, so we know on removal the old end() will still exist
|
|
|
|
bool was_last = it == last;
|
2020-12-19 02:16:57 +00:00
|
|
|
if (VL_UNLIKELY(it->invalid())) { // Deleted earlier, cleanup
|
2017-10-20 01:33:22 +00:00
|
|
|
it = cbObjList.erase(it);
|
2020-11-17 22:19:51 +00:00
|
|
|
if (was_last) break;
|
2017-10-20 01:33:22 +00:00
|
|
|
continue;
|
|
|
|
}
|
2020-12-19 02:16:57 +00:00
|
|
|
VerilatedVpiCbHolder& ho = *it++;
|
|
|
|
if (VerilatedVpioVar* varop = VerilatedVpioVar::castp(ho.cb_datap()->obj)) {
|
2017-10-20 01:33:22 +00:00
|
|
|
void* newDatap = varop->varDatap();
|
|
|
|
void* prevDatap = varop->prevDatap(); // Was malloced when we added the callback
|
2017-10-25 02:56:58 +00:00
|
|
|
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: value_test %s v[0]=%d/%d %p %p\n",
|
2020-04-14 02:51:35 +00:00
|
|
|
varop->fullname(), *((CData*)newDatap),
|
|
|
|
*((CData*)prevDatap), newDatap, prevDatap););
|
2020-04-04 02:31:54 +00:00
|
|
|
if (memcmp(prevDatap, newDatap, varop->entSize()) != 0) {
|
2020-12-19 02:16:57 +00:00
|
|
|
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: value_callback %" VL_PRI64
|
|
|
|
"d %s v[0]=%d\n",
|
|
|
|
ho.id(), varop->fullname(), *((CData*)newDatap)););
|
2017-10-20 01:33:22 +00:00
|
|
|
update.insert(varop);
|
2020-12-19 02:16:57 +00:00
|
|
|
vpi_get_value(ho.cb_datap()->obj, ho.cb_datap()->value);
|
|
|
|
(ho.cb_rtnp())(ho.cb_datap());
|
2020-10-27 01:55:27 +00:00
|
|
|
called = true;
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
|
|
|
}
|
2020-11-17 22:19:51 +00:00
|
|
|
if (was_last) break;
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
2020-08-16 15:43:49 +00:00
|
|
|
for (const auto& ip : update) { memcpy(ip->prevDatap(), ip->varDatap(), ip->entSize()); }
|
2020-10-27 01:55:27 +00:00
|
|
|
return called;
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
|
|
|
|
2017-10-27 01:51:51 +00:00
|
|
|
static VerilatedVpiError* error_info() VL_MT_UNSAFE_ONE; // getter for vpi error info
|
2017-10-20 01:33:22 +00:00
|
|
|
};
|
|
|
|
|
2021-03-05 00:23:40 +00:00
|
|
|
//======================================================================
|
|
|
|
// Statics
|
|
|
|
// Internal note: Globals may multi-construct, see verilated.cpp top.
|
|
|
|
|
|
|
|
VL_THREAD_LOCAL vluint8_t* VerilatedVpio::t_freeHead = nullptr;
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
// VerilatedVpiError
|
|
|
|
/// Internal container for vpi error info
|
2017-10-20 01:33:22 +00:00
|
|
|
|
2021-03-05 00:23:40 +00:00
|
|
|
class VerilatedVpiError final {
|
2017-10-20 01:33:22 +00:00
|
|
|
t_vpi_error_info m_errorInfo;
|
2020-08-16 13:55:36 +00:00
|
|
|
bool m_flag = false;
|
2021-03-04 03:53:50 +00:00
|
|
|
char m_buff[VL_VPI_LINE_SIZE_];
|
2020-04-14 02:51:35 +00:00
|
|
|
void setError(PLI_BYTE8* message, PLI_BYTE8* code, PLI_BYTE8* file, PLI_INT32 line) {
|
2017-10-20 01:33:22 +00:00
|
|
|
m_errorInfo.message = message;
|
|
|
|
m_errorInfo.file = file;
|
|
|
|
m_errorInfo.line = line;
|
|
|
|
m_errorInfo.code = code;
|
|
|
|
do_callbacks();
|
|
|
|
}
|
|
|
|
void do_callbacks() {
|
|
|
|
if (getError()->level >= vpiError && Verilated::fatalOnVpiError()) {
|
|
|
|
// Stop on vpi error/unsupported
|
|
|
|
vpi_unsupported();
|
|
|
|
}
|
2019-05-15 02:49:21 +00:00
|
|
|
// We need to run above code first because in the case that the
|
|
|
|
// callback executes further vpi functions we will loose the error
|
|
|
|
// as it will be overwritten.
|
2017-10-20 01:33:22 +00:00
|
|
|
VerilatedVpiImp::callCbs(cbPLIError);
|
|
|
|
}
|
|
|
|
|
2020-04-14 02:51:35 +00:00
|
|
|
public:
|
2020-08-16 13:55:36 +00:00
|
|
|
VerilatedVpiError() {
|
2017-10-20 01:33:22 +00:00
|
|
|
m_buff[0] = '\0';
|
2020-04-04 02:31:54 +00:00
|
|
|
m_errorInfo.product = const_cast<PLI_BYTE8*>(Verilated::productName());
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
2020-11-17 00:56:16 +00:00
|
|
|
~VerilatedVpiError() = default;
|
2017-10-27 01:51:51 +00:00
|
|
|
static void selfTest() VL_MT_UNSAFE_ONE;
|
2017-10-20 01:33:22 +00:00
|
|
|
VerilatedVpiError* setMessage(PLI_INT32 level) {
|
2019-05-09 01:13:38 +00:00
|
|
|
m_flag = true;
|
2017-10-20 01:33:22 +00:00
|
|
|
m_errorInfo.level = level;
|
|
|
|
return this;
|
|
|
|
}
|
2020-04-04 02:31:54 +00:00
|
|
|
void setMessage(const std::string& file, PLI_INT32 line, const char* message, ...) {
|
2018-06-13 01:14:20 +00:00
|
|
|
// message cannot be a const string& as va_start cannot use a reference
|
2020-12-02 00:01:20 +00:00
|
|
|
static VL_THREAD_LOCAL std::string t_filehold;
|
2017-10-20 01:33:22 +00:00
|
|
|
va_list args;
|
|
|
|
va_start(args, message);
|
2018-06-13 01:14:20 +00:00
|
|
|
VL_VSNPRINTF(m_buff, sizeof(m_buff), message, args);
|
2017-10-20 01:33:22 +00:00
|
|
|
va_end(args);
|
|
|
|
m_errorInfo.state = vpiPLI;
|
2020-12-02 00:01:20 +00:00
|
|
|
t_filehold = file;
|
|
|
|
setError((PLI_BYTE8*)m_buff, nullptr, const_cast<PLI_BYTE8*>(t_filehold.c_str()), line);
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
|
|
|
p_vpi_error_info getError() {
|
|
|
|
if (m_flag) return &m_errorInfo;
|
2020-08-15 14:12:55 +00:00
|
|
|
return nullptr;
|
2017-10-20 01:33:22 +00:00
|
|
|
}
|
2019-05-09 01:13:38 +00:00
|
|
|
void resetError() { m_flag = false; }
|
2017-10-20 01:33:22 +00:00
|
|
|
static void vpi_unsupported() {
|
|
|
|
// Not supported yet
|
|
|
|
p_vpi_error_info error_info_p = VerilatedVpiImp::error_info()->getError();
|
|
|
|
if (error_info_p) {
|
|
|
|
VL_FATAL_MT(error_info_p->file, error_info_p->line, "", error_info_p->message);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
VL_FATAL_MT(__FILE__, __LINE__, "", "vpi_unsupported called without error info set");
|
|
|
|
}
|
2017-10-27 01:51:51 +00:00
|
|
|
static const char* strFromVpiVal(PLI_INT32 vpiVal) VL_MT_SAFE;
|
|
|
|
static const char* strFromVpiObjType(PLI_INT32 vpiVal) VL_MT_SAFE;
|
|
|
|
static const char* strFromVpiMethod(PLI_INT32 vpiVal) VL_MT_SAFE;
|
|
|
|
static const char* strFromVpiCallbackReason(PLI_INT32 vpiVal) VL_MT_SAFE;
|
|
|
|
static const char* strFromVpiProp(PLI_INT32 vpiVal) VL_MT_SAFE;
|
2017-10-20 01:33:22 +00:00
|
|
|
};
|
|
|
|
|
2010-12-25 19:39:41 +00:00
|
|
|
//======================================================================
|
2017-10-20 01:33:22 +00:00
|
|
|
// VerilatedVpi implementation
|
2015-09-26 02:57:28 +00:00
|
|
|
|
2020-04-14 02:51:35 +00:00
|
|
|
void VerilatedVpi::callTimedCbs() VL_MT_UNSAFE_ONE { VerilatedVpiImp::callTimedCbs(); }
|
2015-09-26 02:57:28 +00:00
|
|
|
|
2020-10-27 01:55:27 +00:00
|
|
|
bool VerilatedVpi::callValueCbs() VL_MT_UNSAFE_ONE { return VerilatedVpiImp::callValueCbs(); }
|
2017-10-20 01:33:22 +00:00
|
|
|
|
2019-09-21 11:43:20 +00:00
|
|
|
bool VerilatedVpi::callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE {
|
|
|
|
return VerilatedVpiImp::callCbs(reason);
|
|
|
|
}
|
|
|
|
|
2020-04-14 02:51:35 +00:00
|
|
|
QData VerilatedVpi::cbNextDeadline() VL_MT_UNSAFE_ONE { return VerilatedVpiImp::cbNextDeadline(); }
|
2020-03-28 17:47:21 +00:00
|
|
|
|
2020-12-19 02:16:57 +00:00
|
|
|
PLI_INT32 VerilatedVpioTimedCb::dovpi_remove_cb() {
|
|
|
|
VerilatedVpiImp::cbTimedRemove(m_id, m_time);
|
|
|
|
delete this; // IEEE 37.2.2 a vpi_remove_cb does a vpi_release_handle
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
PLI_INT32 VerilatedVpioReasonCb::dovpi_remove_cb() {
|
|
|
|
VerilatedVpiImp::cbReasonRemove(m_id, m_reason);
|
|
|
|
delete this; // IEEE 37.2.2 a vpi_remove_cb does a vpi_release_handle
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-10-20 01:33:22 +00:00
|
|
|
//======================================================================
|
|
|
|
// VerilatedVpiImp implementation
|
|
|
|
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedVpiError* VerilatedVpiImp::error_info() VL_MT_UNSAFE_ONE {
|
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2021-03-05 00:23:40 +00:00
|
|
|
if (VL_UNLIKELY(!s().m_errorInfop)) s().m_errorInfop = new VerilatedVpiError();
|
|
|
|
return s().m_errorInfop;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
// VerilatedVpiError Methods
|
2013-01-18 02:40:37 +00:00
|
|
|
|
2017-10-27 00:05:42 +00:00
|
|
|
const char* VerilatedVpiError::strFromVpiVal(PLI_INT32 vpiVal) VL_MT_SAFE {
|
2020-04-14 02:51:35 +00:00
|
|
|
// clang-format off
|
2017-10-11 00:16:35 +00:00
|
|
|
static const char* const names[] = {
|
2013-01-18 02:40:37 +00:00
|
|
|
"*undefined*",
|
|
|
|
"vpiBinStrVal",
|
|
|
|
"vpiOctStrVal",
|
|
|
|
"vpiDecStrVal",
|
|
|
|
"vpiHexStrVal",
|
|
|
|
"vpiScalarVal",
|
|
|
|
"vpiIntVal",
|
|
|
|
"vpiRealVal",
|
|
|
|
"vpiStringVal",
|
|
|
|
"vpiVectorVal",
|
|
|
|
"vpiStrengthVal",
|
|
|
|
"vpiTimeVal",
|
|
|
|
"vpiObjTypeVal",
|
|
|
|
"vpiSuppressVal",
|
|
|
|
"vpiShortIntVal",
|
|
|
|
"vpiLongIntVal",
|
|
|
|
"vpiShortRealVal",
|
|
|
|
"vpiRawTwoStateVal",
|
|
|
|
"vpiRawFourStateVal",
|
|
|
|
};
|
2020-04-14 02:51:35 +00:00
|
|
|
// clang-format on
|
2020-06-04 23:49:18 +00:00
|
|
|
if (VL_UNCOVERABLE(vpiVal < 0)) return names[0];
|
2020-04-14 02:51:35 +00:00
|
|
|
return names[(vpiVal <= vpiRawFourStateVal) ? vpiVal : 0];
|
2013-01-18 02:40:37 +00:00
|
|
|
}
|
2017-10-27 00:05:42 +00:00
|
|
|
const char* VerilatedVpiError::strFromVpiObjType(PLI_INT32 vpiVal) VL_MT_SAFE {
|
2020-04-14 02:51:35 +00:00
|
|
|
// clang-format off
|
2017-10-11 00:16:35 +00:00
|
|
|
static const char* const names[] = {
|
2013-01-18 02:40:37 +00:00
|
|
|
"*undefined*",
|
|
|
|
"vpiAlways",
|
|
|
|
"vpiAssignStmt",
|
|
|
|
"vpiAssignment",
|
|
|
|
"vpiBegin",
|
|
|
|
"vpiCase",
|
|
|
|
"vpiCaseItem",
|
|
|
|
"vpiConstant",
|
|
|
|
"vpiContAssign",
|
|
|
|
"vpiDeassign",
|
|
|
|
"vpiDefParam",
|
|
|
|
"vpiDelayControl",
|
|
|
|
"vpiDisable",
|
|
|
|
"vpiEventControl",
|
|
|
|
"vpiEventStmt",
|
|
|
|
"vpiFor",
|
|
|
|
"vpiForce",
|
|
|
|
"vpiForever",
|
|
|
|
"vpiFork",
|
|
|
|
"vpiFuncCall",
|
|
|
|
"vpiFunction",
|
|
|
|
"vpiGate",
|
|
|
|
"vpiIf",
|
|
|
|
"vpiIfElse",
|
|
|
|
"vpiInitial",
|
|
|
|
"vpiIntegerVar",
|
|
|
|
"vpiInterModPath",
|
|
|
|
"vpiIterator",
|
|
|
|
"vpiIODecl",
|
|
|
|
"vpiMemory",
|
|
|
|
"vpiMemoryWord",
|
|
|
|
"vpiModPath",
|
|
|
|
"vpiModule",
|
|
|
|
"vpiNamedBegin",
|
|
|
|
"vpiNamedEvent",
|
|
|
|
"vpiNamedFork",
|
|
|
|
"vpiNet",
|
|
|
|
"vpiNetBit",
|
|
|
|
"vpiNullStmt",
|
|
|
|
"vpiOperation",
|
|
|
|
"vpiParamAssign",
|
|
|
|
"vpiParameter",
|
|
|
|
"vpiPartSelect",
|
|
|
|
"vpiPathTerm",
|
|
|
|
"vpiPort",
|
|
|
|
"vpiPortBit",
|
|
|
|
"vpiPrimTerm",
|
|
|
|
"vpiRealVar",
|
|
|
|
"vpiReg",
|
|
|
|
"vpiRegBit",
|
|
|
|
"vpiRelease",
|
|
|
|
"vpiRepeat",
|
|
|
|
"vpiRepeatControl",
|
|
|
|
"vpiSchedEvent",
|
|
|
|
"vpiSpecParam",
|
|
|
|
"vpiSwitch",
|
|
|
|
"vpiSysFuncCall",
|
|
|
|
"vpiSysTaskCall",
|
|
|
|
"vpiTableEntry",
|
|
|
|
"vpiTask",
|
|
|
|
"vpiTaskCall",
|
|
|
|
"vpiTchk",
|
|
|
|
"vpiTchkTerm",
|
|
|
|
"vpiTimeVar",
|
|
|
|
"vpiTimeQueue",
|
|
|
|
"vpiUdp",
|
|
|
|
"vpiUdpDefn",
|
|
|
|
"vpiUserSystf",
|
|
|
|
"vpiVarSelect",
|
|
|
|
"vpiWait",
|
|
|
|
"vpiWhile",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"vpiAttribute",
|
|
|
|
"vpiBitSelect",
|
|
|
|
"vpiCallback",
|
|
|
|
"vpiDelayTerm",
|
|
|
|
"vpiDelayDevice",
|
|
|
|
"vpiFrame",
|
|
|
|
"vpiGateArray",
|
|
|
|
"vpiModuleArray",
|
|
|
|
"vpiPrimitiveArray",
|
|
|
|
"vpiNetArray",
|
|
|
|
"vpiRange",
|
|
|
|
"vpiRegArray",
|
|
|
|
"vpiSwitchArray",
|
|
|
|
"vpiUdpArray",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"vpiContAssignBit",
|
|
|
|
"vpiNamedEventArray",
|
|
|
|
"vpiIndexedPartSelect",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"vpiGenScopeArray",
|
|
|
|
"vpiGenScope",
|
|
|
|
"vpiGenVar"
|
|
|
|
};
|
2020-04-14 02:51:35 +00:00
|
|
|
// clang-format on
|
2020-06-04 23:49:18 +00:00
|
|
|
if (VL_UNCOVERABLE(vpiVal < 0)) return names[0];
|
2020-04-14 02:51:35 +00:00
|
|
|
return names[(vpiVal <= vpiGenVar) ? vpiVal : 0];
|
2013-01-18 02:40:37 +00:00
|
|
|
}
|
2017-10-27 00:05:42 +00:00
|
|
|
const char* VerilatedVpiError::strFromVpiMethod(PLI_INT32 vpiVal) VL_MT_SAFE {
|
2020-04-14 02:51:35 +00:00
|
|
|
// clang-format off
|
2017-10-11 00:16:35 +00:00
|
|
|
static const char* const names[] = {
|
2013-01-18 02:40:37 +00:00
|
|
|
"vpiCondition",
|
|
|
|
"vpiDelay",
|
|
|
|
"vpiElseStmt",
|
|
|
|
"vpiForIncStmt",
|
|
|
|
"vpiForInitStmt",
|
|
|
|
"vpiHighConn",
|
|
|
|
"vpiLhs",
|
|
|
|
"vpiIndex",
|
|
|
|
"vpiLeftRange",
|
|
|
|
"vpiLowConn",
|
|
|
|
"vpiParent",
|
|
|
|
"vpiRhs",
|
|
|
|
"vpiRightRange",
|
|
|
|
"vpiScope",
|
|
|
|
"vpiSysTfCall",
|
|
|
|
"vpiTchkDataTerm",
|
|
|
|
"vpiTchkNotifier",
|
|
|
|
"vpiTchkRefTerm",
|
|
|
|
"vpiArgument",
|
|
|
|
"vpiBit",
|
|
|
|
"vpiDriver",
|
|
|
|
"vpiInternalScope",
|
|
|
|
"vpiLoad",
|
|
|
|
"vpiModDataPathIn",
|
|
|
|
"vpiModPathIn",
|
|
|
|
"vpiModPathOut",
|
|
|
|
"vpiOperand",
|
|
|
|
"vpiPortInst",
|
|
|
|
"vpiProcess",
|
|
|
|
"vpiVariables",
|
|
|
|
"vpiUse",
|
|
|
|
"vpiExpr",
|
|
|
|
"vpiPrimitive",
|
|
|
|
"vpiStmt"
|
|
|
|
};
|
2020-04-14 02:51:35 +00:00
|
|
|
// clang-format on
|
|
|
|
if (vpiVal > vpiStmt || vpiVal < vpiCondition) return "*undefined*";
|
|
|
|
return names[vpiVal - vpiCondition];
|
2013-01-18 02:40:37 +00:00
|
|
|
}
|
2015-09-26 02:57:28 +00:00
|
|
|
|
2017-10-27 00:05:42 +00:00
|
|
|
const char* VerilatedVpiError::strFromVpiCallbackReason(PLI_INT32 vpiVal) VL_MT_SAFE {
|
2020-04-14 02:51:35 +00:00
|
|
|
// clang-format off
|
2017-10-11 00:16:35 +00:00
|
|
|
static const char* const names[] = {
|
2013-01-18 02:40:37 +00:00
|
|
|
"*undefined*",
|
|
|
|
"cbValueChange",
|
|
|
|
"cbStmt",
|
|
|
|
"cbForce",
|
|
|
|
"cbRelease",
|
|
|
|
"cbAtStartOfSimTime",
|
|
|
|
"cbReadWriteSynch",
|
|
|
|
"cbReadOnlySynch",
|
|
|
|
"cbNextSimTime",
|
|
|
|
"cbAfterDelay",
|
|
|
|
"cbEndOfCompile",
|
|
|
|
"cbStartOfSimulation",
|
|
|
|
"cbEndOfSimulation",
|
|
|
|
"cbError",
|
|
|
|
"cbTchkViolation",
|
|
|
|
"cbStartOfSave",
|
|
|
|
"cbEndOfSave",
|
|
|
|
"cbStartOfRestart",
|
|
|
|
"cbEndOfRestart",
|
|
|
|
"cbStartOfReset",
|
|
|
|
"cbEndOfReset",
|
|
|
|
"cbEnterInteractive",
|
|
|
|
"cbExitInteractive",
|
|
|
|
"cbInteractiveScopeChange",
|
|
|
|
"cbUnresolvedSystf",
|
|
|
|
"cbAssign",
|
|
|
|
"cbDeassign",
|
|
|
|
"cbDisable",
|
|
|
|
"cbPLIError",
|
|
|
|
"cbSignal",
|
|
|
|
"cbNBASynch",
|
|
|
|
"cbAtEndOfSimTime"
|
|
|
|
};
|
2020-04-14 02:51:35 +00:00
|
|
|
// clang-format on
|
2020-06-04 23:49:18 +00:00
|
|
|
if (VL_UNCOVERABLE(vpiVal < 0)) return names[0];
|
2020-04-14 02:51:35 +00:00
|
|
|
return names[(vpiVal <= cbAtEndOfSimTime) ? vpiVal : 0];
|
2013-01-18 02:40:37 +00:00
|
|
|
}
|
2015-09-26 02:57:28 +00:00
|
|
|
|
2017-10-27 00:05:42 +00:00
|
|
|
const char* VerilatedVpiError::strFromVpiProp(PLI_INT32 vpiVal) VL_MT_SAFE {
|
2020-04-14 02:51:35 +00:00
|
|
|
// clang-format off
|
2017-10-11 00:16:35 +00:00
|
|
|
static const char* const names[] = {
|
2013-01-18 02:40:37 +00:00
|
|
|
"*undefined or other*",
|
|
|
|
"vpiType",
|
|
|
|
"vpiName",
|
|
|
|
"vpiFullName",
|
|
|
|
"vpiSize",
|
|
|
|
"vpiFile",
|
|
|
|
"vpiLineNo",
|
|
|
|
"vpiTopModule",
|
|
|
|
"vpiCellInstance",
|
|
|
|
"vpiDefName",
|
|
|
|
"vpiProtected",
|
|
|
|
"vpiTimeUnit",
|
|
|
|
"vpiTimePrecision",
|
|
|
|
"vpiDefNetType",
|
|
|
|
"vpiUnconnDrive",
|
|
|
|
"vpiDefFile",
|
|
|
|
"vpiDefLineNo",
|
|
|
|
"vpiScalar",
|
|
|
|
"vpiVector",
|
|
|
|
"vpiExplicitName",
|
|
|
|
"vpiDirection",
|
|
|
|
"vpiConnByName",
|
|
|
|
"vpiNetType",
|
|
|
|
"vpiExplicitScalared",
|
|
|
|
"vpiExplicitVectored",
|
|
|
|
"vpiExpanded",
|
|
|
|
"vpiImplicitDecl",
|
|
|
|
"vpiChargeStrength",
|
|
|
|
"vpiArray",
|
|
|
|
"vpiPortIndex",
|
|
|
|
"vpiTermIndex",
|
|
|
|
"vpiStrength0",
|
|
|
|
"vpiStrength1",
|
|
|
|
"vpiPrimType",
|
|
|
|
"vpiPolarity",
|
|
|
|
"vpiDataPolarity",
|
|
|
|
"vpiEdge",
|
|
|
|
"vpiPathType",
|
|
|
|
"vpiTchkType",
|
|
|
|
"vpiOpType",
|
|
|
|
"vpiConstType",
|
|
|
|
"vpiBlocking",
|
|
|
|
"vpiCaseType",
|
|
|
|
"vpiFuncType",
|
|
|
|
"vpiNetDeclAssign",
|
|
|
|
"vpiUserDefn",
|
|
|
|
"vpiScheduled",
|
|
|
|
"*undefined*",
|
|
|
|
"*undefined*",
|
|
|
|
"vpiActive",
|
|
|
|
"vpiAutomatic",
|
|
|
|
"vpiCell",
|
|
|
|
"vpiConfig",
|
|
|
|
"vpiConstantSelect",
|
|
|
|
"vpiDecompile",
|
|
|
|
"vpiDefAttribute",
|
|
|
|
"vpiDelayType",
|
|
|
|
"vpiIteratorType",
|
|
|
|
"vpiLibrary",
|
|
|
|
"*undefined*",
|
|
|
|
"vpiOffset",
|
|
|
|
"vpiResolvedNetType",
|
|
|
|
"vpiSaveRestartID",
|
|
|
|
"vpiSaveRestartLocation",
|
|
|
|
"vpiValid",
|
|
|
|
"vpiSigned",
|
|
|
|
"vpiStop",
|
|
|
|
"vpiFinish",
|
|
|
|
"vpiReset",
|
|
|
|
"vpiSetInteractiveScope",
|
|
|
|
"vpiLocalParam",
|
|
|
|
"vpiModPathHasIfNone",
|
|
|
|
"vpiIndexedPartSelectType",
|
|
|
|
"vpiIsMemory",
|
|
|
|
"vpiIsProtected"
|
|
|
|
};
|
2020-04-14 02:51:35 +00:00
|
|
|
// clang-format on
|
|
|
|
if (vpiVal == vpiUndefined) return "vpiUndefined";
|
|
|
|
return names[(vpiVal <= vpiIsProtected) ? vpiVal : 0];
|
2013-01-18 02:40:37 +00:00
|
|
|
}
|
2015-09-26 02:57:28 +00:00
|
|
|
|
2020-07-10 23:17:21 +00:00
|
|
|
#define SELF_CHECK_RESULT_CSTR(got, exp) \
|
2020-06-02 03:16:02 +00:00
|
|
|
if (0 != strcmp((got), (exp))) { \
|
2020-04-05 22:30:46 +00:00
|
|
|
std::string msg \
|
|
|
|
= std::string("%Error: ") + "GOT = '" + got + "'" + " EXP = '" + exp + "'"; \
|
|
|
|
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str()); \
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
|
2020-08-16 16:05:35 +00:00
|
|
|
#define SELF_CHECK_ENUM_STR(fn, enumn) \
|
2015-09-26 02:57:28 +00:00
|
|
|
do { \
|
2020-08-16 16:05:35 +00:00
|
|
|
const char* strVal = VerilatedVpiError::fn(enumn); \
|
|
|
|
SELF_CHECK_RESULT_CSTR(strVal, #enumn); \
|
2015-09-26 02:57:28 +00:00
|
|
|
} while (0)
|
|
|
|
|
2020-04-14 02:51:35 +00:00
|
|
|
void VerilatedVpi::selfTest() VL_MT_UNSAFE_ONE { VerilatedVpiError::selfTest(); }
|
2017-10-27 01:51:51 +00:00
|
|
|
void VerilatedVpiError::selfTest() VL_MT_UNSAFE_ONE {
|
|
|
|
VerilatedVpiImp::assertOneCheck();
|
|
|
|
|
2020-07-10 23:17:21 +00:00
|
|
|
SELF_CHECK_ENUM_STR(strFromVpiVal, vpiBinStrVal);
|
|
|
|
SELF_CHECK_ENUM_STR(strFromVpiVal, vpiRawFourStateVal);
|
|
|
|
|
|
|
|
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiAlways);
|
|
|
|
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiWhile);
|
|
|
|
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiAttribute);
|
|
|
|
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiUdpArray);
|
|
|
|
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiContAssignBit);
|
|
|
|
SELF_CHECK_ENUM_STR(strFromVpiObjType, vpiGenVar);
|
|
|
|
|
|
|
|
SELF_CHECK_ENUM_STR(strFromVpiMethod, vpiCondition);
|
|
|
|
SELF_CHECK_ENUM_STR(strFromVpiMethod, vpiStmt);
|
|
|
|
|
|
|
|
SELF_CHECK_ENUM_STR(strFromVpiCallbackReason, cbValueChange);
|
|
|
|
SELF_CHECK_ENUM_STR(strFromVpiCallbackReason, cbAtEndOfSimTime);
|
|
|
|
|
|
|
|
SELF_CHECK_ENUM_STR(strFromVpiProp, vpiType);
|
|
|
|
SELF_CHECK_ENUM_STR(strFromVpiProp, vpiProtected);
|
|
|
|
SELF_CHECK_ENUM_STR(strFromVpiProp, vpiDirection);
|
|
|
|
SELF_CHECK_ENUM_STR(strFromVpiProp, vpiTermIndex);
|
|
|
|
SELF_CHECK_ENUM_STR(strFromVpiProp, vpiConstType);
|
|
|
|
SELF_CHECK_ENUM_STR(strFromVpiProp, vpiAutomatic);
|
|
|
|
SELF_CHECK_ENUM_STR(strFromVpiProp, vpiOffset);
|
|
|
|
SELF_CHECK_ENUM_STR(strFromVpiProp, vpiStop);
|
|
|
|
SELF_CHECK_ENUM_STR(strFromVpiProp, vpiIsProtected);
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
|
2020-07-10 23:17:21 +00:00
|
|
|
#undef SELF_CHECK_ENUM_STR
|
|
|
|
#undef SELF_CHECK_RESULT_CSTR
|
2015-09-26 02:57:28 +00:00
|
|
|
|
|
|
|
//======================================================================
|
|
|
|
// callback related
|
|
|
|
|
|
|
|
vpiHandle vpi_register_cb(p_cb_data cb_data_p) {
|
2020-12-19 02:16:57 +00:00
|
|
|
// Returns handle so user can remove the callback, user must vpi_release_handle it
|
|
|
|
// Don't confuse with the callback-activated t_cb_data object handle
|
|
|
|
// which is the object causing the callback rather than the callback itself
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_RESET_();
|
2015-10-04 02:33:06 +00:00
|
|
|
// cppcheck-suppress nullPointer
|
2015-09-26 02:57:28 +00:00
|
|
|
if (VL_UNLIKELY(!cb_data_p)) {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_WARNING_(__FILE__, __LINE__, "%s : callback data pointer is null", VL_FUNC);
|
2020-08-15 14:12:55 +00:00
|
|
|
return nullptr;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
switch (cb_data_p->reason) {
|
|
|
|
case cbAfterDelay: {
|
2019-05-09 01:13:38 +00:00
|
|
|
QData time = 0;
|
2021-03-04 03:53:50 +00:00
|
|
|
if (cb_data_p->time) time = VL_SET_QII(cb_data_p->time->high, cb_data_p->time->low);
|
2020-12-19 02:16:57 +00:00
|
|
|
QData abstime = VL_TIME_Q() + time;
|
|
|
|
vluint64_t id = VerilatedVpiImp::nextCallbackId();
|
|
|
|
VerilatedVpioTimedCb* vop = new VerilatedVpioTimedCb{id, abstime};
|
|
|
|
VerilatedVpiImp::cbTimedAdd(id, cb_data_p, abstime);
|
2019-05-09 01:13:38 +00:00
|
|
|
return vop->castVpiHandle();
|
|
|
|
}
|
2020-04-14 02:51:35 +00:00
|
|
|
case cbReadWriteSynch: // FALLTHRU // Supported via vlt_main.cpp
|
|
|
|
case cbReadOnlySynch: // FALLTHRU // Supported via vlt_main.cpp
|
|
|
|
case cbNextSimTime: // FALLTHRU // Supported via vlt_main.cpp
|
|
|
|
case cbStartOfSimulation: // FALLTHRU // Supported via vlt_main.cpp
|
|
|
|
case cbEndOfSimulation: // FALLTHRU // Supported via vlt_main.cpp
|
|
|
|
case cbValueChange: // FALLTHRU // Supported via vlt_main.cpp
|
|
|
|
case cbPLIError: // FALLTHRU // NOP, but need to return handle, so make object
|
|
|
|
case cbEnterInteractive: // FALLTHRU // NOP, but need to return handle, so make object
|
|
|
|
case cbExitInteractive: // FALLTHRU // NOP, but need to return handle, so make object
|
2019-05-15 02:49:21 +00:00
|
|
|
case cbInteractiveScopeChange: { // FALLTHRU // NOP, but need to return handle, so make object
|
2020-12-19 02:16:57 +00:00
|
|
|
vluint64_t id = VerilatedVpiImp::nextCallbackId();
|
|
|
|
VerilatedVpioReasonCb* vop = new VerilatedVpioReasonCb{id, cb_data_p->reason};
|
|
|
|
VerilatedVpiImp::cbReasonAdd(id, cb_data_p);
|
2019-05-09 01:13:38 +00:00
|
|
|
return vop->castVpiHandle();
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
default:
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_WARNING_(__FILE__, __LINE__, "%s: Unsupported callback type %s", VL_FUNC,
|
2020-04-14 02:51:35 +00:00
|
|
|
VerilatedVpiError::strFromVpiCallbackReason(cb_data_p->reason));
|
2020-08-15 14:12:55 +00:00
|
|
|
return nullptr;
|
2020-05-30 17:46:12 +00:00
|
|
|
}
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
|
2020-11-11 02:40:14 +00:00
|
|
|
PLI_INT32 vpi_remove_cb(vpiHandle cb_obj) {
|
|
|
|
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_remove_cb %p\n", cb_obj););
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_RESET_();
|
2020-12-19 02:16:57 +00:00
|
|
|
VerilatedVpio* vop = VerilatedVpio::castp(cb_obj);
|
2015-09-26 02:57:28 +00:00
|
|
|
if (VL_UNLIKELY(!vop)) return 0;
|
2020-12-19 02:16:57 +00:00
|
|
|
return vop->dovpi_remove_cb();
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
|
2021-03-04 03:53:50 +00:00
|
|
|
void vpi_get_cb_info(vpiHandle /*object*/, p_cb_data /*cb_data_p*/) { VL_VPI_UNIMP_(); }
|
2020-04-04 02:31:54 +00:00
|
|
|
vpiHandle vpi_register_systf(p_vpi_systf_data /*systf_data_p*/) {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_UNIMP_();
|
2020-11-11 02:40:14 +00:00
|
|
|
return nullptr;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
2020-04-04 02:31:54 +00:00
|
|
|
void vpi_get_systf_info(vpiHandle /*object*/, p_vpi_systf_data /*systf_data_p*/) {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_UNIMP_();
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// for obtaining handles
|
|
|
|
|
|
|
|
vpiHandle vpi_handle_by_name(PLI_BYTE8* namep, vpiHandle scope) {
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_RESET_();
|
2020-08-15 14:12:55 +00:00
|
|
|
if (VL_UNLIKELY(!namep)) return nullptr;
|
2019-05-09 01:13:38 +00:00
|
|
|
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_handle_by_name %s %p\n", namep, scope););
|
2020-08-15 14:12:55 +00:00
|
|
|
const VerilatedVar* varp = nullptr;
|
2015-09-26 02:57:28 +00:00
|
|
|
const VerilatedScope* scopep;
|
2019-10-02 22:47:12 +00:00
|
|
|
VerilatedVpioScope* voScopep = VerilatedVpioScope::castp(scope);
|
2017-09-23 11:32:37 +00:00
|
|
|
std::string scopeAndName = namep;
|
2015-09-26 02:57:28 +00:00
|
|
|
if (voScopep) {
|
2019-05-09 01:13:38 +00:00
|
|
|
scopeAndName = std::string(voScopep->fullname()) + "." + namep;
|
2020-04-04 02:31:54 +00:00
|
|
|
namep = const_cast<PLI_BYTE8*>(scopeAndName.c_str());
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
{
|
2019-05-09 01:13:38 +00:00
|
|
|
// This doesn't yet follow the hierarchy in the proper way
|
|
|
|
scopep = Verilated::scopeFind(namep);
|
|
|
|
if (scopep) { // Whole thing found as a scope
|
2019-10-02 22:47:12 +00:00
|
|
|
if (scopep->type() == VerilatedScope::SCOPE_MODULE) {
|
|
|
|
return (new VerilatedVpioModule(scopep))->castVpiHandle();
|
|
|
|
} else {
|
|
|
|
return (new VerilatedVpioScope(scopep))->castVpiHandle();
|
|
|
|
}
|
2019-05-09 01:13:38 +00:00
|
|
|
}
|
|
|
|
const char* baseNamep = scopeAndName.c_str();
|
|
|
|
std::string scopename;
|
|
|
|
const char* dotp = strrchr(namep, '.');
|
|
|
|
if (VL_LIKELY(dotp)) {
|
2020-04-14 02:51:35 +00:00
|
|
|
baseNamep = dotp + 1;
|
|
|
|
scopename = std::string(namep, dotp - namep);
|
2019-05-09 01:13:38 +00:00
|
|
|
}
|
2019-10-02 01:57:45 +00:00
|
|
|
|
2020-04-04 02:31:54 +00:00
|
|
|
if (scopename.find('.') == std::string::npos) {
|
2019-10-02 01:57:45 +00:00
|
|
|
// This is a toplevel, hence search in our TOP ports first.
|
|
|
|
scopep = Verilated::scopeFind("TOP");
|
2021-02-22 02:25:21 +00:00
|
|
|
if (scopep) varp = scopep->varFind(baseNamep);
|
2019-10-02 01:57:45 +00:00
|
|
|
}
|
|
|
|
if (!varp) {
|
|
|
|
scopep = Verilated::scopeFind(scopename.c_str());
|
2020-08-15 14:12:55 +00:00
|
|
|
if (!scopep) return nullptr;
|
2019-10-02 01:57:45 +00:00
|
|
|
varp = scopep->varFind(baseNamep);
|
|
|
|
}
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
2020-08-15 14:12:55 +00:00
|
|
|
if (!varp) return nullptr;
|
2020-06-12 22:38:01 +00:00
|
|
|
|
|
|
|
if (varp->isParam()) {
|
|
|
|
return (new VerilatedVpioParam(varp, scopep))->castVpiHandle();
|
|
|
|
} else {
|
|
|
|
return (new VerilatedVpioVar(varp, scopep))->castVpiHandle();
|
|
|
|
}
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
vpiHandle vpi_handle_by_index(vpiHandle object, PLI_INT32 indx) {
|
|
|
|
// Used to get array entries
|
2019-05-09 01:13:38 +00:00
|
|
|
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_handle_by_index %p %d\n", object, indx););
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_RESET_();
|
2020-12-13 03:47:47 +00:00
|
|
|
// Memory words are not indexable
|
|
|
|
VerilatedVpioMemoryWord* vop = VerilatedVpioMemoryWord::castp(object);
|
|
|
|
if (VL_UNLIKELY(vop)) return nullptr;
|
|
|
|
VerilatedVpioVar* varop = VerilatedVpioVar::castp(object);
|
2015-09-26 02:57:28 +00:00
|
|
|
if (VL_LIKELY(varop)) {
|
2020-11-11 02:40:14 +00:00
|
|
|
if (varop->varp()->dims() < 2) return nullptr;
|
2017-12-16 15:52:43 +00:00
|
|
|
if (VL_LIKELY(varop->varp()->unpacked().left() >= varop->varp()->unpacked().right())) {
|
2018-03-10 21:32:04 +00:00
|
|
|
if (VL_UNLIKELY(indx > varop->varp()->unpacked().left()
|
2020-04-14 02:51:35 +00:00
|
|
|
|| indx < varop->varp()->unpacked().right()))
|
2020-11-11 02:40:14 +00:00
|
|
|
return nullptr;
|
2019-05-09 01:13:38 +00:00
|
|
|
return (new VerilatedVpioMemoryWord(varop->varp(), varop->scopep(), indx,
|
2020-04-14 02:51:35 +00:00
|
|
|
indx - varop->varp()->unpacked().right()))
|
2019-05-09 01:13:38 +00:00
|
|
|
->castVpiHandle();
|
|
|
|
}
|
2018-10-14 22:39:33 +00:00
|
|
|
if (VL_UNLIKELY(indx < varop->varp()->unpacked().left()
|
2020-04-14 02:51:35 +00:00
|
|
|
|| indx > varop->varp()->unpacked().right()))
|
2020-11-11 02:40:14 +00:00
|
|
|
return nullptr;
|
2018-10-14 22:39:33 +00:00
|
|
|
return (new VerilatedVpioMemoryWord(varop->varp(), varop->scopep(), indx,
|
|
|
|
indx - varop->varp()->unpacked().left()))
|
|
|
|
->castVpiHandle();
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_INTERNAL_(__FILE__, __LINE__, "%s : can't resolve handle", VL_FUNC);
|
2020-11-11 02:40:14 +00:00
|
|
|
return nullptr;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// for traversing relationships
|
|
|
|
|
|
|
|
vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
|
2019-05-09 01:13:38 +00:00
|
|
|
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_handle %d %p\n", type, object););
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_RESET_();
|
2015-09-26 02:57:28 +00:00
|
|
|
switch (type) {
|
|
|
|
case vpiLeftRange: {
|
2020-06-02 12:04:22 +00:00
|
|
|
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
|
2020-11-11 02:40:14 +00:00
|
|
|
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
|
2020-06-02 12:04:22 +00:00
|
|
|
return (new VerilatedVpioConst(vop->rangep()->left()))->castVpiHandle();
|
|
|
|
} else if (VerilatedVpioRange* vop = VerilatedVpioRange::castp(object)) {
|
2020-11-11 02:40:14 +00:00
|
|
|
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
|
2020-06-02 12:04:22 +00:00
|
|
|
return (new VerilatedVpioConst(vop->rangep()->left()))->castVpiHandle();
|
|
|
|
}
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_WARNING_(__FILE__, __LINE__,
|
2020-06-04 23:49:18 +00:00
|
|
|
"%s: Unsupported vpiHandle (%p) for type %s, nothing will be returned",
|
2020-06-02 12:04:22 +00:00
|
|
|
VL_FUNC, object, VerilatedVpiError::strFromVpiMethod(type));
|
2020-11-11 02:40:14 +00:00
|
|
|
return nullptr;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
case vpiRightRange: {
|
2020-06-02 12:04:22 +00:00
|
|
|
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
|
2020-11-11 02:40:14 +00:00
|
|
|
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
|
2020-06-02 12:04:22 +00:00
|
|
|
return (new VerilatedVpioConst(vop->rangep()->right()))->castVpiHandle();
|
|
|
|
} else if (VerilatedVpioRange* vop = VerilatedVpioRange::castp(object)) {
|
2020-11-11 02:40:14 +00:00
|
|
|
if (VL_UNLIKELY(!vop->rangep())) return nullptr;
|
2020-06-02 12:04:22 +00:00
|
|
|
return (new VerilatedVpioConst(vop->rangep()->right()))->castVpiHandle();
|
|
|
|
}
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_WARNING_(__FILE__, __LINE__,
|
2020-06-04 23:49:18 +00:00
|
|
|
"%s: Unsupported vpiHandle (%p) for type %s, nothing will be returned",
|
2020-06-02 12:04:22 +00:00
|
|
|
VL_FUNC, object, VerilatedVpiError::strFromVpiMethod(type));
|
2020-11-11 02:40:14 +00:00
|
|
|
return nullptr;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
case vpiIndex: {
|
2019-05-09 01:13:38 +00:00
|
|
|
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
2020-11-11 02:40:14 +00:00
|
|
|
if (VL_UNLIKELY(!vop)) return nullptr;
|
2015-09-26 02:57:28 +00:00
|
|
|
return (new VerilatedVpioConst(vop->index()))->castVpiHandle();
|
|
|
|
}
|
|
|
|
case vpiScope: {
|
2019-05-09 01:13:38 +00:00
|
|
|
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
2020-11-11 02:40:14 +00:00
|
|
|
if (VL_UNLIKELY(!vop)) return nullptr;
|
2019-05-09 01:13:38 +00:00
|
|
|
return (new VerilatedVpioScope(vop->scopep()))->castVpiHandle();
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
case vpiParent: {
|
2019-05-09 01:13:38 +00:00
|
|
|
VerilatedVpioMemoryWord* vop = VerilatedVpioMemoryWord::castp(object);
|
2020-11-11 02:40:14 +00:00
|
|
|
if (VL_UNLIKELY(!vop)) return nullptr;
|
2019-05-09 01:13:38 +00:00
|
|
|
return (new VerilatedVpioVar(vop->varp(), vop->scopep()))->castVpiHandle();
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
default:
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_WARNING_(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
|
2019-05-09 01:13:38 +00:00
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiMethod(type));
|
2020-11-11 02:40:14 +00:00
|
|
|
return nullptr;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-04 02:31:54 +00:00
|
|
|
vpiHandle vpi_handle_multi(PLI_INT32 /*type*/, vpiHandle /*refHandle1*/, vpiHandle /*refHandle2*/,
|
|
|
|
...) {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_UNIMP_();
|
2020-11-11 02:40:14 +00:00
|
|
|
return nullptr;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
|
2019-05-09 01:13:38 +00:00
|
|
|
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_iterate %d %p\n", type, object););
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_RESET_();
|
2015-09-26 02:57:28 +00:00
|
|
|
switch (type) {
|
|
|
|
case vpiMemoryWord: {
|
2019-05-09 01:13:38 +00:00
|
|
|
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
2020-11-11 02:40:14 +00:00
|
|
|
if (VL_UNLIKELY(!vop)) return nullptr;
|
|
|
|
if (vop->varp()->dims() < 2) return nullptr;
|
2019-05-09 01:13:38 +00:00
|
|
|
if (vop->varp()->dims() > 2) {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_WARNING_(__FILE__, __LINE__,
|
2020-04-14 02:51:35 +00:00
|
|
|
"%s: %s, object %s has unsupported number of indices (%d)", VL_FUNC,
|
|
|
|
VerilatedVpiError::strFromVpiMethod(type), vop->fullname(),
|
|
|
|
vop->varp()->dims());
|
2019-05-09 01:13:38 +00:00
|
|
|
}
|
|
|
|
return (new VerilatedVpioMemoryWordIter(object, vop->varp()))->castVpiHandle();
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
case vpiRange: {
|
2019-05-09 01:13:38 +00:00
|
|
|
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
2020-11-11 02:40:14 +00:00
|
|
|
if (VL_UNLIKELY(!vop)) return nullptr;
|
|
|
|
if (vop->varp()->dims() < 2) return nullptr;
|
2019-05-09 01:13:38 +00:00
|
|
|
// Unsupported is multidim list
|
2015-09-26 02:57:28 +00:00
|
|
|
if (vop->varp()->dims() > 2) {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_WARNING_(__FILE__, __LINE__,
|
2020-04-14 02:51:35 +00:00
|
|
|
"%s: %s, object %s has unsupported number of indices (%d)", VL_FUNC,
|
|
|
|
VerilatedVpiError::strFromVpiMethod(type), vop->fullname(),
|
|
|
|
vop->varp()->dims());
|
2019-05-09 01:13:38 +00:00
|
|
|
}
|
2020-12-12 13:11:08 +00:00
|
|
|
return ((new VerilatedVpioRangeIter(vop->rangep()))->castVpiHandle());
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
case vpiReg: {
|
2019-05-09 01:13:38 +00:00
|
|
|
VerilatedVpioScope* vop = VerilatedVpioScope::castp(object);
|
2020-11-11 02:40:14 +00:00
|
|
|
if (VL_UNLIKELY(!vop)) return nullptr;
|
2020-04-14 02:51:35 +00:00
|
|
|
return ((new VerilatedVpioVarIter(vop->scopep()))->castVpiHandle());
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
2019-10-02 01:57:45 +00:00
|
|
|
case vpiModule: {
|
|
|
|
VerilatedVpioModule* vop = VerilatedVpioModule::castp(object);
|
|
|
|
const VerilatedHierarchyMap* map = VerilatedImp::hierarchyMap();
|
2020-08-15 14:12:55 +00:00
|
|
|
const VerilatedScope* mod = vop ? vop->scopep() : nullptr;
|
2020-08-16 15:43:49 +00:00
|
|
|
const auto it = vlstd::as_const(map)->find(const_cast<VerilatedScope*>(mod));
|
2020-11-11 02:40:14 +00:00
|
|
|
if (it == map->end()) return nullptr;
|
2020-04-14 02:51:35 +00:00
|
|
|
return ((new VerilatedVpioModuleIter(it->second))->castVpiHandle());
|
2019-10-02 01:57:45 +00:00
|
|
|
}
|
2015-09-26 02:57:28 +00:00
|
|
|
default:
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_WARNING_(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
|
2019-05-09 01:13:38 +00:00
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiObjType(type));
|
2020-11-11 02:40:14 +00:00
|
|
|
return nullptr;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
vpiHandle vpi_scan(vpiHandle object) {
|
2019-05-09 01:13:38 +00:00
|
|
|
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_scan %p\n", object););
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_RESET_();
|
2015-09-26 02:57:28 +00:00
|
|
|
VerilatedVpio* vop = VerilatedVpio::castp(object);
|
2020-08-15 14:12:55 +00:00
|
|
|
if (VL_UNLIKELY(!vop)) return nullptr;
|
2015-09-26 02:57:28 +00:00
|
|
|
return vop->dovpi_scan();
|
|
|
|
}
|
|
|
|
|
|
|
|
// for processing properties
|
|
|
|
|
|
|
|
PLI_INT32 vpi_get(PLI_INT32 property, vpiHandle object) {
|
|
|
|
// Leave this in the header file - in many cases the compiler can constant propagate "object"
|
2019-05-09 01:13:38 +00:00
|
|
|
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_get %d %p\n", property, object););
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_RESET_();
|
2015-09-26 02:57:28 +00:00
|
|
|
switch (property) {
|
|
|
|
case vpiTimePrecision: {
|
2020-04-15 23:39:03 +00:00
|
|
|
return Verilated::timeprecision();
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
2019-12-14 00:11:37 +00:00
|
|
|
case vpiTimeUnit: {
|
2020-04-15 23:39:03 +00:00
|
|
|
VerilatedVpioScope* vop = VerilatedVpioScope::castp(object);
|
|
|
|
if (!vop) return Verilated::timeunit(); // Null asks for global, not unlikely
|
|
|
|
return vop->scopep()->timeunit();
|
2019-12-14 00:11:37 +00:00
|
|
|
}
|
2015-09-26 02:57:28 +00:00
|
|
|
case vpiType: {
|
2019-09-18 11:22:59 +00:00
|
|
|
VerilatedVpio* vop = VerilatedVpio::castp(object);
|
2019-05-09 01:13:38 +00:00
|
|
|
if (VL_UNLIKELY(!vop)) return 0;
|
|
|
|
return vop->type();
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
case vpiDirection: {
|
2019-05-09 01:13:38 +00:00
|
|
|
// By forthought, the directions already are vpi enumerated
|
|
|
|
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
|
|
|
if (VL_UNLIKELY(!vop)) return 0;
|
|
|
|
return vop->varp()->vldir();
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
case vpiScalar: // FALLTHRU
|
|
|
|
case vpiVector: {
|
2019-05-09 01:13:38 +00:00
|
|
|
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
|
|
|
if (VL_UNLIKELY(!vop)) return 0;
|
2020-04-14 02:51:35 +00:00
|
|
|
return (property == vpiVector) ^ (vop->varp()->dims() == 0);
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
case vpiSize: {
|
2019-05-09 01:13:38 +00:00
|
|
|
VerilatedVpioVar* vop = VerilatedVpioVar::castp(object);
|
|
|
|
if (VL_UNLIKELY(!vop)) return 0;
|
|
|
|
return vop->size();
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
default:
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_WARNING_(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
|
2019-05-09 01:13:38 +00:00
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiProp(property));
|
|
|
|
return 0;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-04 02:31:54 +00:00
|
|
|
PLI_INT64 vpi_get64(PLI_INT32 /*property*/, vpiHandle /*object*/) {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_UNIMP_();
|
2015-09-26 02:57:28 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-04-14 02:51:35 +00:00
|
|
|
PLI_BYTE8* vpi_get_str(PLI_INT32 property, vpiHandle object) {
|
2019-05-09 01:13:38 +00:00
|
|
|
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_get_str %d %p\n", property, object););
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2015-09-26 02:57:28 +00:00
|
|
|
VerilatedVpio* vop = VerilatedVpio::castp(object);
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_RESET_();
|
2020-08-15 14:12:55 +00:00
|
|
|
if (VL_UNLIKELY(!vop)) return nullptr;
|
2015-09-26 02:57:28 +00:00
|
|
|
switch (property) {
|
|
|
|
case vpiName: {
|
2020-04-04 02:31:54 +00:00
|
|
|
return const_cast<PLI_BYTE8*>(vop->name());
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
case vpiFullName: {
|
2020-04-04 02:31:54 +00:00
|
|
|
return const_cast<PLI_BYTE8*>(vop->fullname());
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
case vpiDefName: {
|
2020-04-04 02:31:54 +00:00
|
|
|
return const_cast<PLI_BYTE8*>(vop->defname());
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
2019-09-18 16:24:19 +00:00
|
|
|
case vpiType: {
|
2020-04-04 02:31:54 +00:00
|
|
|
return const_cast<PLI_BYTE8*>(VerilatedVpiError::strFromVpiObjType(vop->type()));
|
2019-09-18 16:24:19 +00:00
|
|
|
}
|
2015-09-26 02:57:28 +00:00
|
|
|
default:
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_WARNING_(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned",
|
2019-05-09 01:13:38 +00:00
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiProp(property));
|
2020-11-11 02:40:14 +00:00
|
|
|
return nullptr;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// delay processing
|
|
|
|
|
2021-03-04 03:53:50 +00:00
|
|
|
void vpi_get_delays(vpiHandle /*object*/, p_vpi_delay /*delay_p*/) { VL_VPI_UNIMP_(); }
|
|
|
|
void vpi_put_delays(vpiHandle /*object*/, p_vpi_delay /*delay_p*/) { VL_VPI_UNIMP_(); }
|
2015-09-26 02:57:28 +00:00
|
|
|
|
|
|
|
// value processing
|
2020-06-12 22:38:01 +00:00
|
|
|
bool vl_check_format(const VerilatedVar* varp, const p_vpi_value valuep, const char* fullname,
|
|
|
|
bool isGetValue) {
|
|
|
|
bool status = true;
|
|
|
|
if ((valuep->format == vpiVectorVal) || (valuep->format == vpiBinStrVal)
|
|
|
|
|| (valuep->format == vpiOctStrVal) || (valuep->format == vpiHexStrVal)) {
|
|
|
|
switch (varp->vltype()) {
|
|
|
|
case VLVT_UINT8:
|
|
|
|
case VLVT_UINT16:
|
|
|
|
case VLVT_UINT32:
|
|
|
|
case VLVT_UINT64:
|
|
|
|
case VLVT_WDATA: return status;
|
|
|
|
default: status = false;
|
|
|
|
}
|
|
|
|
} else if (valuep->format == vpiDecStrVal) {
|
|
|
|
switch (varp->vltype()) {
|
|
|
|
case VLVT_UINT8:
|
|
|
|
case VLVT_UINT16:
|
|
|
|
case VLVT_UINT32:
|
|
|
|
case VLVT_UINT64: return status;
|
|
|
|
default: status = false;
|
|
|
|
}
|
|
|
|
} else if (valuep->format == vpiStringVal) {
|
|
|
|
switch (varp->vltype()) {
|
|
|
|
case VLVT_UINT8:
|
|
|
|
case VLVT_UINT16:
|
|
|
|
case VLVT_UINT32:
|
|
|
|
case VLVT_UINT64:
|
|
|
|
case VLVT_WDATA: return status;
|
|
|
|
case VLVT_STRING:
|
|
|
|
if (isGetValue) {
|
|
|
|
return status;
|
|
|
|
} else {
|
|
|
|
status = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: status = false;
|
|
|
|
}
|
|
|
|
} else if (valuep->format == vpiIntVal) {
|
|
|
|
switch (varp->vltype()) {
|
|
|
|
case VLVT_UINT8:
|
|
|
|
case VLVT_UINT16:
|
|
|
|
case VLVT_UINT32: return status;
|
|
|
|
default: status = false;
|
|
|
|
}
|
|
|
|
} else if (valuep->format == vpiSuppressVal) {
|
|
|
|
return status;
|
|
|
|
} else {
|
|
|
|
status = false;
|
|
|
|
}
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC,
|
2020-06-12 22:38:01 +00:00
|
|
|
VerilatedVpiError::strFromVpiVal(valuep->format), fullname);
|
|
|
|
return status;
|
|
|
|
}
|
2015-09-26 02:57:28 +00:00
|
|
|
|
2020-06-12 22:38:01 +00:00
|
|
|
void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
|
|
|
const char* fullname) {
|
|
|
|
if (!vl_check_format(varp, valuep, fullname, true)) return;
|
2018-03-10 21:32:04 +00:00
|
|
|
// Maximum required size is for binary string, one byte per bit plus null termination
|
2020-12-02 00:01:20 +00:00
|
|
|
static VL_THREAD_LOCAL char t_outStr[1 + VL_MULS_MAX_WORDS * 32];
|
2015-09-26 02:57:28 +00:00
|
|
|
// cppcheck-suppress variableScope
|
2020-12-02 00:01:20 +00:00
|
|
|
static VL_THREAD_LOCAL int t_outStrSz = sizeof(t_outStr) - 1;
|
2020-06-12 22:38:01 +00:00
|
|
|
// We used to presume vpiValue.format = vpiIntVal or if single bit vpiScalarVal
|
|
|
|
// This may cause backward compatibility issues with older code.
|
|
|
|
if (valuep->format == vpiVectorVal) {
|
|
|
|
// Vector pointer must come from our memory pool
|
|
|
|
// It only needs to persist until the next vpi_get_value
|
2020-12-02 00:01:20 +00:00
|
|
|
static VL_THREAD_LOCAL t_vpi_vecval t_out[VL_MULS_MAX_WORDS * 2];
|
|
|
|
valuep->value.vector = t_out;
|
2020-06-12 22:38:01 +00:00
|
|
|
if (varp->vltype() == VLVT_UINT8) {
|
2020-12-02 00:01:20 +00:00
|
|
|
t_out[0].aval = *(reinterpret_cast<CData*>(varDatap));
|
|
|
|
t_out[0].bval = 0;
|
2020-06-12 22:38:01 +00:00
|
|
|
return;
|
|
|
|
} else if (varp->vltype() == VLVT_UINT16) {
|
2020-12-02 00:01:20 +00:00
|
|
|
t_out[0].aval = *(reinterpret_cast<SData*>(varDatap));
|
|
|
|
t_out[0].bval = 0;
|
2020-06-12 22:38:01 +00:00
|
|
|
return;
|
|
|
|
} else if (varp->vltype() == VLVT_UINT32) {
|
2020-12-02 00:01:20 +00:00
|
|
|
t_out[0].aval = *(reinterpret_cast<IData*>(varDatap));
|
|
|
|
t_out[0].bval = 0;
|
2020-06-12 22:38:01 +00:00
|
|
|
return;
|
|
|
|
} else if (varp->vltype() == VLVT_UINT64) {
|
|
|
|
QData data = *(reinterpret_cast<QData*>(varDatap));
|
2020-12-02 00:01:20 +00:00
|
|
|
t_out[1].aval = static_cast<IData>(data >> 32ULL);
|
|
|
|
t_out[1].bval = 0;
|
|
|
|
t_out[0].aval = static_cast<IData>(data);
|
|
|
|
t_out[0].bval = 0;
|
2020-06-12 22:38:01 +00:00
|
|
|
return;
|
|
|
|
} else if (varp->vltype() == VLVT_WDATA) {
|
|
|
|
int words = VL_WORDS_I(varp->packed().elements());
|
|
|
|
if (VL_UNCOVERABLE(words >= VL_MULS_MAX_WORDS)) {
|
|
|
|
VL_FATAL_MT(
|
|
|
|
__FILE__, __LINE__, "",
|
|
|
|
"vpi_get_value with more than VL_MULS_MAX_WORDS; increase and recompile");
|
2018-11-29 00:59:10 +00:00
|
|
|
}
|
2020-06-12 22:38:01 +00:00
|
|
|
WDataInP datap = (reinterpret_cast<EData*>(varDatap));
|
|
|
|
for (int i = 0; i < words; ++i) {
|
2020-12-02 00:01:20 +00:00
|
|
|
t_out[i].aval = datap[i];
|
|
|
|
t_out[i].bval = 0;
|
2019-05-09 01:13:38 +00:00
|
|
|
}
|
2020-06-12 22:38:01 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else if (valuep->format == vpiBinStrVal) {
|
2020-12-02 00:01:20 +00:00
|
|
|
valuep->value.str = t_outStr;
|
2020-06-12 22:38:01 +00:00
|
|
|
int bits = varp->packed().elements();
|
|
|
|
CData* datap = (reinterpret_cast<CData*>(varDatap));
|
|
|
|
int i;
|
2020-12-02 00:01:20 +00:00
|
|
|
if (bits > t_outStrSz) {
|
2020-06-12 22:38:01 +00:00
|
|
|
// limit maximum size of output to size of buffer to prevent overrun.
|
2020-12-02 00:01:20 +00:00
|
|
|
bits = t_outStrSz;
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_WARNING_(
|
2020-06-12 22:38:01 +00:00
|
|
|
__FILE__, __LINE__,
|
|
|
|
"%s: Truncating string value of %s for %s"
|
|
|
|
" as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
|
2020-12-02 00:01:20 +00:00
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, t_outStrSz,
|
2020-06-12 22:38:01 +00:00
|
|
|
VL_MULS_MAX_WORDS, bits);
|
|
|
|
}
|
|
|
|
for (i = 0; i < bits; ++i) {
|
|
|
|
char val = (datap[i >> 3] >> (i & 7)) & 1;
|
2020-12-02 00:01:20 +00:00
|
|
|
t_outStr[bits - i - 1] = val ? '1' : '0';
|
2020-06-12 22:38:01 +00:00
|
|
|
}
|
2020-12-02 00:01:20 +00:00
|
|
|
t_outStr[i] = '\0';
|
2020-06-12 22:38:01 +00:00
|
|
|
return;
|
|
|
|
} else if (valuep->format == vpiOctStrVal) {
|
2020-12-02 00:01:20 +00:00
|
|
|
valuep->value.str = t_outStr;
|
2020-06-12 22:38:01 +00:00
|
|
|
int chars = (varp->packed().elements() + 2) / 3;
|
|
|
|
int bytes = VL_BYTES_I(varp->packed().elements());
|
|
|
|
CData* datap = (reinterpret_cast<CData*>(varDatap));
|
|
|
|
int i;
|
2020-12-02 00:01:20 +00:00
|
|
|
if (chars > t_outStrSz) {
|
2020-06-12 22:38:01 +00:00
|
|
|
// limit maximum size of output to size of buffer to prevent overrun.
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_WARNING_(
|
2020-06-12 22:38:01 +00:00
|
|
|
__FILE__, __LINE__,
|
|
|
|
"%s: Truncating string value of %s for %s"
|
|
|
|
" as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
|
2020-12-02 00:01:20 +00:00
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, t_outStrSz,
|
2020-06-12 22:38:01 +00:00
|
|
|
VL_MULS_MAX_WORDS, chars);
|
2020-12-02 00:01:20 +00:00
|
|
|
chars = t_outStrSz;
|
2020-06-12 22:38:01 +00:00
|
|
|
}
|
|
|
|
for (i = 0; i < chars; ++i) {
|
|
|
|
div_t idx = div(i * 3, 8);
|
|
|
|
int val = datap[idx.quot];
|
|
|
|
if ((idx.quot + 1) < bytes) {
|
|
|
|
// if the next byte is valid or that in
|
|
|
|
// for when the required 3 bits straddle adjacent bytes
|
|
|
|
val |= datap[idx.quot + 1] << 8;
|
2019-05-09 01:13:38 +00:00
|
|
|
}
|
2020-06-12 22:38:01 +00:00
|
|
|
// align so least significant 3 bits represent octal char
|
|
|
|
val >>= idx.rem;
|
|
|
|
if (i == (chars - 1)) {
|
|
|
|
// most signifcant char, mask off non existant bits when vector
|
|
|
|
// size is not a multiple of 3
|
|
|
|
unsigned int rem = varp->packed().elements() % 3;
|
|
|
|
if (rem) {
|
|
|
|
// generate bit mask & zero non existant bits
|
|
|
|
val &= (1 << rem) - 1;
|
2019-05-09 01:13:38 +00:00
|
|
|
}
|
|
|
|
}
|
2020-12-02 00:01:20 +00:00
|
|
|
t_outStr[chars - i - 1] = '0' + (val & 7);
|
2020-06-12 22:38:01 +00:00
|
|
|
}
|
2020-12-02 00:01:20 +00:00
|
|
|
t_outStr[i] = '\0';
|
2020-06-12 22:38:01 +00:00
|
|
|
return;
|
|
|
|
} else if (valuep->format == vpiDecStrVal) {
|
2020-12-02 00:01:20 +00:00
|
|
|
valuep->value.str = t_outStr;
|
2020-08-15 14:12:55 +00:00
|
|
|
// outStrSz does not include nullptr termination so add one
|
2020-06-12 22:38:01 +00:00
|
|
|
if (varp->vltype() == VLVT_UINT8) {
|
2020-12-02 00:01:20 +00:00
|
|
|
VL_SNPRINTF(t_outStr, t_outStrSz + 1, "%hhu",
|
2020-06-12 22:38:01 +00:00
|
|
|
static_cast<unsigned char>(*(reinterpret_cast<CData*>(varDatap))));
|
|
|
|
return;
|
|
|
|
} else if (varp->vltype() == VLVT_UINT16) {
|
2020-12-02 00:01:20 +00:00
|
|
|
VL_SNPRINTF(t_outStr, t_outStrSz + 1, "%hu",
|
2020-06-12 22:38:01 +00:00
|
|
|
static_cast<unsigned short>(*(reinterpret_cast<SData*>(varDatap))));
|
|
|
|
return;
|
|
|
|
} else if (varp->vltype() == VLVT_UINT32) {
|
2020-12-02 00:01:20 +00:00
|
|
|
VL_SNPRINTF(t_outStr, t_outStrSz + 1, "%u",
|
2020-06-12 22:38:01 +00:00
|
|
|
static_cast<unsigned int>(*(reinterpret_cast<IData*>(varDatap))));
|
|
|
|
return;
|
|
|
|
} else if (varp->vltype() == VLVT_UINT64) {
|
2020-12-02 00:01:20 +00:00
|
|
|
VL_SNPRINTF(t_outStr, t_outStrSz + 1, "%llu",
|
2020-06-12 22:38:01 +00:00
|
|
|
static_cast<unsigned long long>(*(reinterpret_cast<QData*>(varDatap))));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else if (valuep->format == vpiHexStrVal) {
|
2020-12-02 00:01:20 +00:00
|
|
|
valuep->value.str = t_outStr;
|
2020-06-12 22:38:01 +00:00
|
|
|
int chars = (varp->packed().elements() + 3) >> 2;
|
|
|
|
CData* datap = (reinterpret_cast<CData*>(varDatap));
|
|
|
|
int i;
|
2020-12-02 00:01:20 +00:00
|
|
|
if (chars > t_outStrSz) {
|
2020-06-12 22:38:01 +00:00
|
|
|
// limit maximum size of output to size of buffer to prevent overrun.
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_WARNING_(
|
2020-06-12 22:38:01 +00:00
|
|
|
__FILE__, __LINE__,
|
|
|
|
"%s: Truncating string value of %s for %s"
|
|
|
|
" as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
|
2020-12-02 00:01:20 +00:00
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, t_outStrSz,
|
2020-06-12 22:38:01 +00:00
|
|
|
VL_MULS_MAX_WORDS, chars);
|
2020-12-02 00:01:20 +00:00
|
|
|
chars = t_outStrSz;
|
2020-06-12 22:38:01 +00:00
|
|
|
}
|
|
|
|
for (i = 0; i < chars; ++i) {
|
|
|
|
char val = (datap[i >> 1] >> ((i & 1) << 2)) & 15;
|
|
|
|
if (i == (chars - 1)) {
|
|
|
|
// most signifcant char, mask off non existant bits when vector
|
|
|
|
// size is not a multiple of 4
|
|
|
|
unsigned int rem = varp->packed().elements() & 3;
|
|
|
|
if (rem) {
|
|
|
|
// generate bit mask & zero non existant bits
|
|
|
|
val &= (1 << rem) - 1;
|
2018-11-29 00:59:10 +00:00
|
|
|
}
|
|
|
|
}
|
2020-12-02 00:01:20 +00:00
|
|
|
t_outStr[chars - i - 1] = "0123456789abcdef"[static_cast<int>(val)];
|
2020-06-12 22:38:01 +00:00
|
|
|
}
|
2020-12-02 00:01:20 +00:00
|
|
|
t_outStr[i] = '\0';
|
2020-06-12 22:38:01 +00:00
|
|
|
return;
|
|
|
|
} else if (valuep->format == vpiStringVal) {
|
|
|
|
if (varp->vltype() == VLVT_STRING) {
|
|
|
|
valuep->value.str = reinterpret_cast<char*>(varDatap);
|
|
|
|
return;
|
|
|
|
} else {
|
2020-12-02 00:01:20 +00:00
|
|
|
valuep->value.str = t_outStr;
|
2020-06-12 22:38:01 +00:00
|
|
|
int bytes = VL_BYTES_I(varp->packed().elements());
|
|
|
|
CData* datap = (reinterpret_cast<CData*>(varDatap));
|
|
|
|
int i;
|
2020-12-02 00:01:20 +00:00
|
|
|
if (bytes > t_outStrSz) {
|
2020-06-12 22:38:01 +00:00
|
|
|
// limit maximum size of output to size of buffer to prevent overrun.
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_WARNING_(
|
2020-06-12 22:38:01 +00:00
|
|
|
__FILE__, __LINE__,
|
|
|
|
"%s: Truncating string value of %s for %s"
|
|
|
|
" as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)",
|
2020-12-02 00:01:20 +00:00
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname,
|
|
|
|
t_outStrSz, VL_MULS_MAX_WORDS, bytes);
|
|
|
|
bytes = t_outStrSz;
|
2019-05-09 01:13:38 +00:00
|
|
|
}
|
2020-06-12 22:38:01 +00:00
|
|
|
for (i = 0; i < bytes; ++i) {
|
|
|
|
char val = datap[bytes - i - 1];
|
|
|
|
// other simulators replace [leading?] zero chars with spaces, replicate here.
|
2020-12-02 00:01:20 +00:00
|
|
|
t_outStr[i] = val ? val : ' ';
|
2019-05-09 01:13:38 +00:00
|
|
|
}
|
2020-12-02 00:01:20 +00:00
|
|
|
t_outStr[i] = '\0';
|
2019-05-09 01:13:38 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-06-12 22:38:01 +00:00
|
|
|
} else if (valuep->format == vpiIntVal) {
|
|
|
|
if (varp->vltype() == VLVT_UINT8) {
|
|
|
|
valuep->value.integer = *(reinterpret_cast<CData*>(varDatap));
|
|
|
|
return;
|
|
|
|
} else if (varp->vltype() == VLVT_UINT16) {
|
|
|
|
valuep->value.integer = *(reinterpret_cast<SData*>(varDatap));
|
|
|
|
return;
|
|
|
|
} else if (varp->vltype() == VLVT_UINT32) {
|
|
|
|
valuep->value.integer = *(reinterpret_cast<IData*>(varDatap));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else if (valuep->format == vpiSuppressVal) {
|
|
|
|
return;
|
|
|
|
}
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported format (%s) as requested for %s", VL_FUNC,
|
2020-06-12 22:38:01 +00:00
|
|
|
VerilatedVpiError::strFromVpiVal(valuep->format), fullname);
|
|
|
|
}
|
|
|
|
|
|
|
|
void vpi_get_value(vpiHandle object, p_vpi_value valuep) {
|
|
|
|
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_get_value %p\n", object););
|
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_RESET_();
|
2020-06-12 22:38:01 +00:00
|
|
|
if (VL_UNLIKELY(!valuep)) return;
|
|
|
|
|
|
|
|
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
|
|
|
|
vl_get_value(vop->varp(), vop->varDatap(), valuep, vop->fullname());
|
|
|
|
return;
|
|
|
|
} else if (VerilatedVpioParam* vop = VerilatedVpioParam::castp(object)) {
|
|
|
|
vl_get_value(vop->varp(), vop->varDatap(), valuep, vop->fullname());
|
2019-05-09 01:13:38 +00:00
|
|
|
return;
|
2020-04-14 02:51:35 +00:00
|
|
|
} else if (VerilatedVpioConst* vop = VerilatedVpioConst::castp(object)) {
|
2020-06-12 22:38:01 +00:00
|
|
|
if (valuep->format == vpiIntVal) {
|
|
|
|
valuep->value.integer = vop->num();
|
2020-04-14 02:51:35 +00:00
|
|
|
return;
|
2019-05-09 01:13:38 +00:00
|
|
|
}
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s", VL_FUNC,
|
2020-06-12 22:38:01 +00:00
|
|
|
VerilatedVpiError::strFromVpiVal(valuep->format), vop->fullname());
|
2015-09-26 02:57:28 +00:00
|
|
|
return;
|
|
|
|
}
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported vpiHandle (%p)", VL_FUNC, object);
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
|
2020-06-12 22:38:01 +00:00
|
|
|
vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_p*/,
|
2020-04-04 02:31:54 +00:00
|
|
|
PLI_INT32 /*flags*/) {
|
2020-06-12 22:38:01 +00:00
|
|
|
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_put_value %p %p\n", object, valuep););
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_RESET_();
|
2020-06-12 22:38:01 +00:00
|
|
|
if (VL_UNLIKELY(!valuep)) {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_WARNING_(__FILE__, __LINE__, "Ignoring vpi_put_value with nullptr value pointer");
|
2020-11-11 02:40:14 +00:00
|
|
|
return nullptr;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
if (VerilatedVpioVar* vop = VerilatedVpioVar::castp(object)) {
|
2020-04-14 02:51:35 +00:00
|
|
|
VL_DEBUG_IF_PLI(
|
|
|
|
VL_DBG_MSGF("- vpi: vpi_put_value name=%s fmt=%d vali=%d\n", vop->fullname(),
|
2020-06-12 22:38:01 +00:00
|
|
|
valuep->format, valuep->value.integer);
|
2020-04-14 02:51:35 +00:00
|
|
|
VL_DBG_MSGF("- vpi: varp=%p putatp=%p\n", vop->varp()->datap(), vop->varDatap()););
|
2020-06-12 22:38:01 +00:00
|
|
|
|
2019-05-09 01:13:38 +00:00
|
|
|
if (VL_UNLIKELY(!vop->varp()->isPublicRW())) {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_WARNING_(__FILE__, __LINE__,
|
2019-05-15 02:49:21 +00:00
|
|
|
"Ignoring vpi_put_value to signal marked read-only,"
|
2020-06-12 22:38:01 +00:00
|
|
|
" use public_flat_rw instead: %s",
|
2018-03-10 21:32:04 +00:00
|
|
|
vop->fullname());
|
2020-11-11 02:40:14 +00:00
|
|
|
return nullptr;
|
2019-05-09 01:13:38 +00:00
|
|
|
}
|
2020-11-11 02:40:14 +00:00
|
|
|
if (!vl_check_format(vop->varp(), valuep, vop->fullname(), false)) return nullptr;
|
2020-06-12 22:38:01 +00:00
|
|
|
if (valuep->format == vpiVectorVal) {
|
2020-08-15 14:12:55 +00:00
|
|
|
if (VL_UNLIKELY(!valuep->value.vector)) return nullptr;
|
2020-06-12 22:38:01 +00:00
|
|
|
if (vop->varp()->vltype() == VLVT_UINT8) {
|
2019-05-09 01:13:38 +00:00
|
|
|
*(reinterpret_cast<CData*>(vop->varDatap()))
|
2020-06-12 22:38:01 +00:00
|
|
|
= valuep->value.vector[0].aval & vop->mask();
|
2019-05-09 01:13:38 +00:00
|
|
|
return object;
|
2020-06-12 22:38:01 +00:00
|
|
|
} else if (vop->varp()->vltype() == VLVT_UINT16) {
|
2019-05-09 01:13:38 +00:00
|
|
|
*(reinterpret_cast<SData*>(vop->varDatap()))
|
2020-06-12 22:38:01 +00:00
|
|
|
= valuep->value.vector[0].aval & vop->mask();
|
2019-05-09 01:13:38 +00:00
|
|
|
return object;
|
2020-06-12 22:38:01 +00:00
|
|
|
} else if (vop->varp()->vltype() == VLVT_UINT32) {
|
2019-05-09 01:13:38 +00:00
|
|
|
*(reinterpret_cast<IData*>(vop->varDatap()))
|
2020-06-12 22:38:01 +00:00
|
|
|
= valuep->value.vector[0].aval & vop->mask();
|
|
|
|
return object;
|
|
|
|
} else if (vop->varp()->vltype() == VLVT_UINT64) {
|
2021-03-04 03:53:50 +00:00
|
|
|
*(reinterpret_cast<QData*>(vop->varDatap())) = VL_SET_QII(
|
2020-06-12 22:38:01 +00:00
|
|
|
valuep->value.vector[1].aval & vop->mask(), valuep->value.vector[0].aval);
|
2019-05-09 01:13:38 +00:00
|
|
|
return object;
|
2020-06-12 22:38:01 +00:00
|
|
|
} else if (vop->varp()->vltype() == VLVT_WDATA) {
|
2017-12-16 15:52:43 +00:00
|
|
|
int words = VL_WORDS_I(vop->varp()->packed().elements());
|
2019-12-09 02:36:38 +00:00
|
|
|
WDataOutP datap = (reinterpret_cast<EData*>(vop->varDatap()));
|
2020-04-14 02:51:35 +00:00
|
|
|
for (int i = 0; i < words; ++i) {
|
2020-06-12 22:38:01 +00:00
|
|
|
datap[i] = valuep->value.vector[i].aval;
|
2020-04-14 02:51:35 +00:00
|
|
|
if (i == (words - 1)) datap[i] &= vop->mask();
|
2019-05-09 01:13:38 +00:00
|
|
|
}
|
|
|
|
return object;
|
|
|
|
}
|
2020-06-12 22:38:01 +00:00
|
|
|
} else if (valuep->format == vpiBinStrVal) {
|
|
|
|
int bits = vop->varp()->packed().elements();
|
|
|
|
int len = strlen(valuep->value.str);
|
|
|
|
CData* datap = (reinterpret_cast<CData*>(vop->varDatap()));
|
|
|
|
for (int i = 0; i < bits; ++i) {
|
|
|
|
char set = (i < len) ? (valuep->value.str[len - i - 1] == '1') : 0;
|
|
|
|
// zero bits 7:1 of byte when assigning to bit 0, else
|
|
|
|
// or in 1 if bit set
|
|
|
|
if (i & 7) {
|
|
|
|
datap[i >> 3] |= set << (i & 7);
|
|
|
|
} else {
|
|
|
|
datap[i >> 3] = set;
|
2019-05-09 01:13:38 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-12 22:38:01 +00:00
|
|
|
return object;
|
|
|
|
} else if (valuep->format == vpiOctStrVal) {
|
|
|
|
int chars = (vop->varp()->packed().elements() + 2) / 3;
|
|
|
|
int bytes = VL_BYTES_I(vop->varp()->packed().elements());
|
|
|
|
int len = strlen(valuep->value.str);
|
|
|
|
CData* datap = (reinterpret_cast<CData*>(vop->varDatap()));
|
|
|
|
div_t idx;
|
|
|
|
datap[0] = 0; // reset zero'th byte
|
|
|
|
for (int i = 0; i < chars; ++i) {
|
|
|
|
union {
|
|
|
|
char byte[2];
|
2020-08-16 18:55:46 +00:00
|
|
|
vluint16_t half;
|
2020-06-12 22:38:01 +00:00
|
|
|
} val;
|
|
|
|
idx = div(i * 3, 8);
|
|
|
|
if (i < len) {
|
|
|
|
// ignore illegal chars
|
|
|
|
char digit = valuep->value.str[len - i - 1];
|
|
|
|
if (digit >= '0' && digit <= '7') {
|
|
|
|
val.half = digit - '0';
|
2019-05-09 01:13:38 +00:00
|
|
|
} else {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_WARNING_(__FILE__, __LINE__,
|
2020-06-12 22:38:01 +00:00
|
|
|
"%s: Non octal character '%c' in '%s' as value %s for %s",
|
|
|
|
VL_FUNC, digit, valuep->value.str,
|
|
|
|
VerilatedVpiError::strFromVpiVal(valuep->format),
|
|
|
|
vop->fullname());
|
2015-09-26 02:57:28 +00:00
|
|
|
val.half = 0;
|
2019-05-09 01:13:38 +00:00
|
|
|
}
|
2020-06-12 22:38:01 +00:00
|
|
|
} else {
|
|
|
|
val.half = 0;
|
2018-11-29 00:59:10 +00:00
|
|
|
}
|
2020-06-12 22:38:01 +00:00
|
|
|
// align octal character to position within vector, note that
|
|
|
|
// the three bits may straddle a byte boundary so two byte wide
|
|
|
|
// assignments are made to adjacent bytes - but not if the least
|
|
|
|
// significant byte of the aligned value is the most significant
|
|
|
|
// byte of the destination.
|
|
|
|
val.half <<= idx.rem;
|
|
|
|
datap[idx.quot] |= val.byte[0]; // or in value
|
|
|
|
if ((idx.quot + 1) < bytes) {
|
|
|
|
datap[idx.quot + 1] = val.byte[1]; // this also resets
|
|
|
|
// all bits to 0 prior to or'ing above
|
2019-05-09 01:13:38 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-12 22:38:01 +00:00
|
|
|
// mask off non-existent bits in the most significant byte
|
|
|
|
if (idx.quot == (bytes - 1)) {
|
|
|
|
datap[idx.quot] &= vop->mask_byte(idx.quot);
|
|
|
|
} else if (idx.quot + 1 == (bytes - 1)) {
|
|
|
|
datap[idx.quot + 1] &= vop->mask_byte(idx.quot + 1);
|
2019-05-09 01:13:38 +00:00
|
|
|
}
|
2020-06-12 22:38:01 +00:00
|
|
|
// zero off remaining top bytes
|
|
|
|
for (int i = idx.quot + 2; i < bytes; ++i) datap[i] = 0;
|
|
|
|
return object;
|
|
|
|
} else if (valuep->format == vpiDecStrVal) {
|
2015-09-26 02:57:28 +00:00
|
|
|
char remainder[16];
|
|
|
|
unsigned long long val;
|
2020-06-12 22:38:01 +00:00
|
|
|
int success = sscanf(valuep->value.str, "%30llu%15s", &val, remainder);
|
2015-09-26 02:57:28 +00:00
|
|
|
if (success < 1) {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Parsing failed for '%s' as value %s for %s",
|
2020-06-12 22:38:01 +00:00
|
|
|
VL_FUNC, valuep->value.str,
|
|
|
|
VerilatedVpiError::strFromVpiVal(valuep->format), vop->fullname());
|
2020-11-11 02:40:14 +00:00
|
|
|
return nullptr;
|
2019-05-09 01:13:38 +00:00
|
|
|
}
|
2015-09-26 02:57:28 +00:00
|
|
|
if (success > 1) {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_WARNING_(__FILE__, __LINE__,
|
2020-06-12 22:38:01 +00:00
|
|
|
"%s: Trailing garbage '%s' in '%s' as value %s for %s", VL_FUNC,
|
|
|
|
remainder, valuep->value.str,
|
|
|
|
VerilatedVpiError::strFromVpiVal(valuep->format), vop->fullname());
|
2019-05-09 01:13:38 +00:00
|
|
|
}
|
2020-06-12 22:38:01 +00:00
|
|
|
if (vop->varp()->vltype() == VLVT_UINT8) {
|
2020-04-14 02:51:35 +00:00
|
|
|
*(reinterpret_cast<CData*>(vop->varDatap())) = val & vop->mask();
|
2020-06-12 22:38:01 +00:00
|
|
|
return object;
|
|
|
|
} else if (vop->varp()->vltype() == VLVT_UINT16) {
|
2020-04-14 02:51:35 +00:00
|
|
|
*(reinterpret_cast<SData*>(vop->varDatap())) = val & vop->mask();
|
2020-06-12 22:38:01 +00:00
|
|
|
return object;
|
|
|
|
} else if (vop->varp()->vltype() == VLVT_UINT32) {
|
2020-04-14 02:51:35 +00:00
|
|
|
*(reinterpret_cast<IData*>(vop->varDatap())) = val & vop->mask();
|
2020-06-12 22:38:01 +00:00
|
|
|
return object;
|
|
|
|
} else if (vop->varp()->vltype() == VLVT_UINT64) {
|
2020-04-14 02:51:35 +00:00
|
|
|
*(reinterpret_cast<QData*>(vop->varDatap())) = val;
|
|
|
|
(reinterpret_cast<IData*>(vop->varDatap()))[1] &= vop->mask();
|
2020-06-12 22:38:01 +00:00
|
|
|
return object;
|
2019-05-09 01:13:38 +00:00
|
|
|
}
|
2020-06-12 22:38:01 +00:00
|
|
|
} else if (valuep->format == vpiHexStrVal) {
|
|
|
|
int chars = (vop->varp()->packed().elements() + 3) >> 2;
|
|
|
|
CData* datap = (reinterpret_cast<CData*>(vop->varDatap()));
|
|
|
|
char* val = valuep->value.str;
|
|
|
|
// skip hex ident if one is detected at the start of the string
|
|
|
|
if (val[0] == '0' && (val[1] == 'x' || val[1] == 'X')) val += 2;
|
|
|
|
int len = strlen(val);
|
|
|
|
for (int i = 0; i < chars; ++i) {
|
|
|
|
char hex;
|
|
|
|
// compute hex digit value
|
|
|
|
if (i < len) {
|
|
|
|
char digit = val[len - i - 1];
|
|
|
|
if (digit >= '0' && digit <= '9') {
|
|
|
|
hex = digit - '0';
|
|
|
|
} else if (digit >= 'a' && digit <= 'f') {
|
|
|
|
hex = digit - 'a' + 10;
|
|
|
|
} else if (digit >= 'A' && digit <= 'F') {
|
|
|
|
hex = digit - 'A' + 10;
|
2019-05-09 01:13:38 +00:00
|
|
|
} else {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_WARNING_(__FILE__, __LINE__,
|
2020-06-12 22:38:01 +00:00
|
|
|
"%s: Non hex character '%c' in '%s' as value %s for %s",
|
|
|
|
VL_FUNC, digit, valuep->value.str,
|
|
|
|
VerilatedVpiError::strFromVpiVal(valuep->format),
|
|
|
|
vop->fullname());
|
2019-05-09 01:13:38 +00:00
|
|
|
hex = 0;
|
|
|
|
}
|
2020-06-12 22:38:01 +00:00
|
|
|
} else {
|
|
|
|
hex = 0;
|
2018-11-29 00:59:10 +00:00
|
|
|
}
|
2020-06-12 22:38:01 +00:00
|
|
|
// assign hex digit value to destination
|
|
|
|
if (i & 1) {
|
|
|
|
datap[i >> 1] |= hex << 4;
|
|
|
|
} else {
|
|
|
|
datap[i >> 1] = hex; // this also resets all
|
|
|
|
// bits to 0 prior to or'ing above of the msb
|
2019-05-09 01:13:38 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-12 22:38:01 +00:00
|
|
|
// apply bit mask to most significant byte
|
|
|
|
datap[(chars - 1) >> 1] &= vop->mask_byte((chars - 1) >> 1);
|
|
|
|
return object;
|
|
|
|
} else if (valuep->format == vpiStringVal) {
|
|
|
|
int bytes = VL_BYTES_I(vop->varp()->packed().elements());
|
|
|
|
int len = strlen(valuep->value.str);
|
|
|
|
CData* datap = (reinterpret_cast<CData*>(vop->varDatap()));
|
|
|
|
for (int i = 0; i < bytes; ++i) {
|
|
|
|
// prepend with 0 values before placing string the least significant bytes
|
|
|
|
datap[i] = (i < len) ? valuep->value.str[len - i - 1] : 0;
|
2019-05-09 01:13:38 +00:00
|
|
|
}
|
2020-06-12 22:38:01 +00:00
|
|
|
return object;
|
|
|
|
} else if (valuep->format == vpiIntVal) {
|
|
|
|
if (vop->varp()->vltype() == VLVT_UINT8) {
|
|
|
|
*(reinterpret_cast<CData*>(vop->varDatap())) = vop->mask() & valuep->value.integer;
|
2019-05-09 01:13:38 +00:00
|
|
|
return object;
|
2020-06-12 22:38:01 +00:00
|
|
|
} else if (vop->varp()->vltype() == VLVT_UINT16) {
|
|
|
|
*(reinterpret_cast<SData*>(vop->varDatap())) = vop->mask() & valuep->value.integer;
|
2019-05-09 01:13:38 +00:00
|
|
|
return object;
|
2020-06-12 22:38:01 +00:00
|
|
|
} else if (vop->varp()->vltype() == VLVT_UINT32) {
|
|
|
|
*(reinterpret_cast<IData*>(vop->varDatap())) = vop->mask() & valuep->value.integer;
|
2019-05-09 01:13:38 +00:00
|
|
|
return object;
|
|
|
|
}
|
|
|
|
}
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported format (%s) as requested for %s",
|
2020-06-12 22:38:01 +00:00
|
|
|
VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), vop->fullname());
|
2020-08-15 14:12:55 +00:00
|
|
|
return nullptr;
|
2020-06-12 22:38:01 +00:00
|
|
|
} else if (VerilatedVpioParam* vop = VerilatedVpioParam::castp(object)) {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_WARNING_(__FILE__, __LINE__, "%s: Ignoring vpi_put_value to vpiParameter: %s",
|
2020-06-12 22:38:01 +00:00
|
|
|
VL_FUNC, vop->fullname());
|
2020-11-11 02:40:14 +00:00
|
|
|
return nullptr;
|
2020-06-12 22:38:01 +00:00
|
|
|
} else if (VerilatedVpioConst* vop = VerilatedVpioConst::castp(object)) {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_WARNING_(__FILE__, __LINE__, "%s: Ignoring vpi_put_value to vpiConstant: %s",
|
2020-06-12 22:38:01 +00:00
|
|
|
VL_FUNC, vop->fullname());
|
2020-11-11 02:40:14 +00:00
|
|
|
return nullptr;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported vpiHandle (%p)", VL_FUNC, object);
|
2020-08-15 14:12:55 +00:00
|
|
|
return nullptr;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
|
2020-04-04 02:31:54 +00:00
|
|
|
void vpi_get_value_array(vpiHandle /*object*/, p_vpi_arrayvalue /*arrayvalue_p*/,
|
|
|
|
PLI_INT32* /*index_p*/, PLI_UINT32 /*num*/) {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_UNIMP_();
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
2020-04-04 02:31:54 +00:00
|
|
|
void vpi_put_value_array(vpiHandle /*object*/, p_vpi_arrayvalue /*arrayvalue_p*/,
|
|
|
|
PLI_INT32* /*index_p*/, PLI_UINT32 /*num*/) {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_UNIMP_();
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// time processing
|
|
|
|
|
2020-04-15 23:39:03 +00:00
|
|
|
void vpi_get_time(vpiHandle object, p_vpi_time time_p) {
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_RESET_();
|
2017-11-23 15:43:34 +00:00
|
|
|
// cppcheck-suppress nullPointer
|
2015-09-26 02:57:28 +00:00
|
|
|
if (VL_UNLIKELY(!time_p)) {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_WARNING_(__FILE__, __LINE__, "Ignoring vpi_get_time with nullptr value pointer");
|
2019-05-09 01:13:38 +00:00
|
|
|
return;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
if (time_p->type == vpiSimTime) {
|
2019-05-09 01:13:38 +00:00
|
|
|
QData qtime = VL_TIME_Q();
|
|
|
|
WData itime[2];
|
|
|
|
VL_SET_WQ(itime, qtime);
|
|
|
|
time_p->low = itime[0];
|
|
|
|
time_p->high = itime[1];
|
|
|
|
return;
|
2020-04-15 23:39:03 +00:00
|
|
|
} else if (time_p->type == vpiScaledRealTime) {
|
|
|
|
double dtime = VL_TIME_D();
|
|
|
|
if (VerilatedVpioScope* vop = VerilatedVpioScope::castp(object)) {
|
|
|
|
int scalePow10 = Verilated::timeprecision() - vop->scopep()->timeunit();
|
|
|
|
double scale = vl_time_multiplier(scalePow10); // e.g. 0.0001
|
|
|
|
dtime *= scale;
|
|
|
|
}
|
|
|
|
time_p->real = dtime;
|
|
|
|
return;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported type (%d)", VL_FUNC, time_p->type);
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// I/O routines
|
|
|
|
|
2020-04-14 02:51:35 +00:00
|
|
|
PLI_UINT32 vpi_mcd_open(PLI_BYTE8* filenamep) {
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_RESET_();
|
2020-05-14 22:03:00 +00:00
|
|
|
return VL_FOPEN_NN(filenamep, "wb");
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PLI_UINT32 vpi_mcd_close(PLI_UINT32 mcd) {
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_RESET_();
|
2020-04-04 02:31:54 +00:00
|
|
|
VL_FCLOSE_I(mcd);
|
|
|
|
return 0;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
|
2020-04-04 02:31:54 +00:00
|
|
|
PLI_BYTE8* vpi_mcd_name(PLI_UINT32 /*mcd*/) {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_UNIMP_();
|
2020-11-11 02:40:14 +00:00
|
|
|
return nullptr;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
|
2020-04-14 02:51:35 +00:00
|
|
|
PLI_INT32 vpi_mcd_printf(PLI_UINT32 mcd, PLI_BYTE8* formatp, ...) {
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_RESET_();
|
2015-09-26 02:57:28 +00:00
|
|
|
va_list ap;
|
2019-05-09 01:13:38 +00:00
|
|
|
va_start(ap, formatp);
|
2015-09-26 02:57:28 +00:00
|
|
|
int chars = vpi_mcd_vprintf(mcd, formatp, ap);
|
|
|
|
va_end(ap);
|
|
|
|
return chars;
|
|
|
|
}
|
|
|
|
|
2020-04-14 02:51:35 +00:00
|
|
|
PLI_INT32 vpi_printf(PLI_BYTE8* formatp, ...) {
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_RESET_();
|
2015-09-26 02:57:28 +00:00
|
|
|
va_list ap;
|
2019-05-09 01:13:38 +00:00
|
|
|
va_start(ap, formatp);
|
2015-09-26 02:57:28 +00:00
|
|
|
int chars = vpi_vprintf(formatp, ap);
|
|
|
|
va_end(ap);
|
|
|
|
return chars;
|
|
|
|
}
|
|
|
|
|
|
|
|
PLI_INT32 vpi_vprintf(PLI_BYTE8* formatp, va_list ap) {
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_RESET_();
|
2015-09-26 02:57:28 +00:00
|
|
|
return VL_VPRINTF(formatp, ap);
|
|
|
|
}
|
|
|
|
|
2020-04-14 02:51:35 +00:00
|
|
|
PLI_INT32 vpi_mcd_vprintf(PLI_UINT32 mcd, PLI_BYTE8* format, va_list ap) {
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2015-09-26 02:57:28 +00:00
|
|
|
FILE* fp = VL_CVT_I_FP(mcd);
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_RESET_();
|
2015-10-04 02:33:06 +00:00
|
|
|
// cppcheck-suppress nullPointer
|
2015-09-26 02:57:28 +00:00
|
|
|
if (VL_UNLIKELY(!fp)) return 0;
|
|
|
|
int chars = vfprintf(fp, format, ap);
|
|
|
|
return chars;
|
|
|
|
}
|
|
|
|
|
|
|
|
PLI_INT32 vpi_flush(void) {
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_RESET_();
|
2020-06-12 06:15:42 +00:00
|
|
|
Verilated::runFlushCallbacks();
|
2015-09-26 02:57:28 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
PLI_INT32 vpi_mcd_flush(PLI_UINT32 mcd) {
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2015-09-26 02:57:28 +00:00
|
|
|
FILE* fp = VL_CVT_I_FP(mcd);
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_RESET_();
|
2015-09-26 02:57:28 +00:00
|
|
|
if (VL_UNLIKELY(!fp)) return 1;
|
|
|
|
fflush(fp);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// utility routines
|
|
|
|
|
2020-04-04 02:31:54 +00:00
|
|
|
PLI_INT32 vpi_compare_objects(vpiHandle /*object1*/, vpiHandle /*object2*/) {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_UNIMP_();
|
2020-04-04 02:31:54 +00:00
|
|
|
return 0;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
PLI_INT32 vpi_chk_error(p_vpi_error_info error_info_p) {
|
|
|
|
// executing vpi_chk_error does not reset error
|
2020-08-15 14:12:55 +00:00
|
|
|
// error_info_p can be nullptr, so only return level in that case
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2017-10-20 01:33:22 +00:00
|
|
|
p_vpi_error_info _error_info_p = VerilatedVpiImp::error_info()->getError();
|
2020-04-14 02:51:35 +00:00
|
|
|
if (error_info_p && _error_info_p) *error_info_p = *_error_info_p;
|
2018-11-29 00:59:10 +00:00
|
|
|
if (!_error_info_p) return 0; // no error occured
|
2015-09-26 02:57:28 +00:00
|
|
|
return _error_info_p->level; // return error severity level
|
2020-02-04 03:10:29 +00:00
|
|
|
}
|
2015-09-26 02:57:28 +00:00
|
|
|
|
2021-02-23 03:59:23 +00:00
|
|
|
#ifndef VL_NO_LEGACY
|
2015-09-26 02:57:28 +00:00
|
|
|
PLI_INT32 vpi_free_object(vpiHandle object) {
|
2020-12-17 00:10:17 +00:00
|
|
|
// vpi_free_object is IEEE deprecated, use vpi_release_handle
|
|
|
|
return vpi_release_handle(object);
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
2021-02-23 03:59:23 +00:00
|
|
|
#endif
|
2015-09-26 02:57:28 +00:00
|
|
|
|
2018-08-25 13:52:45 +00:00
|
|
|
PLI_INT32 vpi_release_handle(vpiHandle object) {
|
2019-05-09 01:13:38 +00:00
|
|
|
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_release_handle %p\n", object););
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2015-09-26 02:57:28 +00:00
|
|
|
VerilatedVpio* vop = VerilatedVpio::castp(object);
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_RESET_();
|
2015-09-26 02:57:28 +00:00
|
|
|
if (VL_UNLIKELY(!vop)) return 0;
|
2020-01-17 01:17:11 +00:00
|
|
|
VL_DO_DANGLING(delete vop, vop);
|
2015-09-26 02:57:28 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-10-27 01:51:51 +00:00
|
|
|
PLI_INT32 vpi_get_vlog_info(p_vpi_vlog_info vlog_info_p) VL_MT_SAFE {
|
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_RESET_();
|
2015-09-26 02:57:28 +00:00
|
|
|
vlog_info_p->argc = Verilated::getCommandArgs()->argc;
|
2020-04-04 02:31:54 +00:00
|
|
|
vlog_info_p->argv = const_cast<PLI_BYTE8**>(Verilated::getCommandArgs()->argv);
|
|
|
|
vlog_info_p->product = const_cast<PLI_BYTE8*>(Verilated::productName());
|
|
|
|
vlog_info_p->version = const_cast<PLI_BYTE8*>(Verilated::productVersion());
|
2015-09-26 02:57:28 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// routines added with 1364-2001
|
|
|
|
|
2020-04-04 02:31:54 +00:00
|
|
|
PLI_INT32 vpi_get_data(PLI_INT32 /*id*/, PLI_BYTE8* /*dataLoc*/, PLI_INT32 /*numOfBytes*/) {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_UNIMP_();
|
2020-04-04 02:31:54 +00:00
|
|
|
return 0;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
2020-04-04 02:31:54 +00:00
|
|
|
PLI_INT32 vpi_put_data(PLI_INT32 /*id*/, PLI_BYTE8* /*dataLoc*/, PLI_INT32 /*numOfBytes*/) {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_UNIMP_();
|
2020-04-04 02:31:54 +00:00
|
|
|
return 0;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
2020-04-04 02:31:54 +00:00
|
|
|
void* vpi_get_userdata(vpiHandle /*obj*/) {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_UNIMP_();
|
2020-11-11 02:40:14 +00:00
|
|
|
return nullptr;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
2020-04-04 02:31:54 +00:00
|
|
|
PLI_INT32 vpi_put_userdata(vpiHandle /*obj*/, void* /*userdata*/) {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_UNIMP_();
|
2020-04-04 02:31:54 +00:00
|
|
|
return 0;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PLI_INT32 vpi_control(PLI_INT32 operation, ...) {
|
2019-05-09 01:13:38 +00:00
|
|
|
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_control %d\n", operation););
|
2017-10-27 01:51:51 +00:00
|
|
|
VerilatedVpiImp::assertOneCheck();
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_ERROR_RESET_();
|
2015-09-26 02:57:28 +00:00
|
|
|
switch (operation) {
|
|
|
|
case vpiFinish: {
|
2020-05-16 22:02:54 +00:00
|
|
|
VL_FINISH_MT("", 0, "*VPI*");
|
2019-05-09 01:13:38 +00:00
|
|
|
return 1;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
case vpiStop: {
|
2020-05-16 22:02:54 +00:00
|
|
|
VL_STOP_MT("", 0, "*VPI*");
|
2020-06-04 23:49:18 +00:00
|
|
|
return 1; // LCOV_EXCL_LINE
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
2020-06-02 03:16:02 +00:00
|
|
|
default: {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_WARNING_(__FILE__, __LINE__, "%s: Unsupported type %s, ignoring", VL_FUNC,
|
2020-06-02 03:16:02 +00:00
|
|
|
VerilatedVpiError::strFromVpiProp(operation));
|
|
|
|
return 0;
|
|
|
|
}
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-04 02:31:54 +00:00
|
|
|
vpiHandle vpi_handle_by_multi_index(vpiHandle /*obj*/, PLI_INT32 /*num_index*/,
|
|
|
|
PLI_INT32* /*index_array*/) {
|
2021-03-04 03:53:50 +00:00
|
|
|
VL_VPI_UNIMP_();
|
2020-11-11 02:40:14 +00:00
|
|
|
return nullptr;
|
2015-09-26 02:57:28 +00:00
|
|
|
}
|