Support vpi_put/vpi_get forcing of signals (#5933) (#6704).

This commit is contained in:
Christian Hecken
2026-01-10 03:48:46 -05:00
committed by Wilson Snyder
parent a98eb4fa04
commit 338afff23c
20 changed files with 2146 additions and 56 deletions
+319 -54
View File
@@ -24,12 +24,12 @@
///
//=========================================================================
#include "verilatedos.h"
#define VERILATOR_VERILATED_VPI_CPP_
#include "verilated_vpi.h"
#include "verilated.h"
#include "verilated_imp.h"
#include "verilated_vpi.h"
#include "vltstd/vpi_user.h"
@@ -880,6 +880,7 @@ struct VerilatedVpiTimedCbsCmp final {
};
class VerilatedVpiError;
void vl_vpi_put_word(const VerilatedVpioVar* vop, QData word, size_t bitCount, size_t addOffset);
class VerilatedVpiImp final {
enum { CB_ENUM_MAX_VALUE = cbAtEndOfSimTime + 1 }; // Maximum callback reason
@@ -1075,6 +1076,47 @@ public:
}
s().m_inertialPuts.clear();
}
static std::pair<vpiHandle, vpiHandle> getForceControlSignals(const VerilatedVpioVarBase* vop);
static std::size_t vlTypeSize(VerilatedVarType vltype);
static void setAllBitsToValue(const VerilatedVpioVar* vop, uint8_t bitValue) {
assert(bitValue == 0 || bitValue == 1);
const uint64_t word = (bitValue == 1) ? -1ULL : 0ULL;
const std::size_t wordSize = vlTypeSize(vop->varp()->vltype());
assert(wordSize > 0);
const uint32_t varBits = vop->bitSize();
const std::size_t numChunks = (varBits / wordSize);
for (std::size_t i{0}; i < numChunks; ++i) {
vl_vpi_put_word(vop, word, wordSize, i * wordSize);
}
// addOffset == varBits would trigger assertion in vl_vpi_var_access_info even if
// bitCount == 0, so first check if there is a remainder
if (varBits % wordSize != 0)
vl_vpi_put_word(vop, word, varBits % wordSize, numChunks * wordSize);
}
// Recreates the __VforceRd signal's data vector, since __VforceRd is not publicly accessible
// in Verilated code.
template <typename T>
static std::vector<T>
createReadDataVector(const void* const baseSignalDatap,
const std::pair<const void*, const void*> forceControlDatap,
const std::size_t bitCount) {
const void* const forceEnableDatap = forceControlDatap.first;
const void* const forceValueDatap = forceControlDatap.second;
assert(bitCount > 0);
const std::size_t numWords = (bitCount + (8 * sizeof(T)) - 1) / (8 * sizeof(T)); // Ceil
std::vector<T> readData(numWords);
for (std::size_t i{0}; i < numWords; ++i) {
const T forceEnableWord = reinterpret_cast<const T*>(forceEnableDatap)[i];
const T forceValueWord = reinterpret_cast<const T*>(forceValueDatap)[i];
const T baseSignalWord = reinterpret_cast<const T*>(baseSignalDatap)[i];
const T readDataWord
= (forceEnableWord & forceValueWord) | (~forceEnableWord & baseSignalWord);
readData[i] = readDataWord;
}
return readData;
}
};
//======================================================================
@@ -1229,6 +1271,47 @@ VerilatedVpiError* VerilatedVpiImp::error_info() VL_MT_UNSAFE_ONE {
return s().m_errorInfop;
}
std::pair<vpiHandle, vpiHandle>
VerilatedVpiImp::getForceControlSignals(const VerilatedVpioVarBase* const vop) {
const std::string signalName = vop->fullname();
const std::string forceEnableSignalName = signalName + "__VforceEn";
const std::string forceValueSignalName = signalName + "__VforceVal";
vpiHandle const forceEnableSignalp // NOLINT(misc-misplaced-const)
= vpi_handle_by_name(const_cast<PLI_BYTE8*>(forceEnableSignalName.c_str()), nullptr);
vpiHandle const forceValueSignalp // NOLINT(misc-misplaced-const)
= vpi_handle_by_name(const_cast<PLI_BYTE8*>(forceValueSignalName.c_str()), nullptr);
if (VL_UNLIKELY(!VerilatedVpioVar::castp(forceEnableSignalp))) {
VL_VPI_ERROR_(__FILE__, __LINE__,
"%s: vpi force or release requested for '%s', but vpiHandle '%p' of enable "
"signal '%s' could not be cast to VerilatedVpioVar*. Ensure signal is "
"marked as forceable",
__func__, signalName.c_str(), forceEnableSignalp,
forceEnableSignalName.c_str());
}
if (VL_UNLIKELY(!VerilatedVpioVar::castp(forceValueSignalp))) {
VL_VPI_ERROR_(__FILE__, __LINE__,
"%s: vpi force or release requested for '%s', but vpiHandle '%p' of value "
"signal '%s' could not be cast to VerilatedVpioVar*. Ensure signal is "
"marked as forceable",
__func__, signalName.c_str(), forceValueSignalp,
forceValueSignalName.c_str());
}
return {forceEnableSignalp, forceValueSignalp};
};
std::size_t VerilatedVpiImp::vlTypeSize(const VerilatedVarType vltype) {
switch (vltype) {
case VLVT_UINT8: return sizeof(CData); break;
case VLVT_UINT16: return sizeof(SData); break;
case VLVT_UINT32: return sizeof(IData); break;
case VLVT_UINT64: return sizeof(QData); break;
case VLVT_WDATA: return sizeof(EData); break;
default: // LCOV_EXCL_START
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported vltype (%d)", __func__, vltype);
return 0;
} // LCOV_EXCL_STOP
}
//======================================================================
// VerilatedVpiError Methods
@@ -2609,6 +2692,66 @@ void vl_vpi_get_value(const VerilatedVpioVarBase* vop, p_vpi_value valuep) {
const int varBits = vop->bitSize();
// __VforceRd already has the correct value, but that signal is not public and thus not
// present in the scope's m_varsp map, so its value has to be recreated using the __VforceEn
// and __VforceVal signals.
// TODO: Implement a way to retrieve __VforceRd, rather than needing to recreate it.
const auto forceControlSignals = vop->varp()->isForceable()
? VerilatedVpiImp::getForceControlSignals(vop)
: std::pair<vpiHandle, vpiHandle>{nullptr, nullptr};
const vpiHandle& forceEnableSignalp = forceControlSignals.first;
const vpiHandle& forceValueSignalp = forceControlSignals.second;
const VerilatedVpioVarBase* const forceEnableSignalVop
= vop->varp()->isForceable() ? VerilatedVpioVar::castp(forceEnableSignalp) : nullptr;
const VerilatedVpioVarBase* const forceValueSignalVop
= vop->varp()->isForceable() ? VerilatedVpioVar::castp(forceValueSignalp) : nullptr;
t_vpi_error_info getForceControlSignalsError{};
const bool errorOccurred = vpi_chk_error(&getForceControlSignalsError);
// LCOV_EXCL_START - Cannot test, since getForceControlSignals does not (currently) produce
// any notices or warnings.
if (errorOccurred && getForceControlSignalsError.level < vpiError) {
vpi_printf(getForceControlSignalsError.message);
VL_VPI_ERROR_RESET_();
} // LCOV_EXCL_STOP
// NOLINTNEXTLINE(readability-simplify-boolean-expr);
if (VL_UNLIKELY((errorOccurred && getForceControlSignalsError.level >= vpiError)
|| (vop->varp()->isForceable()
&& (!forceEnableSignalp || !forceEnableSignalVop || !forceValueSignalp
|| !forceValueSignalVop)))) {
// Check if getForceControlSignals provided any additional error info
t_vpi_error_info getForceControlSignalsError{};
const bool gotErrorMessage = vpi_chk_error(&getForceControlSignalsError);
const std::string previousErrorMessage
= gotErrorMessage
? std::string{" Error message: "} + getForceControlSignalsError.message
: "";
VL_VPI_ERROR_(__FILE__, __LINE__,
"%s: Signal '%s' is marked forceable, but force "
"control signals could not be retrieved.%s",
__func__, vop->fullname(),
gotErrorMessage ? previousErrorMessage.c_str() : "");
return;
}
const std::function<QData(const VerilatedVpioVarBase*, size_t, size_t)> getForceableSignalWord
= [forceEnableSignalVop, forceValueSignalVop](const VerilatedVpioVarBase* baseSignalVop,
size_t bitCount, size_t addOffset) -> QData {
// variables are QData, even though signals may have different representation, because any
// extraneous bits are simply truncated upon implicit casting when this function is called.
const QData baseSignalData = vl_vpi_get_word(baseSignalVop, bitCount, addOffset);
const QData forceEnableData = vl_vpi_get_word(forceEnableSignalVop, bitCount, addOffset);
const QData forceValueData = vl_vpi_get_word(forceValueSignalVop, bitCount, addOffset);
const QData readData
= (forceEnableData & forceValueData) | (~forceEnableData & baseSignalData);
return readData;
};
const std::function<QData(const VerilatedVpioVarBase*, size_t, size_t)> get_word
= vop->varp()->isForceable() ? getForceableSignalWord : vl_vpi_get_word;
// 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) {
@@ -2626,25 +2769,38 @@ void vl_vpi_get_value(const VerilatedVpioVarBase* vop, p_vpi_value valuep) {
return;
}
for (int i = 0; i < words; ++i) {
t_out[i].aval = vl_vpi_get_word(vop, 32, i * 32);
t_out[i].aval = get_word(vop, 32, i * 32);
t_out[i].bval = 0;
}
return;
} else if (varp->vltype() == VLVT_UINT64 && varBits > 32) {
const QData data = vl_vpi_get_word(vop, 64, 0);
const QData data = get_word(vop, 64, 0);
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;
return;
} else {
t_out[0].aval = vl_vpi_get_word(vop, 32, 0);
t_out[0].aval = get_word(vop, 32, 0);
t_out[0].bval = 0;
return;
}
} else if (valuep->format == vpiBinStrVal) {
t_outDynamicStr.resize(varBits);
const CData* datap = reinterpret_cast<CData*>(varDatap);
static thread_local std::vector<uint8_t> forceReadCData;
forceReadCData
= vop->varp()->isForceable()
? VerilatedVpiImp::createReadDataVector<uint8_t>(
varDatap,
{forceEnableSignalVop->varDatap(), forceValueSignalVop->varDatap()},
vop->bitSize())
: std::vector<uint8_t>{};
const uint8_t* const varCDatap = vop->varp()->isForceable()
? forceReadCData.data()
: reinterpret_cast<CData*>(varDatap);
const CData* datap = varCDatap;
for (size_t i = 0; i < varBits; ++i) {
const size_t pos = i + vop->bitOffset();
const char val = (datap[pos >> 3] >> (pos & 7)) & 1;
@@ -2656,24 +2812,22 @@ void vl_vpi_get_value(const VerilatedVpioVarBase* vop, p_vpi_value valuep) {
const int chars = (varBits + 2) / 3;
t_outDynamicStr.resize(chars);
for (size_t i = 0; i < chars; ++i) {
const char val = vl_vpi_get_word(vop, 3, i * 3);
const char val = get_word(vop, 3, i * 3);
t_outDynamicStr[chars - i - 1] = '0' + val;
}
valuep->value.str = const_cast<PLI_BYTE8*>(t_outDynamicStr.c_str());
return;
} else if (valuep->format == vpiDecStrVal) {
if (varp->vltype() == VLVT_UINT8) {
vl_strprintf(t_outDynamicStr, "%hhu",
static_cast<unsigned char>(vl_vpi_get_word(vop, 8, 0)));
vl_strprintf(t_outDynamicStr, "%hhu", static_cast<unsigned char>(get_word(vop, 8, 0)));
} else if (varp->vltype() == VLVT_UINT16) {
vl_strprintf(t_outDynamicStr, "%hu",
static_cast<unsigned short>(vl_vpi_get_word(vop, 16, 0)));
static_cast<unsigned short>(get_word(vop, 16, 0)));
} else if (varp->vltype() == VLVT_UINT32) {
vl_strprintf(t_outDynamicStr, "%u",
static_cast<unsigned int>(vl_vpi_get_word(vop, 32, 0)));
vl_strprintf(t_outDynamicStr, "%u", static_cast<unsigned int>(get_word(vop, 32, 0)));
} else if (varp->vltype() == VLVT_UINT64) {
vl_strprintf(t_outDynamicStr, "%llu", // lintok-format-ll
static_cast<unsigned long long>(vl_vpi_get_word(vop, 64, 0)));
static_cast<unsigned long long>(get_word(vop, 64, 0)));
}
valuep->value.str = const_cast<PLI_BYTE8*>(t_outDynamicStr.c_str());
return;
@@ -2681,7 +2835,7 @@ void vl_vpi_get_value(const VerilatedVpioVarBase* vop, p_vpi_value valuep) {
const int chars = (varBits + 3) >> 2;
t_outDynamicStr.resize(chars);
for (size_t i = 0; i < chars; ++i) {
const char val = vl_vpi_get_word(vop, 4, i * 4);
const char val = get_word(vop, 4, i * 4);
t_outDynamicStr[chars - i - 1] = "0123456789abcdef"[static_cast<int>(val)];
}
valuep->value.str = const_cast<PLI_BYTE8*>(t_outDynamicStr.c_str());
@@ -2692,7 +2846,7 @@ void vl_vpi_get_value(const VerilatedVpioVarBase* vop, p_vpi_value valuep) {
valuep->value.str = reinterpret_cast<char*>(varDatap);
return;
} else {
t_outDynamicStr = *(vop->varStringDatap());
t_outDynamicStr = *vop->varStringDatap();
valuep->value.str = const_cast<char*>(t_outDynamicStr.c_str());
return;
}
@@ -2700,7 +2854,7 @@ void vl_vpi_get_value(const VerilatedVpioVarBase* vop, p_vpi_value valuep) {
const int chars = VL_BYTES_I(varBits);
t_outDynamicStr.resize(chars);
for (size_t i = 0; i < chars; ++i) {
const char val = vl_vpi_get_word(vop, 8, i * 8);
const char val = get_word(vop, 8, i * 8);
// other simulators replace [leading?] zero chars with spaces, replicate here.
t_outDynamicStr[chars - i - 1] = val ? val : ' ';
}
@@ -2708,10 +2862,16 @@ void vl_vpi_get_value(const VerilatedVpioVarBase* vop, p_vpi_value valuep) {
return;
}
} else if (valuep->format == vpiIntVal) {
valuep->value.integer = vl_vpi_get_word(vop, 32, 0);
valuep->value.integer = get_word(vop, 32, 0);
return;
} else if (valuep->format == vpiRealVal) {
valuep->value.real = *(vop->varRealDatap());
// Only cover the scalar case, since reals cannot be packed (IEEE 1800, section 7.4.1), and
// unpacked arrays are not supported for forcing in Verilator (#4735).
if (vop->varp()->isForceable() && *forceEnableSignalVop->varCDatap())
valuep->value.real = *forceValueSignalVop->varRealDatap();
else
valuep->value.real = *vop->varRealDatap();
return;
} else if (valuep->format == vpiSuppressVal) {
return;
@@ -2754,55 +2914,157 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
return nullptr;
}
const PLI_INT32 delay_mode = flags & 0xfff;
if (const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object)) {
VL_DEBUG_IF_PLI(
VL_DBG_MSGF("- vpi: vpi_put_value name=%s fmt=%d vali=%d\n", vop->fullname(),
valuep->format, valuep->value.integer);
VL_DBG_MSGF("- vpi: varp=%p putatp=%p\n", vop->varp()->datap(), vop->varDatap()););
const PLI_INT32 forceFlag = flags & 0xfff;
if (const VerilatedVpioVar* const baseSignalVop = VerilatedVpioVar::castp(object)) {
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_put_value name=%s fmt=%d vali=%d\n",
baseSignalVop->fullname(), valuep->format,
valuep->value.integer);
VL_DBG_MSGF("- vpi: varp=%p putatp=%p\n",
baseSignalVop->varp()->datap(), baseSignalVop->varDatap()););
if (VL_UNLIKELY(!vop->varp()->isPublicRW())) {
if (VL_UNLIKELY(!baseSignalVop->varp()->isPublicRW())) {
VL_VPI_ERROR_(__FILE__, __LINE__,
"vpi_put_value was used on signal marked read-only,"
" use public_flat_rw instead for %s : %s",
vop->fullname(), vop->scopep()->defname());
" use public_flat_rw instead for '%s'",
baseSignalVop->fullname());
return nullptr;
}
if (!vl_check_format(vop->varp(), valuep, vop->fullname(), false)) return nullptr;
// NOLINTNEXTLINE(readability-simplify-boolean-expr);
if (VL_UNLIKELY((forceFlag == vpiForceFlag || forceFlag == vpiReleaseFlag)
&& !baseSignalVop->varp()->isForceable())) {
VL_VPI_ERROR_("", 0, "vpi_put_value used with %s on non-forceable signal '%s'",
forceFlag == vpiForceFlag ? "vpiForceFlag" : "vpiReleaseFlag",
baseSignalVop->fullname());
return nullptr;
}
if (!vl_check_format(baseSignalVop->varp(), valuep, baseSignalVop->fullname(), false))
return nullptr;
if (delay_mode == vpiInertialDelay) {
if (!VerilatedVpiPutHolder::canInertialDelay(valuep)) {
VL_VPI_WARNING_(
__FILE__, __LINE__,
"%s: Unsupported p_vpi_value as requested for '%s' with vpiInertialDelay",
__func__, vop->fullname());
__func__, baseSignalVop->fullname());
return nullptr;
}
VerilatedVpiImp::inertialDelay(vop, valuep);
VerilatedVpiImp::inertialDelay(baseSignalVop, valuep);
return object;
}
VerilatedVpiImp::evalNeeded(true);
const int varBits = vop->bitSize();
const int varBits = baseSignalVop->bitSize();
const auto forceControlSignals
= baseSignalVop->varp()->isForceable()
? VerilatedVpiImp::getForceControlSignals(baseSignalVop)
: std::pair<vpiHandle, vpiHandle>{nullptr, nullptr};
const vpiHandle& forceEnableSignalp = forceControlSignals.first;
const vpiHandle& forceValueSignalp = forceControlSignals.second;
const VerilatedVpioVar* const forceEnableSignalVop
= baseSignalVop->varp()->isForceable() ? VerilatedVpioVar::castp(forceEnableSignalp)
: nullptr;
const VerilatedVpioVar* const forceValueSignalVop
= baseSignalVop->varp()->isForceable() ? VerilatedVpioVar::castp(forceValueSignalp)
: nullptr;
t_vpi_error_info getForceControlSignalsError{};
const bool errorOccurred = vpi_chk_error(&getForceControlSignalsError);
// LCOV_EXCL_START - Cannot test, since getForceControlSignals does not (currently) produce
// any notices or warnings.
if (errorOccurred && getForceControlSignalsError.level < vpiError) {
vpi_printf(getForceControlSignalsError.message);
VL_VPI_ERROR_RESET_();
} // LCOV_EXCL_STOP
// NOLINTNEXTLINE(readability-simplify-boolean-expr);
if (VL_UNLIKELY(baseSignalVop->varp()->isForceable()
&& (!forceEnableSignalp || !forceEnableSignalVop || !forceValueSignalp
|| !forceValueSignalVop))) {
// Check if getForceControlSignals provided any additional error info
t_vpi_error_info getForceControlSignalsError{};
const bool gotErrorMessage = vpi_chk_error(&getForceControlSignalsError);
const std::string previousErrorMessage
= gotErrorMessage
? std::string{" Error message: "} + getForceControlSignalsError.message
: "";
VL_VPI_ERROR_(__FILE__, __LINE__,
"%s: Signal '%s' with vpiHandle '%p' is marked forceable, but force "
"control signals could not be retrieved.%s",
__func__, baseSignalVop->fullname(), object,
gotErrorMessage ? previousErrorMessage.c_str() : "");
return nullptr;
}
const VerilatedVpioVar* const valueVop = (forceFlag == vpiForceFlag)
? VerilatedVpioVar::castp(forceValueSignalp)
: baseSignalVop;
if (forceFlag == vpiForceFlag) {
// Enable __VforceEn
VerilatedVpiImp::setAllBitsToValue(forceEnableSignalVop, 1);
}
if (forceFlag == vpiReleaseFlag) {
// If signal is continuously assigned, first clear the force enable bits, then get the
// (non-forced) value. Else, get the (still forced) value first, then clear the force
// enable bits.
if (valueVop->varp()->isContinuously())
VerilatedVpiImp::setAllBitsToValue(forceEnableSignalVop, 0);
vl_vpi_get_value(baseSignalVop, valuep);
t_vpi_error_info baseValueGetError{};
const bool errorOccurred = vpi_chk_error(&baseValueGetError);
// LCOV_EXCL_START - Cannot test, because missing signal would already trigger error
// earlier, at the getForceControlSignals stage
// NOLINTNEXTLINE(readability-simplify-boolean-expr);
if (VL_UNLIKELY(errorOccurred && baseValueGetError.level >= vpiError)) {
const std::string baseValueSignalName = baseSignalVop->fullname();
const std::string previousErrorMessage = baseValueGetError.message;
VL_VPI_ERROR_(__FILE__, __LINE__,
"%s: Could not retrieve value of signal '%s' with "
"vpiHandle '%p'. Error message: %s",
__func__, baseValueSignalName.c_str(), object,
previousErrorMessage.c_str());
return nullptr;
}
// NOLINTNEXTLINE(readability-simplify-boolean-expr);
if (VL_UNCOVERABLE(errorOccurred && baseValueGetError.level < vpiError)) {
vpi_printf(baseValueGetError.message);
VL_VPI_ERROR_RESET_();
} // LCOV_EXCL_STOP
if (!valueVop->varp()->isContinuously())
VerilatedVpiImp::setAllBitsToValue(forceEnableSignalVop, 0);
// TODO: According to the SystemVerilog specification,
// vpi_put_value should return a handle to the scheduled event
// if the vpiReturnEvent flag is selected, NULL otherwise.
return object;
}
if (valuep->format == vpiVectorVal) {
if (VL_UNLIKELY(!valuep->value.vector)) return nullptr;
if (vop->varp()->vltype() == VLVT_WDATA) {
if (valueVop->varp()->vltype() == VLVT_WDATA) {
const int words = VL_WORDS_I(varBits);
for (int i = 0; i < words; ++i)
vl_vpi_put_word(vop, valuep->value.vector[i].aval, 32, i * 32);
vl_vpi_put_word(valueVop, valuep->value.vector[i].aval, 32, i * 32);
return object;
} else if (vop->varp()->vltype() == VLVT_UINT64 && varBits > 32) {
} else if (valueVop->varp()->vltype() == VLVT_UINT64 && varBits > 32) {
const QData val = (static_cast<QData>(valuep->value.vector[1].aval) << 32)
| static_cast<QData>(valuep->value.vector[0].aval);
vl_vpi_put_word(vop, val, 64, 0);
vl_vpi_put_word(valueVop, val, 64, 0);
return object;
} else {
vl_vpi_put_word(vop, valuep->value.vector[0].aval, 32, 0);
vl_vpi_put_word(valueVop, valuep->value.vector[0].aval, 32, 0);
return object;
}
} else if (valuep->format == vpiBinStrVal) {
const int len = std::strlen(valuep->value.str);
CData* const datap = reinterpret_cast<CData*>(vop->varDatap());
CData* const datap = reinterpret_cast<CData*>(valueVop->varDatap());
for (int i = 0; i < varBits; ++i) {
const bool set = (i < len) && (valuep->value.str[len - i - 1] == '1');
const size_t pos = vop->bitOffset() + i;
const size_t pos = valueVop->bitOffset() + i;
if (set)
datap[pos >> 3] |= 1 << (pos & 7);
@@ -2819,10 +3081,10 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
"%s: Non octal character '%c' in '%s' as value %s for %s",
__func__, digit + '0', valuep->value.str,
VerilatedVpiError::strFromVpiVal(valuep->format),
vop->fullname());
valueVop->fullname());
digit = 0;
}
vl_vpi_put_word(vop, digit, 3, i * 3);
vl_vpi_put_word(valueVop, digit, 3, i * 3);
}
return object;
} else if (valuep->format == vpiDecStrVal) {
@@ -2833,16 +3095,17 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
if (success < 1) {
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Parsing failed for '%s' as value %s for %s",
__func__, valuep->value.str,
VerilatedVpiError::strFromVpiVal(valuep->format), vop->fullname());
VerilatedVpiError::strFromVpiVal(valuep->format),
valueVop->fullname());
return nullptr;
}
if (success > 1) {
VL_VPI_WARNING_(__FILE__, __LINE__,
"%s: Trailing garbage '%s' in '%s' as value %s for %s", __func__,
remainder, valuep->value.str,
VerilatedVpiError::strFromVpiVal(valuep->format), vop->fullname());
VL_VPI_WARNING_(
__FILE__, __LINE__, "%s: Trailing garbage '%s' in '%s' as value %s for %s",
__func__, remainder, valuep->value.str,
VerilatedVpiError::strFromVpiVal(valuep->format), valueVop->fullname());
}
vl_vpi_put_word(vop, val, 64, 0);
vl_vpi_put_word(valueVop, val, 64, 0);
return object;
} else if (valuep->format == vpiHexStrVal) {
const int chars = (varBits + 3) >> 2;
@@ -2866,19 +3129,20 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
"%s: Non hex character '%c' in '%s' as value %s for %s",
__func__, digit, valuep->value.str,
VerilatedVpiError::strFromVpiVal(valuep->format),
vop->fullname());
valueVop->fullname());
hex = 0;
}
} else {
hex = 0;
}
// assign hex digit value to destination
vl_vpi_put_word(vop, hex, 4, i * 4);
vl_vpi_put_word(valueVop, hex, 4, i * 4);
}
return object;
} else if (valuep->format == vpiStringVal) {
if (vop->varp()->vltype() == VLVT_STRING) {
*(vop->varStringDatap()) = valuep->value.str;
if (valueVop->varp()->vltype() == VLVT_STRING) {
// Does not use valueVop, because strings are not forceable anyway
*(baseSignalVop->varStringDatap()) = valuep->value.str;
return object;
} else {
const int chars = VL_BYTES_I(varBits);
@@ -2886,21 +3150,22 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
for (int i = 0; i < chars; ++i) {
// prepend with 0 values before placing string the least significant bytes
const char c = (i < len) ? valuep->value.str[len - i - 1] : 0;
vl_vpi_put_word(vop, c, 8, i * 8);
vl_vpi_put_word(valueVop, c, 8, i * 8);
}
}
return object;
} else if (valuep->format == vpiIntVal) {
vl_vpi_put_word(vop, valuep->value.integer, 64, 0);
vl_vpi_put_word(valueVop, valuep->value.integer, 64, 0);
return object;
} else if (valuep->format == vpiRealVal) {
if (vop->varp()->vltype() == VLVT_REAL) {
*(vop->varRealDatap()) = valuep->value.real;
if (valueVop->varp()->vltype() == VLVT_REAL) {
*(valueVop->varRealDatap()) = valuep->value.real;
return object;
}
}
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported format (%s) as requested for %s",
__func__, VerilatedVpiError::strFromVpiVal(valuep->format), vop->fullname());
__func__, VerilatedVpiError::strFromVpiVal(valuep->format),
valueVop->fullname());
return nullptr;
} else if (const VerilatedVpioParam* const vop = VerilatedVpioParam::castp(object)) {
VL_VPI_WARNING_(__FILE__, __LINE__, "%s: Ignoring vpi_put_value to vpiParameter: %s",