Support VPI array accessors (#5612)

This commit is contained in:
Moubarak Jeje 2025-02-07 18:06:46 -06:00 committed by GitHub
parent 283f6c7433
commit ac659d525b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 2315 additions and 8 deletions

View File

@ -41,6 +41,7 @@ David Metz
David Stanford
David Turner
Dercury
Diego Roux
Don Williamson
Drew Ranck
Drew Taussig
@ -99,6 +100,7 @@ Jesse Taube
Jevin Sweval
Jiacheng Qian
Jiamin Zhu
Jitesh Nayak
Jinyan Xu
Jiuyang Liu
Joey Liu

View File

@ -2884,13 +2884,637 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
return nullptr;
}
void vpi_get_value_array(vpiHandle /*object*/, p_vpi_arrayvalue /*arrayvalue_p*/,
PLI_INT32* /*index_p*/, PLI_UINT32 /*num*/) {
VL_VPI_UNIMP_();
bool vl_check_array_format(const VerilatedVar* varp, const p_vpi_arrayvalue arrayvalue_p,
const char* fullname) {
if (arrayvalue_p->format == vpiVectorVal) {
switch (varp->vltype()) {
case VLVT_UINT8:
case VLVT_UINT16:
case VLVT_UINT32:
case VLVT_UINT64:
case VLVT_WDATA: return true;
default:;
}
} else if (arrayvalue_p->format == vpiIntVal) {
switch (varp->vltype()) {
case VLVT_UINT8:
case VLVT_UINT16:
case VLVT_UINT32: return true;
default:;
}
} else if ((arrayvalue_p->format == vpiRawTwoStateVal)
|| (arrayvalue_p->format == vpiRawFourStateVal)) {
switch (varp->vltype()) {
case VLVT_UINT8:
case VLVT_UINT16:
case VLVT_UINT32:
case VLVT_UINT64:
case VLVT_WDATA: return true;
default:;
}
} else if (arrayvalue_p->format == vpiShortIntVal) {
switch (varp->vltype()) {
case VLVT_UINT8:
case VLVT_UINT16: return true;
default:;
}
} else if (arrayvalue_p->format == vpiLongIntVal) {
switch (varp->vltype()) {
case VLVT_UINT8:
case VLVT_UINT16:
case VLVT_UINT32:
case VLVT_UINT64: return true;
default:;
}
}
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported format (%s) as requested for %s", __func__,
VerilatedVpiError::strFromVpiVal(arrayvalue_p->format), fullname);
return false;
}
void vpi_put_value_array(vpiHandle /*object*/, p_vpi_arrayvalue /*arrayvalue_p*/,
PLI_INT32* /*index_p*/, PLI_UINT32 /*num*/) {
VL_VPI_UNIMP_();
template <typename T, typename K>
void vl_get_value_array_integrals(unsigned index, const unsigned num, const unsigned size,
const unsigned packedSize, const bool leftIsLow, const T* src,
K* dst) {
static_assert(sizeof(K) >= sizeof(T), "size of type K is less than size of type T");
for (int i = 0; i < num; i++) {
dst[i] = src[index];
index = leftIsLow ? index == (size - 1) ? 0 : index + 1
: index == 0 ? size - 1
: index - 1;
}
}
template <typename T, typename K>
void vl_put_value_array_integrals(unsigned index, const unsigned num, const unsigned size,
const unsigned packedSize, const bool leftIsLow, const T* src,
K* dst) {
static_assert(std::is_integral<T>::value, "type T is not an integral type");
static_assert(std::is_unsigned<T>::value, "type T is not unsigned");
static_assert(sizeof(T) >= sizeof(K), "size of type T is less than size of type K");
const unsigned element_size_bytes = VL_BYTES_I(packedSize);
const T mask = element_size_bytes == sizeof(T)
? static_cast<T>(-1)
: ~(static_cast<T>(-1) << (element_size_bytes * 8));
for (unsigned i = 0; i < num; i++) {
dst[index] = src[i] & static_cast<T>(mask);
index = leftIsLow ? index == (size - 1) ? 0 : index + 1
: index == 0 ? size - 1
: index - 1;
}
}
template <typename T>
void vl_get_value_array_vectors(unsigned index, const unsigned num, const unsigned size,
const unsigned packedSize, const bool leftIsLow, const T* src,
p_vpi_vecval dst) {
static_assert(std::is_unsigned<T>::value,
"type T is not unsigned"); // ensure logical right shift
const unsigned element_size_bytes = VL_BYTES_I(packedSize);
const unsigned element_size_words = VL_WORDS_I(packedSize);
const unsigned element_size_repr = (element_size_bytes + sizeof(T) - 1) / sizeof(T);
if (sizeof(T) == sizeof(QData)) {
for (unsigned i = 0; i < num; i++) {
dst[i * 2].aval = static_cast<QData>(src[index]);
dst[i * 2].bval = 0;
dst[(i * 2) + 1].aval = static_cast<QData>(src[index]) >> 32;
dst[(i * 2) + 1].bval = 0;
index = leftIsLow ? index == (size - 1) ? 0 : index + 1
: index == 0 ? size - 1
: index - 1;
}
} else {
for (unsigned i = 0; i < num; i++) {
const size_t dst_index = i * element_size_words;
const size_t src_index = index * element_size_words;
for (unsigned j = 0; j < element_size_words; j++) {
dst[dst_index + j].aval = src[src_index + j];
dst[dst_index + j].bval = 0;
}
index = leftIsLow ? index == (size - 1) ? 0 : index + 1
: index == 0 ? size - 1
: index - 1;
}
}
}
template <typename T>
void vl_put_value_array_vectors(unsigned index, const unsigned num, const unsigned size,
const unsigned packedSize, const bool leftIsLow,
const bool fourState, const p_vpi_vecval src, T* dst) {
static_assert(std::is_unsigned<T>::value, "type T is not unsigned");
static_assert(std::is_integral<T>::value, "type T is not an integral type");
const unsigned element_size_bytes VL_BYTES_I(packedSize);
const unsigned element_size_words VL_WORDS_I(packedSize);
if (sizeof(T) == sizeof(QData)) { //destination is QDATA
const QData mask = element_size_bytes == sizeof(T)
? static_cast<QData>(-1)
: ~(static_cast<QData>(-1) << (element_size_bytes * 8));
for (unsigned i = 0; i < num; i++) {
dst[index] = src[i * 2].aval;
dst[index]
|= (static_cast<QData>(src[(i * 2) + 1].aval) << (sizeof(PLI_UINT32) * 8)) & mask;
index = leftIsLow ? index == (size - 1) ? 0 : index + 1
: index == 0 ? size - 1
: index - 1;
}
} else {
for (unsigned i = 0; i < num; i++) {
unsigned bytes_stored = 0;
for (unsigned j = 0; j < element_size_words; j++) {
if (bytes_stored >= element_size_bytes) break;
const T mask
= (element_size_bytes - bytes_stored) >= sizeof(PLI_UINT32)
? static_cast<T>(-1)
: ~(static_cast<T>(-1) << ((element_size_bytes - bytes_stored) * 8));
dst[(index * element_size_words) + j]
= static_cast<T>(src[(i * element_size_words) + j].aval) & mask;
bytes_stored += sizeof(PLI_UINT32);
}
index = leftIsLow ? index == (size - 1) ? 0 : index + 1
: index == 0 ? size - 1
: index - 1;
}
}
}
template <typename T>
void vl_get_value_array_rawvals(unsigned index, unsigned num, const unsigned size,
const unsigned packedSize, const bool leftIsLow,
const bool fourState, const T* src, PLI_BYTE8* dst) {
static_assert(std::is_unsigned<T>::value,
"type T is not unsigned"); //ensure loigcal right shift
const unsigned element_size_bytes VL_BYTES_I(packedSize);
const unsigned element_size_repr = (element_size_bytes + sizeof(T) - 1) / sizeof(T);
size_t dst_index = 0;
while (num-- > 0) {
const size_t src_offset = index * element_size_repr;
unsigned bytes_copied = 0;
for (unsigned j = 0; j < element_size_repr; j++) {
const T& src_data = src[src_offset + j];
for (unsigned k = 0; k < sizeof(T); k++) {
if (bytes_copied++ == element_size_bytes) break;
dst[dst_index++] = src_data >> (k * 8);
}
}
if (fourState) {
std::fill(dst + dst_index, dst + dst_index + element_size_bytes, 0);
dst_index += element_size_bytes;
}
index = leftIsLow ? index == (size - 1) ? 0 : index + 1
: index == 0 ? size - 1
: index - 1;
}
}
template <typename T>
void vl_put_value_array_rawvals(unsigned index, const unsigned num, const unsigned size,
const unsigned packedSize, const bool leftIsLow,
const bool fourState, const PLI_UBYTE8* src, T* dst) {
const unsigned element_size_bytes VL_BYTES_I(packedSize);
const unsigned element_size_repr = (element_size_bytes + sizeof(T) - 1) / sizeof(T);
for (unsigned i = 0; i < num; i++) {
unsigned bytes_copied = 0;
const size_t dst_offset = index * element_size_repr;
const size_t src_offset = i * element_size_bytes;
for (unsigned j = 0; j < element_size_repr; j++) {
T& dst_data = dst[dst_offset + j];
for (unsigned k = 0; k < sizeof(T); k++) {
if (bytes_copied == element_size_bytes) break;
const unsigned src_index
= fourState ? (src_offset * 2) + bytes_copied : (src_offset) + bytes_copied;
dst_data &= ~((static_cast<T>(0xFF) & 0xFF) << (k * 8));
dst_data |= ((static_cast<T>(src[src_index]) & 0xFF) << (k * 8));
bytes_copied++;
}
}
index = leftIsLow ? index == (size - 1) ? 0 : index + 1
: index == 0 ? size - 1
: index - 1;
}
}
void vl_get_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, PLI_INT32* index_p,
PLI_UINT32 num) {
const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
if (!vl_check_array_format(vop->varp(), arrayvalue_p, vop->fullname())) return;
const VerilatedVar* const varp = vop->varp();
static thread_local EData out_data[VL_VALUE_STRING_MAX_WORDS * 2];
const unsigned size = vop->size();
if (VL_UNCOVERABLE(num > size)) {
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: requested elements (%u) exceed array size (%u)",
__func__, num, size);
return;
}
const bool leftIsLow = vop->rangep()->left() == vop->rangep()->low();
int index
= leftIsLow ? index_p[0] - vop->rangep()->left() : vop->rangep()->left() - index_p[0];
if (arrayvalue_p->format == vpiShortIntVal) {
if (VL_UNCOVERABLE((sizeof(PLI_INT16) * num) >= VL_VALUE_STRING_MAX_CHARS)) {
VL_FATAL_MT(__FILE__, __LINE__, "",
"vpi_get_value_array with more than VL_VALUE_STRING_MAX_WORDS; "
"increase and recompile");
}
PLI_INT16* shortintsp = (PLI_INT16*)out_data;
arrayvalue_p->value.shortints = shortintsp;
if (varp->vltype() == VLVT_UINT8) {
const CData* ptr = reinterpret_cast<CData*>(vop->varDatap());
vl_get_value_array_integrals(index, num, size, varp->entBits(), leftIsLow,
vop->varCDatap(), shortintsp);
} else if (varp->vltype() == VLVT_UINT16) {
vl_get_value_array_integrals(index, num, size, varp->entBits(), leftIsLow,
vop->varSDatap(), shortintsp);
}
return;
} else if (arrayvalue_p->format == vpiIntVal) {
if (VL_UNCOVERABLE(num >= VL_VALUE_STRING_MAX_WORDS)) {
VL_FATAL_MT(__FILE__, __LINE__, "",
"vpi_get_value_array with more than VL_VALUE_STRING_MAX_WORDS; "
"increase and recompile");
}
PLI_INT32* integersp = (PLI_INT32*)out_data;
arrayvalue_p->value.integers = integersp;
if (varp->vltype() == VLVT_UINT8) {
vl_get_value_array_integrals(index, num, size, varp->entBits(), leftIsLow,
vop->varCDatap(), integersp);
} else if (varp->vltype() == VLVT_UINT16) {
vl_get_value_array_integrals(index, num, size, varp->entBits(), leftIsLow,
vop->varSDatap(), integersp);
} else if (varp->vltype() == VLVT_UINT32) {
vl_get_value_array_integrals(index, num, size, varp->entBits(), leftIsLow,
vop->varIDatap(), integersp);
}
return;
} else if (arrayvalue_p->format == vpiLongIntVal) {
if (VL_UNCOVERABLE((sizeof(PLI_INT64) * num) >= VL_VALUE_STRING_MAX_CHARS)) {
VL_FATAL_MT(__FILE__, __LINE__, "",
"vpi_get_value_array with more than VL_VALUE_STRING_MAX_WORDS; "
"increase and recompile");
}
PLI_INT64* longintsp = (PLI_INT64*)out_data;
arrayvalue_p->value.longints = longintsp;
if (varp->vltype() == VLVT_UINT8) {
vl_get_value_array_integrals(index, num, size, varp->entBits(), leftIsLow,
vop->varCDatap(), longintsp);
} else if (varp->vltype() == VLVT_UINT16) {
vl_get_value_array_integrals(index, num, size, varp->entBits(), leftIsLow,
vop->varSDatap(), longintsp);
} else if (varp->vltype() == VLVT_UINT32) {
vl_get_value_array_integrals(index, num, size, varp->entBits(), leftIsLow,
vop->varIDatap(), longintsp);
} else if (varp->vltype() == VLVT_UINT64) {
vl_get_value_array_integrals(index, num, size, varp->entBits(), leftIsLow,
vop->varQDatap(), longintsp);
}
return;
} else if (arrayvalue_p->format == vpiVectorVal) {
if (VL_UNCOVERABLE((VL_WORDS_I(varp->entBits()) * 2 * num) >= VL_VALUE_STRING_MAX_WORDS)) {
VL_FATAL_MT(__FILE__, __LINE__, "",
"vpi_get_value_array with more than VL_VALUE_STRING_MAX_WORDS; "
"increase and recompile");
}
p_vpi_vecval vectorsp = (p_vpi_vecval)out_data;
arrayvalue_p->value.vectors = vectorsp;
if (varp->vltype() == VLVT_UINT8) {
vl_get_value_array_vectors(index, num, size, varp->entBits(), leftIsLow,
vop->varCDatap(), vectorsp);
} else if (varp->vltype() == VLVT_UINT16) {
vl_get_value_array_vectors(index, num, size, varp->entBits(), leftIsLow,
vop->varSDatap(), vectorsp);
} else if (varp->vltype() == VLVT_UINT32) {
vl_get_value_array_vectors(index, num, size, varp->entBits(), leftIsLow,
vop->varIDatap(), vectorsp);
} else if (varp->vltype() == VLVT_UINT64) {
vl_get_value_array_vectors(index, num, size, varp->entBits(), leftIsLow,
vop->varQDatap(), vectorsp);
} else if (varp->vltype() == VLVT_WDATA) {
vl_get_value_array_vectors(index, num, size, varp->entBits(), leftIsLow,
vop->varEDatap(), vectorsp);
}
return;
} else if (arrayvalue_p->format == vpiRawFourStateVal) {
if (VL_UNCOVERABLE((VL_BYTES_I(varp->entBits()) * 2 * num) >= VL_VALUE_STRING_MAX_CHARS)) {
VL_FATAL_MT(__FILE__, __LINE__, "",
"vpi_get_value_array with more than VL_VALUE_STRING_MAX_WORDS; "
"increase and recompile");
}
PLI_BYTE8* valuep = (PLI_BYTE8*)out_data;
arrayvalue_p->value.rawvals = valuep;
if (varp->vltype() == VLVT_UINT8) {
vl_get_value_array_rawvals(index, num, size, varp->entBits(), leftIsLow, true,
vop->varCDatap(), valuep);
} else if (varp->vltype() == VLVT_UINT16) {
vl_get_value_array_rawvals(index, num, size, varp->entBits(), leftIsLow, true,
vop->varSDatap(), valuep);
} else if (varp->vltype() == VLVT_UINT32) {
vl_get_value_array_rawvals(index, num, size, varp->entBits(), leftIsLow, true,
vop->varIDatap(), valuep);
} else if (varp->vltype() == VLVT_UINT64) {
vl_get_value_array_rawvals(index, num, size, varp->entBits(), leftIsLow, true,
vop->varQDatap(), valuep);
} else if (varp->vltype() == VLVT_WDATA) {
vl_get_value_array_rawvals(index, num, size, varp->entBits(), leftIsLow, true,
vop->varEDatap(), valuep);
}
return;
} else if (arrayvalue_p->format == vpiRawTwoStateVal) {
if (VL_UNCOVERABLE((VL_BYTES_I(varp->entBits()) * num) >= VL_VALUE_STRING_MAX_CHARS)) {
VL_FATAL_MT(__FILE__, __LINE__, "",
"vpi_get_value_array with more than VL_VALUE_STRING_MAX_WORDS; "
"increase and recompile");
}
PLI_BYTE8* valuep = (PLI_BYTE8*)out_data;
arrayvalue_p->value.rawvals = valuep;
if (varp->vltype() == VLVT_UINT8) {
vl_get_value_array_rawvals(index, num, size, varp->entBits(), leftIsLow, false,
vop->varCDatap(), valuep);
} else if (varp->vltype() == VLVT_UINT16) {
vl_get_value_array_rawvals(index, num, size, varp->entBits(), leftIsLow, false,
vop->varSDatap(), valuep);
} else if (varp->vltype() == VLVT_UINT32) {
vl_get_value_array_rawvals(index, num, size, varp->entBits(), leftIsLow, false,
vop->varIDatap(), valuep);
} else if (varp->vltype() == VLVT_UINT64) {
vl_get_value_array_rawvals(index, num, size, varp->entBits(), leftIsLow, false,
vop->varQDatap(), valuep);
} else if (varp->vltype() == VLVT_WDATA) {
vl_get_value_array_rawvals(index, num, size, varp->entBits(), leftIsLow, false,
vop->varEDatap(), valuep);
}
return;
}
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported format (%s) as requested for %s", __func__,
VerilatedVpiError::strFromVpiVal(arrayvalue_p->format), vop->fullname());
}
void vpi_get_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, PLI_INT32* index_p,
PLI_UINT32 num) {
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_get_value_array %p\n", object););
VerilatedVpiImp::assertOneCheck();
VL_VPI_ERROR_RESET_();
if (VL_UNLIKELY(!object)) return;
if (VL_UNLIKELY(!arrayvalue_p)) {
VL_VPI_WARNING_(__FILE__, __LINE__,
"Ignoring vpi_get_value_array with null value pointer");
return;
}
if (VL_UNLIKELY(!index_p)) {
VL_VPI_WARNING_(__FILE__, __LINE__,
"Ignoring vpi_get_value_array with null index pointer");
return;
}
const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) {
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported vpiHandle (%p)", __func__, object);
return;
}
if (vop->type() != vpiRegArray) {
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported type (%p, %s)", __func__, object,
VerilatedVpiError::strFromVpiObjType(vop->type()));
return;
}
const VerilatedVar* const varp = vop->varp();
int lowRange = vop->rangep()->low();
int highRange = vop->rangep()->high();
if ((index_p[0] > highRange) || (index_p[0] < lowRange)) {
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: index %u for object %s is out of bounds [%u,%u]",
__func__, index_p[0], vop->fullname(), lowRange, highRange);
return;
}
if (arrayvalue_p->flags & vpiUserAllocFlag) {
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported vpiUserAllocFlag (%x)", __func__,
arrayvalue_p->flags);
return;
}
vl_get_value_array(object, arrayvalue_p, index_p, num);
}
void vl_put_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, PLI_INT32* index_p,
PLI_UINT32 num) {
const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
if (!vl_check_array_format(vop->varp(), arrayvalue_p, vop->fullname())) return;
const VerilatedVar* const varp = vop->varp();
int size = vop->size();
if (VL_UNCOVERABLE(num > size)) {
VL_VPI_ERROR_(__FILE__, __LINE__,
"%s: requested elements to set (%u) exceed array size (%u)", __func__, num,
size);
return;
}
const bool leftIsLow = vop->rangep()->left() == vop->rangep()->low();
int index
= leftIsLow ? index_p[0] - vop->rangep()->left() : vop->rangep()->left() - index_p[0];
if (arrayvalue_p->format == vpiShortIntVal) {
const PLI_UINT16* shortintsp
= reinterpret_cast<PLI_UINT16*>(arrayvalue_p->value.shortints);
if (varp->vltype() == VLVT_UINT8) {
vl_put_value_array_integrals(index, num, size, varp->entBits(), leftIsLow, shortintsp,
vop->varCDatap());
} else if (varp->vltype() == VLVT_UINT16) {
vl_put_value_array_integrals(index, num, size, varp->entBits(), leftIsLow, shortintsp,
vop->varSDatap());
}
return;
} else if (arrayvalue_p->format == vpiIntVal) {
const PLI_UINT32* integersp = reinterpret_cast<PLI_UINT32*>(arrayvalue_p->value.integers);
if (varp->vltype() == VLVT_UINT8) {
vl_put_value_array_integrals(index, num, size, varp->entBits(), leftIsLow, integersp,
vop->varCDatap());
} else if (varp->vltype() == VLVT_UINT16) {
vl_put_value_array_integrals(index, num, size, varp->entBits(), leftIsLow, integersp,
vop->varSDatap());
} else if (varp->vltype() == VLVT_UINT32) {
vl_put_value_array_integrals(index, num, size, varp->entBits(), leftIsLow, integersp,
vop->varIDatap());
}
return;
} else if (arrayvalue_p->format == vpiLongIntVal) {
const PLI_UINT64* longintsp = reinterpret_cast<PLI_UINT64*>(arrayvalue_p->value.longints);
if (varp->vltype() == VLVT_UINT8) {
vl_put_value_array_integrals(index, num, size, varp->entBits(), leftIsLow, longintsp,
vop->varCDatap());
} else if (varp->vltype() == VLVT_UINT16) {
vl_put_value_array_integrals(index, num, size, varp->entBits(), leftIsLow, longintsp,
vop->varSDatap());
} else if (varp->vltype() == VLVT_UINT32) {
vl_put_value_array_integrals(index, num, size, varp->entBits(), leftIsLow, longintsp,
vop->varIDatap());
} else if (varp->vltype() == VLVT_UINT64) {
vl_put_value_array_integrals(index, num, size, varp->entBits(), leftIsLow, longintsp,
vop->varQDatap());
}
return;
} else if (arrayvalue_p->format == vpiVectorVal) {
const p_vpi_vecval vectorsp = arrayvalue_p->value.vectors;
if (varp->vltype() == VLVT_UINT8) {
vl_put_value_array_vectors(index, num, size, varp->entBits(), leftIsLow, true,
vectorsp, vop->varCDatap());
} else if (varp->vltype() == VLVT_UINT16) {
vl_put_value_array_vectors(index, num, size, varp->entBits(), leftIsLow, true,
vectorsp, vop->varSDatap());
} else if (varp->vltype() == VLVT_UINT32) {
vl_put_value_array_vectors(index, num, size, varp->entBits(), leftIsLow, true,
vectorsp, vop->varIDatap());
} else if (varp->vltype() == VLVT_UINT64) {
vl_put_value_array_vectors(index, num, size, varp->entBits(), leftIsLow, true,
vectorsp, vop->varQDatap());
} else if (varp->vltype() == VLVT_WDATA) {
vl_put_value_array_vectors(index, num, size, varp->entBits(), leftIsLow, true,
vectorsp, vop->varEDatap());
}
return;
} else if (arrayvalue_p->format == vpiRawFourStateVal) {
const PLI_UBYTE8* valuep = reinterpret_cast<PLI_UBYTE8*>(arrayvalue_p->value.rawvals);
if (varp->vltype() == VLVT_UINT8) {
vl_put_value_array_rawvals(index, num, size, varp->entBits(), leftIsLow, true, valuep,
vop->varCDatap());
} else if (varp->vltype() == VLVT_UINT16) {
vl_put_value_array_rawvals(index, num, size, varp->entBits(), leftIsLow, true, valuep,
vop->varSDatap());
} else if (varp->vltype() == VLVT_UINT32) {
vl_put_value_array_rawvals(index, num, size, varp->entBits(), leftIsLow, true, valuep,
vop->varIDatap());
} else if (varp->vltype() == VLVT_UINT64) {
vl_put_value_array_rawvals(index, num, size, varp->entBits(), leftIsLow, true, valuep,
vop->varQDatap());
} else if (varp->vltype() == VLVT_WDATA) {
vl_put_value_array_rawvals(index, num, size, varp->entBits(), leftIsLow, true, valuep,
vop->varEDatap());
}
return;
} else if (arrayvalue_p->format == vpiRawTwoStateVal) {
const PLI_UBYTE8* valuep = reinterpret_cast<PLI_UBYTE8*>(arrayvalue_p->value.rawvals);
if (varp->vltype() == VLVT_UINT8) {
vl_put_value_array_rawvals(index, num, size, varp->entBits(), leftIsLow, false, valuep,
vop->varCDatap());
} else if (varp->vltype() == VLVT_UINT16) {
vl_put_value_array_rawvals(index, num, size, varp->entBits(), leftIsLow, false, valuep,
vop->varSDatap());
} else if (varp->vltype() == VLVT_UINT32) {
vl_put_value_array_rawvals(index, num, size, varp->entBits(), leftIsLow, false, valuep,
vop->varIDatap());
} else if (varp->vltype() == VLVT_UINT64) {
vl_put_value_array_rawvals(index, num, size, varp->entBits(), leftIsLow, false, valuep,
vop->varQDatap());
} else if (varp->vltype() == VLVT_WDATA) {
vl_put_value_array_rawvals(index, num, size, varp->entBits(), leftIsLow, false, valuep,
vop->varEDatap());
}
return;
}
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported format (%s) as requested for %s", __func__,
VerilatedVpiError::strFromVpiVal(arrayvalue_p->format), vop->fullname());
}
void vpi_put_value_array(vpiHandle object, p_vpi_arrayvalue arrayvalue_p, PLI_INT32* index_p,
PLI_UINT32 num) {
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_put_value_array %p\n", object););
VerilatedVpiImp::assertOneCheck();
VL_VPI_ERROR_RESET_();
if (VL_UNLIKELY(!arrayvalue_p)) {
VL_VPI_WARNING_(__FILE__, __LINE__,
"Ignoring vpi_put_value_array with null value pointer");
return;
}
if (VL_UNLIKELY(!index_p)) {
VL_VPI_WARNING_(__FILE__, __LINE__,
"Ignoring vpi_put_value_array with null index pointer");
return;
}
const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
if (VL_UNLIKELY(!vop)) {
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported vpiHandle (%p)", __func__, object);
return;
}
if (vop->type() != vpiRegArray) {
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported type (%p, %s)", __func__, object,
VerilatedVpiError::strFromVpiObjType(vop->type()));
return;
}
const VerilatedVar* const varp = vop->varp();
int lowRange = vop->rangep()->low();
int highRange = vop->rangep()->high();
if ((index_p[0] > highRange) || (index_p[0] < lowRange)) {
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: index %u for object %s is out of bounds [%u,%u]",
__func__, index_p[0], vop->fullname(), lowRange, highRange);
return;
}
if (VL_UNLIKELY(!vop->varp()->isPublicRW())) {
VL_VPI_ERROR_(__FILE__, __LINE__,
"Ignoring vpi_put_value_array to signal marked read-only,"
" use public_flat_rw instead: %s",
vop->fullname());
return;
}
if (arrayvalue_p->flags & (vpiPropagateOff | vpiOneValue)) {
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported flags (%x)", __func__,
arrayvalue_p->flags);
return;
}
vl_put_value_array(object, arrayvalue_p, index_p, num);
}
// time processing

View File

@ -474,6 +474,7 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read()
#ifndef VL_VALUE_STRING_MAX_WORDS
#define VL_VALUE_STRING_MAX_WORDS 64 ///< Max size in words of String conversion operation
#endif
#define VL_VALUE_STRING_MAX_CHARS (VL_VALUE_STRING_MAX_WORDS) * 4
//=========================================================================
// Base macros

View File

@ -11,6 +11,7 @@
#include "sv_vpi_user.h"
#include "vpi_user.h"
#include <iostream>
// Avoid C++11 in this file as not all simulators allow it

View File

@ -0,0 +1,695 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Copyright 2024 by Diego Roux. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************
#ifndef IS_VPI
#include "verilated.h"
#include "verilated_vpi.h"
#include "Vt_vpi_get_value_array.h"
#endif
// These require the above. Comment prevents clang-format moving them
#include "TestSimulator.h"
#include "TestVpi.h"
#include <vector>
//======================================================================
int test_vpiRawFourStateVal(char* name, PLI_BYTE8* test_data, int index, const unsigned low,
const unsigned num, const unsigned size, const unsigned elem_size) {
#ifdef TEST_VERBOSE
printf("%%\n%s: name=%s index=%u low=%u num=%u size=%u elem_size=%u\n\n", __func__, name,
index, low, num, size, elem_size);
#endif
// prepare index
int index_arr[1] = {index};
// get array handle
TestVpiHandle arrayhandle = vpi_handle_by_name(name, NULL);
CHECK_RESULT_NZ(arrayhandle);
// test raw fourstate
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiRawFourStateVal;
arrayvalue.flags = 0;
arrayvalue.value.vectors = 0;
vpi_get_value_array(arrayhandle, &arrayvalue, index_arr, num);
CHECK_RESULT_NZ(!vpi_chk_error(0));
// compare to test data
index -= low;
for (unsigned i = 0; i < num; i++) {
const unsigned offset = (index + i) % size;
for (unsigned j = 0; j < elem_size; j++) {
#ifdef TEST_VERBOSE
printf("arr[%u] == test[%u]\n", (i * 2 * elem_size) + j, (offset * elem_size) + j);
#endif
CHECK_RESULT_HEX(arrayvalue.value.rawvals[(i * 2 * elem_size) + j],
test_data[(offset * elem_size) + j]);
}
for (unsigned j = 0; j < elem_size; j++) {
CHECK_RESULT_HEX(arrayvalue.value.rawvals[(((i * 2) + 1) * elem_size) + j], 0);
}
}
return 0;
}
int test_vpiRawTwoStateVal(char* name, PLI_BYTE8* test_data, int index, const unsigned low,
const unsigned num, const unsigned size, const unsigned elem_size) {
#ifdef TEST_VERBOSE
printf("%%\n%s: name=%s index=%u low=%u num=%u size=%u elem_size=%u\n\n", __func__, name,
index, low, num, size, elem_size);
#endif
// prepare index
int index_arr[1] = {index};
// get array handle
TestVpiHandle arrayhandle = vpi_handle_by_name(name, NULL);
CHECK_RESULT_NZ(arrayhandle);
// test raw two state
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiRawTwoStateVal;
arrayvalue.flags = 0;
arrayvalue.value.vectors = 0;
vpi_get_value_array(arrayhandle, &arrayvalue, index_arr, num);
CHECK_RESULT_NZ(!vpi_chk_error(0));
// compare to test data
index -= low;
for (unsigned i = 0; i < num; i++) {
const unsigned offset = (index + i) % size;
for (unsigned j = 0; j < elem_size; j++) {
#ifdef TEST_VERBOSE
printf("arr[%u] == test[%u]\n", (i * elem_size) + j, (offset * elem_size) + j);
#endif
CHECK_RESULT_HEX(arrayvalue.value.rawvals[(i * elem_size) + j],
test_data[(offset * elem_size) + j]);
}
}
return 0;
}
int test_vpiVectorVal(char* name, PLI_BYTE8* test_data, int index, const unsigned low,
const unsigned num, const unsigned size, const unsigned elem_size) {
#ifdef TEST_VERBOSE
printf("%%\n%s: name=%s index=%u low=%u num=%u size=%u elem_size=%u\n\n", __func__, name,
index, low, num, size, elem_size);
#endif
// prepare index
int index_arr[1] = {index};
const unsigned elem_size_words = (elem_size + 3) / sizeof(PLI_UINT32);
const unsigned vec_size = elem_size_words * size;
std::vector<s_vpi_vecval> test_data_vectors;
test_data_vectors.reserve(vec_size);
unsigned test_data_index = 0;
for (unsigned i = 0; i < size; i++) {
unsigned count = 0;
for (unsigned j = 0; j < elem_size_words; j++) {
PLI_UINT32& aval = test_data_vectors[(i * elem_size_words) + j].aval;
test_data_vectors[(i * elem_size_words) + j].bval = UINT32_MAX;
aval = 0;
for (unsigned k = 0; k < sizeof(PLI_UINT32); k++) {
if (count++ == elem_size) break;
aval |= static_cast<PLI_UINT32>(test_data[test_data_index++] & 0xFF) << (k * 8);
}
}
}
// get array handle
TestVpiHandle arrayhandle = vpi_handle_by_name(name, NULL);
CHECK_RESULT_NZ(arrayhandle);
// test vector
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiVectorVal;
arrayvalue.flags = 0;
arrayvalue.value.vectors = 0;
vpi_get_value_array(arrayhandle, &arrayvalue, index_arr, num);
CHECK_RESULT_NZ(!vpi_chk_error(0));
#ifdef TEST_VERBOSE
for (unsigned i = 0; i < vec_size; i++) {
printf("arr[%u]=%x test[%u]=%x\n", i, arrayvalue.value.vectors[i].aval, i,
test_data_vectors[i].aval);
}
#endif
// compare to test data
index -= low;
for (unsigned i = 0; i < num; i++) {
const unsigned offset = (index + i) % size;
for (unsigned j = 0; j < elem_size_words; j++) {
#ifdef TEST_VERBOSE
printf("array[%u] == test[%u]\n", (i * elem_size_words) + j,
(offset * elem_size_words) + j);
#endif
CHECK_RESULT_HEX(arrayvalue.value.vectors[(i * elem_size_words) + j].aval,
test_data_vectors[(offset * elem_size_words) + j].aval);
CHECK_RESULT_HEX(arrayvalue.value.vectors[(i * elem_size_words) + j].bval, 0);
}
}
return 0;
}
int test_vpiIntVal(char* name, PLI_BYTE8* test_data, int index, const unsigned low,
const unsigned num, const unsigned size, const unsigned elem_size) {
#ifdef TEST_VERBOSE
printf("%%\n%s: name=%s index=%u low=%u num=%u size=%u elem_size=%u\n\n", __func__, name,
index, low, num, size, elem_size);
#endif
// prepare index
int index_arr[1] = {index};
std::vector<PLI_INT32> test_data_integers;
test_data_integers.reserve(size);
for (unsigned i = 0; i < size; i++) {
PLI_INT32& integer = test_data_integers[i];
integer = 0;
for (unsigned j = 0; j < elem_size; j++) {
integer |= (static_cast<PLI_INT32>(test_data[(i * elem_size) + j]) & 0xFF) << (j * 8);
}
}
// get array handle
TestVpiHandle arrayhandle = vpi_handle_by_name(name, NULL);
CHECK_RESULT_NZ(arrayhandle);
// test raw fourstate
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiIntVal;
arrayvalue.flags = 0;
arrayvalue.value.integers = 0;
vpi_get_value_array(arrayhandle, &arrayvalue, index_arr, num);
CHECK_RESULT_NZ(!vpi_chk_error(0));
#ifdef TEST_VERBOSE
for (unsigned i = 0; i < size; i++) {
printf("arr[%u]=%x test[%u]=%x\n", i, arrayvalue.value.integers[i], i,
test_data_integers[i]);
}
#endif
// compare to test data
index -= low;
for (unsigned i = 0; i < num; i++) {
const unsigned offset = (index + i) % size;
#ifdef TEST_VERBOSE
printf("array[%u] == test[%u]\n", i, offset);
#endif
CHECK_RESULT_HEX(arrayvalue.value.integers[i], test_data_integers[offset]);
}
return 0;
}
int test_vpiShortIntVal(char* name, PLI_BYTE8* test_data, int index, const unsigned low,
const unsigned num, const unsigned size, const unsigned elem_size) {
#ifdef TEST_VERBOSE
printf("%%\n%s: name=%s index=%u low=%u num=%u size=%u elem_size=%u\n\n", __func__, name,
index, low, num, size, elem_size);
#endif
// prepare index
int index_arr[1] = {index};
std::vector<PLI_INT16> test_data_shortints;
test_data_shortints.reserve(size);
for (unsigned i = 0; i < size; i++) {
if (elem_size == 2) {
test_data_shortints[i] = test_data[i * 2] & 0xFF;
test_data_shortints[i] |= test_data[(i * 2) + 1] << 8;
} else {
test_data_shortints[i] = test_data[i] & 0xFF;
}
}
// get array handle
TestVpiHandle arrayhandle = vpi_handle_by_name(name, NULL);
CHECK_RESULT_NZ(arrayhandle);
// test raw fourstate
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiShortIntVal;
arrayvalue.flags = 0;
arrayvalue.value.shortints = 0;
vpi_get_value_array(arrayhandle, &arrayvalue, index_arr, num);
CHECK_RESULT_NZ(!vpi_chk_error(0));
#ifdef TEST_VERBOSE
for (unsigned i = 0; i < size; i++) {
printf("arr[%u]=%x test[%u]=%x\n", i, arrayvalue.value.shortints[i], i,
test_data_shortints[i]);
}
#endif
// compare to test data
index -= low;
for (unsigned i = 0; i < num; i++) {
const unsigned offset = (index + i) % size;
#ifdef TEST_VERBOSE
printf("array[%u] == test[%u]\n", i, offset);
#endif
CHECK_RESULT_HEX(arrayvalue.value.shortints[i], test_data_shortints[offset]);
}
return 0;
}
int test_vpiLongIntVal(char* name, PLI_BYTE8* test_data, int index, const unsigned low,
const unsigned num, const unsigned size, const unsigned elem_size) {
#ifdef TEST_VERBOSE
printf("%%\n%s: name=%s index=%u low=%u num=%u size=%u elem_size=%u\n\n", __func__, name,
index, low, num, size, elem_size);
#endif
// prepare index
int index_arr[1] = {index};
std::vector<PLI_INT64> test_data_longints;
test_data_longints.reserve(size);
for (unsigned i = 0; i < size; i++) {
PLI_INT64& longint = test_data_longints[i];
longint = 0;
for (unsigned j = 0; j < elem_size; j++) {
longint |= (static_cast<PLI_INT64>(test_data[(i * elem_size) + j]) & 0xFF) << (j * 8);
}
}
// get array handle
TestVpiHandle arrayhandle = vpi_handle_by_name(name, NULL);
CHECK_RESULT_NZ(arrayhandle);
// test raw fourstate
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiLongIntVal;
arrayvalue.flags = 0;
arrayvalue.value.longints = 0;
vpi_get_value_array(arrayhandle, &arrayvalue, index_arr, num);
CHECK_RESULT_NZ(!vpi_chk_error(0));
// compare to test data
index -= low;
for (unsigned i = 0; i < num; i++) {
const unsigned offset = (index + i) % size;
#ifdef TEST_VERBOSE
printf("array[%u] == test[%u]\n", i, offset);
#endif
CHECK_RESULT_HEX(arrayvalue.value.longints[i], test_data_longints[offset]);
}
return 0;
}
int mon_check_props() {
// skip test if not verilator (value_array accessors unimplemented in other sims)
if (!TestSimulator::is_verilator()) {
#ifdef VERILATOR
printf("TestSimulator indicating not verilator, but VERILATOR macro is defined\n");
return 1;
#endif
return 0;
}
const unsigned NUM_ELEMENTS = 4;
PLI_BYTE8 read_bytes[NUM_ELEMENTS]
= {static_cast<PLI_BYTE8>(0xad), static_cast<PLI_BYTE8>(0xde),
static_cast<PLI_BYTE8>(0xef), static_cast<PLI_BYTE8>(0xbe)};
PLI_BYTE8 read_shorts[NUM_ELEMENTS * 2] = {
static_cast<PLI_BYTE8>(0xad), static_cast<PLI_BYTE8>(0xde), static_cast<PLI_BYTE8>(0xef),
static_cast<PLI_BYTE8>(0xbe), static_cast<PLI_BYTE8>(0xfe), static_cast<PLI_BYTE8>(0xca),
static_cast<PLI_BYTE8>(0x0d), static_cast<PLI_BYTE8>(0xf0)};
PLI_BYTE8 read_words[NUM_ELEMENTS * 4] = {
static_cast<PLI_BYTE8>(0xef), static_cast<PLI_BYTE8>(0xbe), static_cast<PLI_BYTE8>(0xad),
static_cast<PLI_BYTE8>(0xde), static_cast<PLI_BYTE8>(0x0d), static_cast<PLI_BYTE8>(0xf0),
static_cast<PLI_BYTE8>(0xfe), static_cast<PLI_BYTE8>(0xca), static_cast<PLI_BYTE8>(0x03),
static_cast<PLI_BYTE8>(0x02), static_cast<PLI_BYTE8>(0x01), static_cast<PLI_BYTE8>(0x00),
static_cast<PLI_BYTE8>(0x07), static_cast<PLI_BYTE8>(0x06), static_cast<PLI_BYTE8>(0x05),
static_cast<PLI_BYTE8>(0x04)};
PLI_BYTE8 read_longs[NUM_ELEMENTS * 8] = {
static_cast<PLI_BYTE8>(0x0d), static_cast<PLI_BYTE8>(0xf0), static_cast<PLI_BYTE8>(0xfe),
static_cast<PLI_BYTE8>(0xca), static_cast<PLI_BYTE8>(0xef), static_cast<PLI_BYTE8>(0xbe),
static_cast<PLI_BYTE8>(0xad), static_cast<PLI_BYTE8>(0xde), static_cast<PLI_BYTE8>(0x07),
static_cast<PLI_BYTE8>(0x06), static_cast<PLI_BYTE8>(0x05), static_cast<PLI_BYTE8>(0x04),
static_cast<PLI_BYTE8>(0x03), static_cast<PLI_BYTE8>(0x02), static_cast<PLI_BYTE8>(0x01),
static_cast<PLI_BYTE8>(0x00), static_cast<PLI_BYTE8>(0x0F), static_cast<PLI_BYTE8>(0x0E),
static_cast<PLI_BYTE8>(0x0D), static_cast<PLI_BYTE8>(0x0C), static_cast<PLI_BYTE8>(0x0B),
static_cast<PLI_BYTE8>(0x0A), static_cast<PLI_BYTE8>(0x09), static_cast<PLI_BYTE8>(0x08),
static_cast<PLI_BYTE8>(0x17), static_cast<PLI_BYTE8>(0x16), static_cast<PLI_BYTE8>(0x15),
static_cast<PLI_BYTE8>(0x14), static_cast<PLI_BYTE8>(0x13), static_cast<PLI_BYTE8>(0x12),
static_cast<PLI_BYTE8>(0x11), static_cast<PLI_BYTE8>(0x10)};
PLI_BYTE8 read_customs[NUM_ELEMENTS * 9] = {
static_cast<PLI_BYTE8>(0x0d), static_cast<PLI_BYTE8>(0xf0), static_cast<PLI_BYTE8>(0xfe),
static_cast<PLI_BYTE8>(0xca), static_cast<PLI_BYTE8>(0xef), static_cast<PLI_BYTE8>(0xbe),
static_cast<PLI_BYTE8>(0xad), static_cast<PLI_BYTE8>(0xde), static_cast<PLI_BYTE8>(0x1A),
static_cast<PLI_BYTE8>(0x07), static_cast<PLI_BYTE8>(0x06), static_cast<PLI_BYTE8>(0x05),
static_cast<PLI_BYTE8>(0x04), static_cast<PLI_BYTE8>(0x03), static_cast<PLI_BYTE8>(0x02),
static_cast<PLI_BYTE8>(0x01), static_cast<PLI_BYTE8>(0x00), static_cast<PLI_BYTE8>(0x15),
static_cast<PLI_BYTE8>(0x0F), static_cast<PLI_BYTE8>(0x0E), static_cast<PLI_BYTE8>(0x0D),
static_cast<PLI_BYTE8>(0x0C), static_cast<PLI_BYTE8>(0x0B), static_cast<PLI_BYTE8>(0x0A),
static_cast<PLI_BYTE8>(0x09), static_cast<PLI_BYTE8>(0x08), static_cast<PLI_BYTE8>(0x0A),
static_cast<PLI_BYTE8>(0x17), static_cast<PLI_BYTE8>(0x16), static_cast<PLI_BYTE8>(0x15),
static_cast<PLI_BYTE8>(0x14), static_cast<PLI_BYTE8>(0x13), static_cast<PLI_BYTE8>(0x12),
static_cast<PLI_BYTE8>(0x11), static_cast<PLI_BYTE8>(0x10), static_cast<PLI_BYTE8>(0x05)};
char read_bytes_name[] = "test.read_bytes";
char read_bytes_nonzero_index_name[] = "test.read_bytes_nonzero_index";
char read_bytes_rl_name[] = "test.read_bytes_rl";
char read_shorts_name[] = "test.read_shorts";
char read_words_name[] = "test.read_words";
char read_integers_name[] = "test.read_integers";
char read_longs_name[] = "test.read_longs";
char read_customs_name[] = "test.read_customs";
char read_customs_nonzero_index_rl_name[] = "test.read_customs_nonzero_index_rl";
for (unsigned i = 0; i < NUM_ELEMENTS; i++) {
for (unsigned j = 0; j < (NUM_ELEMENTS + 1); j++) {
if (test_vpiRawFourStateVal(read_bytes_name, read_bytes, i, 0, j, NUM_ELEMENTS, 1))
return 1;
if (test_vpiRawFourStateVal(read_bytes_nonzero_index_name, read_bytes, i + 1, 1, j,
NUM_ELEMENTS, 1))
return 1;
if (test_vpiRawFourStateVal(read_bytes_rl_name, read_bytes, i, 0, j, NUM_ELEMENTS, 1))
return 1;
if (test_vpiRawFourStateVal(read_shorts_name, read_shorts, i, 0, j, NUM_ELEMENTS, 2))
return 1;
if (test_vpiRawFourStateVal(read_words_name, read_words, i, 0, j, NUM_ELEMENTS, 4))
return 1;
if (test_vpiRawFourStateVal(read_integers_name, read_words, i, 0, j, NUM_ELEMENTS, 4))
return 1;
if (test_vpiRawFourStateVal(read_longs_name, read_longs, i, 0, j, NUM_ELEMENTS, 8))
return 1;
if (test_vpiRawFourStateVal(read_customs_name, read_customs, i, 0, j, NUM_ELEMENTS, 9))
return 1;
if (test_vpiRawFourStateVal(read_customs_nonzero_index_rl_name, read_customs, i + 1, 1,
j, NUM_ELEMENTS, 9))
return 1;
if (test_vpiRawTwoStateVal(read_bytes_name, read_bytes, i, 0, j, NUM_ELEMENTS, 1))
return 1;
if (test_vpiRawTwoStateVal(read_bytes_rl_name, read_bytes, i, 0, j, NUM_ELEMENTS, 1))
return 1;
if (test_vpiRawTwoStateVal(read_bytes_nonzero_index_name, read_bytes, i + 1, 1, j,
NUM_ELEMENTS, 1))
return 1;
if (test_vpiRawTwoStateVal(read_shorts_name, read_shorts, i, 0, j, NUM_ELEMENTS, 2))
return 1;
if (test_vpiRawTwoStateVal(read_words_name, read_words, i, 0, j, NUM_ELEMENTS, 4))
return 1;
if (test_vpiRawTwoStateVal(read_integers_name, read_words, i, 0, j, NUM_ELEMENTS, 4))
return 1;
if (test_vpiRawTwoStateVal(read_longs_name, read_longs, i, 0, j, NUM_ELEMENTS, 8))
return 1;
if (test_vpiRawTwoStateVal(read_customs_name, read_customs, i, 0, j, NUM_ELEMENTS, 9))
return 1;
if (test_vpiRawTwoStateVal(read_customs_nonzero_index_rl_name, read_customs, i + 1, 1,
j, NUM_ELEMENTS, 9))
return 1;
if (test_vpiVectorVal(read_bytes_name, read_bytes, i, 0, j, NUM_ELEMENTS, 1)) return 1;
if (test_vpiVectorVal(read_bytes_nonzero_index_name, read_bytes, i + 1, 1, j,
NUM_ELEMENTS, 1))
return 1;
if (test_vpiVectorVal(read_bytes_rl_name, read_bytes, i, 0, j, NUM_ELEMENTS, 1))
return 1;
if (test_vpiVectorVal(read_shorts_name, read_shorts, i, 0, j, NUM_ELEMENTS, 2))
return 1;
if (test_vpiVectorVal(read_words_name, read_words, i, 0, j, NUM_ELEMENTS, 4)) return 1;
if (test_vpiVectorVal(read_integers_name, read_words, i, 0, j, NUM_ELEMENTS, 4))
return 1;
if (test_vpiVectorVal(read_longs_name, read_longs, i, 0, j, NUM_ELEMENTS, 8)) return 1;
if (test_vpiVectorVal(read_customs_name, read_customs, i, 0, j, NUM_ELEMENTS, 9))
return 1;
if (test_vpiVectorVal(read_customs_nonzero_index_rl_name, read_customs, i + 1, 1, j,
NUM_ELEMENTS, 9))
return 1;
if (test_vpiShortIntVal(read_bytes_name, read_bytes, i, 0, j, NUM_ELEMENTS, 1))
return 1;
if (test_vpiShortIntVal(read_bytes_nonzero_index_name, read_bytes, i + 1, 1, j,
NUM_ELEMENTS, 1))
return 1;
if (test_vpiShortIntVal(read_bytes_rl_name, read_bytes, i, 0, j, NUM_ELEMENTS, 1))
return 1;
if (test_vpiShortIntVal(read_shorts_name, read_shorts, i, 0, j, NUM_ELEMENTS, 2))
return 1;
if (test_vpiIntVal(read_bytes_name, read_bytes, i, 0, j, NUM_ELEMENTS, 1)) return 1;
if (test_vpiIntVal(read_bytes_nonzero_index_name, read_bytes, i + 1, 1, j,
NUM_ELEMENTS, 1))
return 1;
if (test_vpiIntVal(read_bytes_rl_name, read_bytes, i, 0, j, NUM_ELEMENTS, 1)) return 1;
if (test_vpiIntVal(read_words_name, read_words, i, 0, j, NUM_ELEMENTS, 4)) return 1;
if (test_vpiIntVal(read_integers_name, read_words, i, 0, j, NUM_ELEMENTS, 4)) return 1;
if (test_vpiLongIntVal(read_bytes_name, read_bytes, i, 0, j, NUM_ELEMENTS, 1))
return 1;
if (test_vpiLongIntVal(read_bytes_nonzero_index_name, read_bytes, i + 1, 1, j,
NUM_ELEMENTS, 1))
return 1;
if (test_vpiLongIntVal(read_bytes_rl_name, read_bytes, i, 0, j, NUM_ELEMENTS, 1))
return 1;
if (test_vpiLongIntVal(read_shorts_name, read_shorts, i, 0, j, NUM_ELEMENTS, 2))
return 1;
if (test_vpiLongIntVal(read_words_name, read_words, i, 0, j, NUM_ELEMENTS, 4))
return 1;
if (test_vpiLongIntVal(read_integers_name, read_words, i, 0, j, NUM_ELEMENTS, 4))
return 1;
if (test_vpiLongIntVal(read_longs_name, read_longs, i, 0, j, NUM_ELEMENTS, 8))
return 1;
}
}
{
// test unsupported format
TestVpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"test.read_longs", NULL);
CHECK_RESULT_NZ(object);
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiRealVal;
arrayvalue.flags = 0;
arrayvalue.value.integers = 0;
PLI_INT32 indexp[1] = {0};
vpi_get_value_array(object, &arrayvalue, indexp, NUM_ELEMENTS);
CHECK_RESULT_NZ(vpi_chk_error(0));
}
{
// test unsupported foramt
TestVpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"test.read_words", NULL);
CHECK_RESULT_NZ(object);
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiShortRealVal;
arrayvalue.flags = 0;
arrayvalue.value.integers = 0;
PLI_INT32 indexp[1] = {0};
vpi_get_value_array(object, &arrayvalue, indexp, NUM_ELEMENTS);
CHECK_RESULT_NZ(vpi_chk_error(0));
}
{
// test unsupported format
TestVpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"test.read_longs", NULL);
CHECK_RESULT_NZ(object);
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiTimeVal;
arrayvalue.flags = 0;
arrayvalue.value.integers = 0;
PLI_INT32 indexp[1] = {0};
vpi_get_value_array(object, &arrayvalue, indexp, NUM_ELEMENTS);
CHECK_RESULT_NZ(vpi_chk_error(0));
}
{
// test unsupported TestVpiHandle
TestVpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"test", NULL);
CHECK_RESULT_NZ(object);
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiIntVal;
arrayvalue.flags = 0;
arrayvalue.value.integers = 0;
PLI_INT32 indexp[1] = {0};
vpi_get_value_array(object, &arrayvalue, indexp, NUM_ELEMENTS);
CHECK_RESULT_NZ(vpi_chk_error(0));
}
{
// test unsupported type
TestVpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"test.read_scalar", NULL);
CHECK_RESULT_NZ(object);
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiIntVal;
arrayvalue.flags = 0;
arrayvalue.value.integers = 0;
PLI_INT32 indexp[1] = {0};
vpi_get_value_array(object, &arrayvalue, indexp, NUM_ELEMENTS);
CHECK_RESULT_NZ(vpi_chk_error(0));
}
{
// test indexp out of bounds
TestVpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"test.read_bounds", NULL);
CHECK_RESULT_NZ(object);
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiIntVal;
arrayvalue.flags = 0;
arrayvalue.value.integers = 0;
PLI_INT32 indexp[1] = {4};
vpi_get_value_array(object, &arrayvalue, indexp, NUM_ELEMENTS);
CHECK_RESULT_NZ(vpi_chk_error(0));
indexp[0] = 0;
vpi_get_value_array(object, &arrayvalue, indexp, NUM_ELEMENTS);
CHECK_RESULT_NZ(vpi_chk_error(0));
}
{
// test unsupported flags
TestVpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"test.read_words", NULL);
CHECK_RESULT_NZ(object);
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiIntVal;
arrayvalue.flags = vpiUserAllocFlag;
arrayvalue.value.integers = 0;
PLI_INT32 indexp[1] = {0};
vpi_get_value_array(object, &arrayvalue, indexp, NUM_ELEMENTS);
CHECK_RESULT_NZ(vpi_chk_error(0));
}
{
// test unsupported format & vltype combination
TestVpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"test.read_words", NULL);
CHECK_RESULT_NZ(object);
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiShortIntVal;
arrayvalue.flags = 0;
arrayvalue.value.integers = 0;
PLI_INT32 indexp[1] = {0};
vpi_get_value_array(object, &arrayvalue, indexp, NUM_ELEMENTS);
CHECK_RESULT_NZ(vpi_chk_error(0));
}
{
// test num out of bounds
TestVpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"test.read_words", NULL);
CHECK_RESULT_NZ(object);
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiIntVal;
arrayvalue.flags = 0;
arrayvalue.value.integers = 0;
PLI_INT32 indexp[1] = {0};
vpi_get_value_array(object, &arrayvalue, indexp, 5);
CHECK_RESULT_NZ(vpi_chk_error(0));
}
{
// test null arrayvalue
TestVpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"test.read_words", NULL);
CHECK_RESULT_NZ(object);
PLI_INT32 indexp[1] = {0};
vpi_get_value_array(object, 0, indexp, 0);
CHECK_RESULT_NZ(vpi_chk_error(0));
}
{
// test null indexp
TestVpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"test.read_words", NULL);
CHECK_RESULT_NZ(object);
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiIntVal;
arrayvalue.flags = 0;
arrayvalue.value.integers = 0;
vpi_get_value_array(object, &arrayvalue, 0, 0);
CHECK_RESULT_NZ(vpi_chk_error(0));
}
return 0;
}
extern "C" int mon_check(void) { return mon_check_props(); }
#ifdef IS_VPI
static int mon_check_vpi() {
TestVpiHandle href = vpi_handle(vpiSysTfCall, 0);
s_vpi_value vpi_value;
vpi_value.format = vpiIntVal;
vpi_value.value.integer = mon_check();
vpi_put_value(href, &vpi_value, NULL, vpiNoDelay);
return 0;
}
static s_vpi_systf_data vpi_systf_data[] = {{vpiSysFunc, vpiIntFunc, (PLI_BYTE8*)"$mon_check",
(PLI_INT32(*)(PLI_BYTE8*))mon_check_vpi, 0, 0, 0},
0};
// cver entry
void vpi_compat_bootstrap(void) {
p_vpi_systf_data systf_data_p;
systf_data_p = &(vpi_systf_data[0]);
while (systf_data_p->type != 0) vpi_register_systf(systf_data_p++);
}
// icarus entry
void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0};
#else
int main(int argc, char** argv) {
Verilated::commandArgs(argc, argv);
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
const std::unique_ptr<VM_PREFIX> top{new VM_PREFIX{contextp.get(), ""}};
contextp->fatalOnVpiError(0);
#ifdef VERILATOR
#ifdef TEST_VERBOSE
contextp->scopesDump();
#endif
#endif
while (!contextp->gotFinish()) { top->eval(); }
return 0;
}
#endif

View File

@ -0,0 +1,23 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2024 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('simulator')
test.compile(make_top_shell=False,
make_main=False,
make_pli=True,
verilator_flags2=["--exe --vpi --no-l2name", test.pli_filename],
iv_flags2=["-g2005-sv -D USE_VPI_NOT_DPI"],
v_flags2=["+define+USE_VPI_NOT_DPI +define+VERILATOR_COMMENTS"])
test.execute(use_libvpi=True)
test.passes()

View File

@ -0,0 +1,105 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// Copyright 2024 by Diego Roux. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
`ifdef VERILATOR_COMMENTS
`define PUBLIC_FLAT_RD /*verilator public_flat_rd*/
`define PUBLIC_FLAT_RW /*verilator public_flat_rw*/
`else
`define PUBLIC_FLAT_RD
`define PUBLIC_FLAT_RW
`endif
module test ();
`ifdef VERILATOR
`systemc_header
extern "C" int mon_check();
`verilog
`endif
reg [7:0] read_bytes [0:3] `PUBLIC_FLAT_RD;
reg [7:0] read_bytes_nonzero_index [1:4] `PUBLIC_FLAT_RD;
reg [7:0] read_bytes_rl [3:0] `PUBLIC_FLAT_RD;
reg [15:0] read_shorts [0:3] `PUBLIC_FLAT_RD;
reg [31:0] read_words [0:3] `PUBLIC_FLAT_RD;
reg [31:0] read_words_rl [3:0] `PUBLIC_FLAT_RD;
reg [63:0] read_longs [0:3] `PUBLIC_FLAT_RD;
integer read_integers [0:3] `PUBLIC_FLAT_RD;
reg [68:0] read_customs [0:3] `PUBLIC_FLAT_RD;
reg [68:0] read_customs_nonzero_index_rl [4:1] `PUBLIC_FLAT_RD;
reg [7:0] read_scalar `PUBLIC_FLAT_RD;
reg [7:0] read_bounds [1:3] `PUBLIC_FLAT_RD;
integer status;
initial begin
read_bytes[0] = 8'had;
read_bytes[1] = 8'hde;
read_bytes[2] = 8'hef;
read_bytes[3] = 8'hbe;
read_bytes_rl[3] = 8'had;
read_bytes_rl[2] = 8'hde;
read_bytes_rl[1] = 8'hef;
read_bytes_rl[0] = 8'hbe;
read_bytes_nonzero_index[1] = 8'had;
read_bytes_nonzero_index[2] = 8'hde;
read_bytes_nonzero_index[3] = 8'hef;
read_bytes_nonzero_index[4] = 8'hbe;
read_shorts[0] = 16'hdead;
read_shorts[1] = 16'hbeef;
read_shorts[2] = 16'hcafe;
read_shorts[3] = 16'hf00d;
read_words[0] = 32'hdeadbeef;
read_words[1] = 32'hcafef00d;
read_words[2] = 32'h00010203;
read_words[3] = 32'h04050607;
read_integers[0] = 32'hdeadbeef;
read_integers[1] = 32'hcafef00d;
read_integers[2] = 32'h00010203;
read_integers[3] = 32'h04050607;
read_longs[0] = 64'hdeadbeefcafef00d;
read_longs[1] = 64'h0001020304050607;
read_longs[2] = 64'h08090a0b0c0d0e0f;
read_longs[3] = 64'h1011121314151617;
read_customs[0] = 69'hFAdeadbeefcafef00d; //0x001F'FFFF'FFFF'FFFF'FFFF
read_customs[1] = 69'hF50001020304050607;
read_customs[2] = 69'h0A08090a0b0c0d0e0f;
read_customs[3] = 69'h051011121314151617;
read_customs_nonzero_index_rl[4] = 69'hFAdeadbeefcafef00d; //0x001F'FFFF'FFFF'FFFF'FFFF
read_customs_nonzero_index_rl[3] = 69'hF50001020304050607;
read_customs_nonzero_index_rl[2] = 69'h0A08090a0b0c0d0e0f;
read_customs_nonzero_index_rl[1] = 69'h051011121314151617;
`ifdef IVERILOG
status = $mon_check;
`endif
`ifdef VERILATOR
status = $c32("mon_check()");
`endif
if (status != 0) begin
$write("%%Error: t_vpi_get_value_array.cpp:%0d: C Test failed\n", status);
$stop;
end
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,759 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Copyright 2024 by Diego Roux. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************
#ifndef IS_VPI
#include "verilated.h"
#include "verilated_vpi.h"
#include "Vt_vpi_put_value_array.h"
#endif
// These require the above. Comment prevents clang-format moving them
#include "TestSimulator.h"
#include "TestVpi.h"
#include <vector>
//======================================================================
int test_vpiRawFourStateVal(char* name, PLI_BYTE8* test_data, int index, const unsigned num,
const unsigned size, const unsigned elem_size) {
#ifdef TEST_VERBOSE
printf("%%\n%s: name=%s index=%u num=%u size=%u elem_size=%u\n\n", __func__, name, index, num,
size, elem_size);
#endif
// prepare index and test data arrays
int index_arr[1] = {index};
std::vector<PLI_BYTE8> test_data_four_state;
test_data_four_state.reserve(size * elem_size * 2);
for (unsigned i = 0; i < size; i++) {
for (unsigned j = 0; j < elem_size; j++) {
test_data_four_state[(i * 2 * elem_size) + j] = test_data[(i * elem_size) + j];
}
for (unsigned j = 0; j < elem_size; j++) {
test_data_four_state[(((i * 2) + 1) * elem_size) + j] = -1; // bval should be ignored
}
}
// get array handle
TestVpiHandle arrayhandle = vpi_handle_by_name(name, NULL);
CHECK_RESULT_NZ(arrayhandle);
// test raw fourstate
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiRawFourStateVal;
arrayvalue.flags = 0;
arrayvalue.value.rawvals = test_data_four_state.data();
vpi_put_value_array(arrayhandle, &arrayvalue, index_arr, num);
CHECK_RESULT_NZ(!vpi_chk_error(0));
// get value to nu
arrayvalue.value.rawvals = 0;
vpi_get_value_array(arrayhandle, &arrayvalue, index_arr, size);
CHECK_RESULT_NZ(!vpi_chk_error(0));
#ifdef TEST_VERBOSE
for (unsigned i = 0; i < (2 * size * elem_size); i++) {
printf("arr[%u]=%x test[%u]=%x\n", i, arrayvalue.value.rawvals[i] & 0xFF, i,
test_data_four_state[i] & 0xFF);
}
#endif
// compare to test data
for (unsigned i = 0; i < num; i++) {
const unsigned offset = (index + i) % size;
for (unsigned j = 0; j < elem_size; j++) {
#ifdef TEST_VERBOSE
printf("arr[%u] == test[%u]\n", (i * 2 * elem_size) + j, (i * elem_size) + j);
#endif
CHECK_RESULT_HEX(arrayvalue.value.rawvals[(i * 2 * elem_size) + j],
test_data[(i * elem_size) + j]);
}
for (unsigned j = 0; j < elem_size; j++) {
CHECK_RESULT_HEX(arrayvalue.value.rawvals[(((i * 2) + 1) * elem_size) + j], 0);
}
}
return 0;
}
int test_vpiRawTwoStateVal(char* name, PLI_BYTE8* test_data, int index, const unsigned num,
const unsigned size, const unsigned elem_size) {
#ifdef TEST_VERBOSE
printf("%%\n%s: name=%s index=%u num=%u size=%u elem_size=%u\n\n", __func__, name, index, num,
size, elem_size);
#endif
// prepare index
int index_arr[1] = {index};
// get array handle
TestVpiHandle arrayhandle = vpi_handle_by_name(name, NULL);
CHECK_RESULT_NZ(arrayhandle);
// test raw fourstate
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiRawTwoStateVal;
arrayvalue.flags = 0;
arrayvalue.value.rawvals = test_data;
vpi_put_value_array(arrayhandle, &arrayvalue, index_arr, num);
CHECK_RESULT_NZ(!vpi_chk_error(0));
// get value to check
arrayvalue.value.rawvals = 0;
vpi_get_value_array(arrayhandle, &arrayvalue, index_arr, size);
CHECK_RESULT_NZ(!vpi_chk_error(0));
#ifdef TEST_VERBOSE
for (unsigned i = 0; i < (size * elem_size); i++) {
printf("arr[%u]=%x test[%u]=%x\n", i, arrayvalue.value.rawvals[i] & 0xFF, i,
test_data[i] & 0xFF);
}
#endif
// compare to test data
for (unsigned i = 0; i < num; i++) {
const unsigned offset = (index + i) % size;
for (unsigned j = 0; j < elem_size; j++) {
#ifdef TEST_VERBOSE
printf("arr[%u] == test[%u]\n", (i * elem_size) + j, (i * elem_size) + j);
#endif
CHECK_RESULT_HEX(arrayvalue.value.rawvals[(i * elem_size) + j],
test_data[(i * elem_size) + j]);
}
}
return 0;
}
int test_vpiVectorVal(char* name, PLI_BYTE8* test_data, int index, const unsigned num,
const unsigned size, const unsigned elem_size) {
#ifdef TEST_VERBOSE
printf("%%\n%s: name=%s index=%u num=%u size=%u elem_size=%u\n\n", __func__, name, index, num,
size, elem_size);
#endif
// prepare index
int index_arr[1] = {index};
const unsigned elem_size_words = (elem_size + 3) / sizeof(PLI_UINT32);
const unsigned vec_size = elem_size_words * size;
std::vector<s_vpi_vecval> test_data_vectors;
test_data_vectors.reserve(vec_size);
unsigned test_data_index = 0;
for (unsigned i = 0; i < size; i++) {
unsigned count = 0;
for (unsigned j = 0; j < elem_size_words; j++) {
PLI_UINT32& aval = test_data_vectors[(i * elem_size_words) + j].aval;
test_data_vectors[(i * elem_size_words) + j].bval = UINT32_MAX;
aval = 0;
for (unsigned k = 0; k < sizeof(PLI_UINT32); k++) {
if (count++ == elem_size) break;
aval |= static_cast<PLI_UINT32>(test_data[test_data_index++] & 0xFF) << (k * 8);
}
}
}
// get array handle
TestVpiHandle arrayhandle = vpi_handle_by_name(name, NULL);
CHECK_RESULT_NZ(arrayhandle);
// test raw fourstate
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiVectorVal;
arrayvalue.flags = 0;
arrayvalue.value.vectors = test_data_vectors.data();
vpi_put_value_array(arrayhandle, &arrayvalue, index_arr, num);
CHECK_RESULT_NZ(!vpi_chk_error(0));
// get value to check
arrayvalue.value.vectors = 0;
vpi_get_value_array(arrayhandle, &arrayvalue, index_arr, size);
CHECK_RESULT_NZ(!vpi_chk_error(0));
#ifdef TEST_VERBOSE
for (unsigned i = 0; i < vec_size; i++) {
printf("arr[%u]=%x test[%u]=%x\n", i, arrayvalue.value.vectors[i].aval, i,
test_data_vectors[i].aval);
}
#endif
// compare to test data
for (unsigned i = 0; i < num; i++) {
const unsigned offset = (index + i) % size;
for (unsigned j = 0; j < elem_size_words; j++) {
#ifdef TEST_VERBOSE
printf("arr[%u] == test[%u]\n", (i * elem_size_words) + j, (i * elem_size_words) + j);
#endif
CHECK_RESULT_HEX(arrayvalue.value.vectors[(i * elem_size_words) + j].aval,
test_data_vectors[(i * elem_size_words) + j].aval);
}
for (unsigned j = 0; j < elem_size_words; j++) {
CHECK_RESULT_HEX(arrayvalue.value.vectors[(i * elem_size_words) + j].bval, 0);
}
}
return 0;
}
int test_vpiIntVal(char* name, PLI_BYTE8* test_data, int index, const unsigned num,
const unsigned size, const unsigned elem_size) {
#ifdef TEST_VERBOSE
printf("%%\n%s: name=%s index=%u num=%u size=%u elem_size=%u\n\n", __func__, name, index, num,
size, elem_size);
#endif
// prepare index
int index_arr[1] = {index};
std::vector<PLI_INT32> test_data_integers;
test_data_integers.reserve(size);
for (unsigned i = 0; i < size; i++) {
PLI_INT32& integer = test_data_integers[i];
integer = 0;
for (unsigned j = 0; j < elem_size; j++) {
integer |= (static_cast<PLI_INT32>(test_data[(i * elem_size) + j]) & 0xFF) << (j * 8);
}
}
// get array handle
TestVpiHandle arrayhandle = vpi_handle_by_name(name, NULL);
CHECK_RESULT_NZ(arrayhandle);
// test raw fourstate
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiIntVal;
arrayvalue.flags = 0;
arrayvalue.value.integers = test_data_integers.data();
vpi_put_value_array(arrayhandle, &arrayvalue, index_arr, num);
CHECK_RESULT_NZ(!vpi_chk_error(0));
// get value to check
arrayvalue.value.vectors = 0;
vpi_get_value_array(arrayhandle, &arrayvalue, index_arr, size);
CHECK_RESULT_NZ(!vpi_chk_error(0));
#ifdef TEST_VERBOSE
for (unsigned i = 0; i < size; i++) {
printf("arr[%u]=%x test[%u]=%x\n", i, arrayvalue.value.integers[i], i,
test_data_integers[i]);
}
#endif
// compare to test data
for (unsigned i = 0; i < num; i++) {
#ifdef TEST_VERBOSE
printf("arr[%u] == test[%u]\n", i, i);
#endif
CHECK_RESULT_HEX(arrayvalue.value.integers[i], test_data_integers[i]);
}
return 0;
}
int test_vpiShortIntVal(char* name, PLI_BYTE8* test_data, int index, const unsigned num,
const unsigned size, const unsigned elem_size) {
#ifdef TEST_VERBOSE
printf("%%\n%s: name=%s index=%u num=%u size=%u elem_size=%u\n\n", __func__, name, index, num,
size, elem_size);
#endif
// prepare index
int index_arr[1] = {index};
std::vector<PLI_INT16> test_data_shortints;
test_data_shortints.reserve(size);
for (unsigned i = 0; i < size; i++) {
if (elem_size == 2) {
test_data_shortints[i] = test_data[i * 2] & 0xFF;
test_data_shortints[i] |= test_data[(i * 2) + 1] << 8;
} else {
test_data_shortints[i] = test_data[i] & 0xFF;
}
}
// get array handle
TestVpiHandle arrayhandle = vpi_handle_by_name(name, NULL);
CHECK_RESULT_NZ(arrayhandle);
// test raw fourstate
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiShortIntVal;
arrayvalue.flags = 0;
arrayvalue.value.shortints = test_data_shortints.data();
vpi_put_value_array(arrayhandle, &arrayvalue, index_arr, num);
CHECK_RESULT_NZ(!vpi_chk_error(0));
// get value to check
arrayvalue.value.vectors = 0;
vpi_get_value_array(arrayhandle, &arrayvalue, index_arr, size);
CHECK_RESULT_NZ(!vpi_chk_error(0));
#ifdef TEST_VERBOSE
for (unsigned i = 0; i < size; i++) {
printf("arr[%u]=%x test[%u]=%x\n", i, arrayvalue.value.shortints[i], i,
test_data_shortints[i]);
}
#endif
// compare to test data
for (unsigned i = 0; i < num; i++) {
#ifdef TEST_VERBOSE
printf("arr[%u] == test[%u]\n", i, i);
#endif
CHECK_RESULT_HEX(arrayvalue.value.shortints[i], test_data_shortints[i]);
}
return 0;
}
int test_vpiLongIntVal(char* name, PLI_BYTE8* test_data, int index, const unsigned num,
const unsigned size, const unsigned elem_size) {
#ifdef TEST_VERBOSE
printf("%%\n%s: name=%s index=%u num=%u size=%u elem_size=%u\n\n", __func__, name, index, num,
size, elem_size);
#endif
// prepare index
int index_arr[1] = {index};
std::vector<PLI_INT64> test_data_longints;
test_data_longints.reserve(size);
for (unsigned i = 0; i < size; i++) {
PLI_INT64& longint = test_data_longints[i];
longint = 0;
for (unsigned j = 0; j < elem_size; j++) {
longint |= (static_cast<PLI_INT64>(test_data[(i * elem_size) + j]) & 0xFF) << (j * 8);
}
}
// get array handle
TestVpiHandle arrayhandle = vpi_handle_by_name(name, NULL);
CHECK_RESULT_NZ(arrayhandle);
// test raw fourstate
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiLongIntVal;
arrayvalue.flags = 0;
arrayvalue.value.longints = test_data_longints.data();
vpi_put_value_array(arrayhandle, &arrayvalue, index_arr, num);
CHECK_RESULT_NZ(!vpi_chk_error(0));
// get value to check
arrayvalue.value.vectors = 0;
vpi_get_value_array(arrayhandle, &arrayvalue, index_arr, size);
CHECK_RESULT_NZ(!vpi_chk_error(0));
// compare to test data
for (unsigned i = 0; i < num; i++) {
#ifdef TEST_VERBOSE
printf("arr[%u] == test[%u]\n", i, i);
#endif
CHECK_RESULT_HEX(arrayvalue.value.longints[i], test_data_longints[i]);
}
return 0;
}
int mon_check_props(void) {
// skip test if not verilator (value_array accessors unimplemented in other sims)
if (!TestSimulator::is_verilator()) {
#ifdef VERILATOR
printf("TestSimulator indicating not verilator, but VERILATOR macro is defined\n");
return 1;
#endif
return 0;
}
const unsigned NUM_ELEMENTS = 4;
PLI_BYTE8 write_bytes[NUM_ELEMENTS]
= {static_cast<PLI_BYTE8>(0xad), static_cast<PLI_BYTE8>(0xde),
static_cast<PLI_BYTE8>(0xef), static_cast<PLI_BYTE8>(0xbe)};
PLI_BYTE8 write_shorts[NUM_ELEMENTS * 2] = {
static_cast<PLI_BYTE8>(0xad), static_cast<PLI_BYTE8>(0xde), static_cast<PLI_BYTE8>(0xef),
static_cast<PLI_BYTE8>(0xbe), static_cast<PLI_BYTE8>(0xfe), static_cast<PLI_BYTE8>(0xca),
static_cast<PLI_BYTE8>(0x0d), static_cast<PLI_BYTE8>(0xf0)};
PLI_BYTE8 write_words[NUM_ELEMENTS * 4] = {
static_cast<PLI_BYTE8>(0xef), static_cast<PLI_BYTE8>(0xbe), static_cast<PLI_BYTE8>(0xad),
static_cast<PLI_BYTE8>(0xde), static_cast<PLI_BYTE8>(0x0d), static_cast<PLI_BYTE8>(0xf0),
static_cast<PLI_BYTE8>(0xfe), static_cast<PLI_BYTE8>(0xca), static_cast<PLI_BYTE8>(0x03),
static_cast<PLI_BYTE8>(0x02), static_cast<PLI_BYTE8>(0x01), static_cast<PLI_BYTE8>(0x00),
static_cast<PLI_BYTE8>(0x07), static_cast<PLI_BYTE8>(0x06), static_cast<PLI_BYTE8>(0x05),
static_cast<PLI_BYTE8>(0x04)};
PLI_BYTE8 write_longs[NUM_ELEMENTS * 8] = {
static_cast<PLI_BYTE8>(0x0d), static_cast<PLI_BYTE8>(0xf0), static_cast<PLI_BYTE8>(0xfe),
static_cast<PLI_BYTE8>(0xca), static_cast<PLI_BYTE8>(0xef), static_cast<PLI_BYTE8>(0xbe),
static_cast<PLI_BYTE8>(0xad), static_cast<PLI_BYTE8>(0xde), static_cast<PLI_BYTE8>(0x07),
static_cast<PLI_BYTE8>(0x06), static_cast<PLI_BYTE8>(0x05), static_cast<PLI_BYTE8>(0x04),
static_cast<PLI_BYTE8>(0x03), static_cast<PLI_BYTE8>(0x02), static_cast<PLI_BYTE8>(0x01),
static_cast<PLI_BYTE8>(0x00), static_cast<PLI_BYTE8>(0x0F), static_cast<PLI_BYTE8>(0x0E),
static_cast<PLI_BYTE8>(0x0D), static_cast<PLI_BYTE8>(0x0C), static_cast<PLI_BYTE8>(0x0B),
static_cast<PLI_BYTE8>(0x0A), static_cast<PLI_BYTE8>(0x09), static_cast<PLI_BYTE8>(0x08),
static_cast<PLI_BYTE8>(0x17), static_cast<PLI_BYTE8>(0x16), static_cast<PLI_BYTE8>(0x15),
static_cast<PLI_BYTE8>(0x14), static_cast<PLI_BYTE8>(0x13), static_cast<PLI_BYTE8>(0x12),
static_cast<PLI_BYTE8>(0x11), static_cast<PLI_BYTE8>(0x10)};
PLI_BYTE8 write_customs[NUM_ELEMENTS * 9] = {
static_cast<PLI_BYTE8>(0x0d), static_cast<PLI_BYTE8>(0xf0), static_cast<PLI_BYTE8>(0xfe),
static_cast<PLI_BYTE8>(0xca), static_cast<PLI_BYTE8>(0xef), static_cast<PLI_BYTE8>(0xbe),
static_cast<PLI_BYTE8>(0xad), static_cast<PLI_BYTE8>(0xde), static_cast<PLI_BYTE8>(0x1A),
static_cast<PLI_BYTE8>(0x07), static_cast<PLI_BYTE8>(0x06), static_cast<PLI_BYTE8>(0x05),
static_cast<PLI_BYTE8>(0x04), static_cast<PLI_BYTE8>(0x03), static_cast<PLI_BYTE8>(0x02),
static_cast<PLI_BYTE8>(0x01), static_cast<PLI_BYTE8>(0x00), static_cast<PLI_BYTE8>(0x15),
static_cast<PLI_BYTE8>(0x0F), static_cast<PLI_BYTE8>(0x0E), static_cast<PLI_BYTE8>(0x0D),
static_cast<PLI_BYTE8>(0x0C), static_cast<PLI_BYTE8>(0x0B), static_cast<PLI_BYTE8>(0x0A),
static_cast<PLI_BYTE8>(0x09), static_cast<PLI_BYTE8>(0x08), static_cast<PLI_BYTE8>(0x0A),
static_cast<PLI_BYTE8>(0x17), static_cast<PLI_BYTE8>(0x16), static_cast<PLI_BYTE8>(0x15),
static_cast<PLI_BYTE8>(0x14), static_cast<PLI_BYTE8>(0x13), static_cast<PLI_BYTE8>(0x12),
static_cast<PLI_BYTE8>(0x11), static_cast<PLI_BYTE8>(0x10), static_cast<PLI_BYTE8>(0x05)};
char write_bytes_name[] = "test.write_bytes";
char write_bytes_nonzero_index_name[] = "test.write_bytes_nonzero_index";
char write_bytes_rl_name[] = "test.write_bytes_rl";
char write_shorts_name[] = "test.write_shorts";
char write_words_name[] = "test.write_words";
char write_integers_name[] = "test.write_integers";
char write_longs_name[] = "test.write_longs";
char write_customs_name[] = "test.write_customs";
char write_customs_nonzero_index_rl_name[] = "test.write_customs_nonzero_index_rl";
for (unsigned i = 0; i < NUM_ELEMENTS; i++) {
for (unsigned j = 0; j < (NUM_ELEMENTS + 1); j++) {
if (test_vpiRawFourStateVal(write_bytes_name, write_bytes, i, j, NUM_ELEMENTS, 1))
return 1;
if (test_vpiRawFourStateVal(write_bytes_nonzero_index_name, write_bytes, i + 1, j,
NUM_ELEMENTS, 1))
return 1;
if (test_vpiRawFourStateVal(write_bytes_rl_name, write_bytes, i, j, NUM_ELEMENTS, 1))
return 1;
if (test_vpiRawFourStateVal(write_shorts_name, write_shorts, i, j, NUM_ELEMENTS, 2))
return 1;
if (test_vpiRawFourStateVal(write_words_name, write_words, i, j, NUM_ELEMENTS, 4))
return 1;
if (test_vpiRawFourStateVal(write_integers_name, write_words, i, j, NUM_ELEMENTS, 4))
return 1;
if (test_vpiRawFourStateVal(write_longs_name, write_longs, i, j, NUM_ELEMENTS, 8))
return 1;
if (test_vpiRawFourStateVal(write_customs_name, write_customs, i, j, NUM_ELEMENTS, 9))
return 1;
if (test_vpiRawFourStateVal(write_customs_nonzero_index_rl_name, write_customs, i + 1,
j, NUM_ELEMENTS, 9))
return 1;
if (test_vpiRawTwoStateVal(write_bytes_name, write_bytes, i, j, NUM_ELEMENTS, 1))
return 1;
if (test_vpiRawTwoStateVal(write_bytes_rl_name, write_bytes, i, j, NUM_ELEMENTS, 1))
return 1;
if (test_vpiRawTwoStateVal(write_bytes_nonzero_index_name, write_bytes, i + 1, j,
NUM_ELEMENTS, 1))
return 1;
if (test_vpiRawTwoStateVal(write_shorts_name, write_shorts, i, j, NUM_ELEMENTS, 2))
return 1;
if (test_vpiRawTwoStateVal(write_words_name, write_words, i, j, NUM_ELEMENTS, 4))
return 1;
if (test_vpiRawTwoStateVal(write_integers_name, write_words, i, j, NUM_ELEMENTS, 4))
return 1;
if (test_vpiRawTwoStateVal(write_longs_name, write_longs, i, j, NUM_ELEMENTS, 8))
return 1;
if (test_vpiRawTwoStateVal(write_customs_name, write_customs, i, j, NUM_ELEMENTS, 9))
return 1;
if (test_vpiRawTwoStateVal(write_customs_nonzero_index_rl_name, write_customs, i + 1,
j, NUM_ELEMENTS, 9))
return 1;
if (test_vpiVectorVal(write_bytes_name, write_bytes, i, j, NUM_ELEMENTS, 1)) return 1;
if (test_vpiVectorVal(write_bytes_nonzero_index_name, write_bytes, i + 1, j,
NUM_ELEMENTS, 1))
return 1;
if (test_vpiVectorVal(write_bytes_rl_name, write_bytes, i, j, NUM_ELEMENTS, 1))
return 1;
if (test_vpiVectorVal(write_shorts_name, write_shorts, i, j, NUM_ELEMENTS, 2))
return 1;
if (test_vpiVectorVal(write_words_name, write_words, i, j, NUM_ELEMENTS, 4)) return 1;
if (test_vpiVectorVal(write_integers_name, write_words, i, j, NUM_ELEMENTS, 4))
return 1;
if (test_vpiVectorVal(write_longs_name, write_longs, i, j, NUM_ELEMENTS, 8)) return 1;
if (test_vpiVectorVal(write_customs_name, write_customs, i, j, NUM_ELEMENTS, 9))
return 1;
if (test_vpiVectorVal(write_customs_nonzero_index_rl_name, write_customs, i + 1, j,
NUM_ELEMENTS, 9))
return 1;
if (test_vpiShortIntVal(write_bytes_name, write_bytes, i, j, NUM_ELEMENTS, 1))
return 1;
if (test_vpiShortIntVal(write_bytes_nonzero_index_name, write_bytes, i + 1, j,
NUM_ELEMENTS, 1))
return 1;
if (test_vpiShortIntVal(write_bytes_rl_name, write_bytes, i, j, NUM_ELEMENTS, 1))
return 1;
if (test_vpiShortIntVal(write_shorts_name, write_shorts, i, j, NUM_ELEMENTS, 2))
return 1;
if (test_vpiIntVal(write_bytes_name, write_bytes, i, j, NUM_ELEMENTS, 1)) return 1;
if (test_vpiIntVal(write_bytes_nonzero_index_name, write_bytes, i + 1, j, NUM_ELEMENTS,
1))
return 1;
if (test_vpiIntVal(write_bytes_rl_name, write_bytes, i, j, NUM_ELEMENTS, 1)) return 1;
if (test_vpiIntVal(write_words_name, write_words, i, j, NUM_ELEMENTS, 4)) return 1;
if (test_vpiIntVal(write_integers_name, write_words, i, j, NUM_ELEMENTS, 4)) return 1;
if (test_vpiLongIntVal(write_bytes_name, write_bytes, i, j, NUM_ELEMENTS, 1)) return 1;
if (test_vpiLongIntVal(write_bytes_nonzero_index_name, write_bytes, i + 1, j,
NUM_ELEMENTS, 1))
return 1;
if (test_vpiLongIntVal(write_bytes_rl_name, write_bytes, i, j, NUM_ELEMENTS, 1))
return 1;
if (test_vpiLongIntVal(write_shorts_name, write_shorts, i, j, NUM_ELEMENTS, 2))
return 1;
if (test_vpiLongIntVal(write_words_name, write_words, i, j, NUM_ELEMENTS, 4)) return 1;
if (test_vpiLongIntVal(write_integers_name, write_words, i, j, NUM_ELEMENTS, 4))
return 1;
if (test_vpiLongIntVal(write_longs_name, write_longs, i, j, NUM_ELEMENTS, 8)) return 1;
}
}
{
// test unsupported format
TestVpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"test.write_longs", NULL);
CHECK_RESULT_NZ(object);
double datap[4] = {0, 0, 0, 0};
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiRealVal;
arrayvalue.flags = 0;
arrayvalue.value.reals = datap;
PLI_INT32 indexp[1] = {0};
vpi_put_value_array(object, &arrayvalue, indexp, 4);
CHECK_RESULT_NZ(vpi_chk_error(0));
arrayvalue.format = vpiShortRealVal;
vpi_put_value_array(object, &arrayvalue, indexp, 4);
CHECK_RESULT_NZ(vpi_chk_error(0));
arrayvalue.format = vpiTimeVal;
vpi_put_value_array(object, &arrayvalue, indexp, 4);
CHECK_RESULT_NZ(vpi_chk_error(0));
}
{
// test null array value
TestVpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"test.write_words", NULL);
CHECK_RESULT_NZ(object);
PLI_INT32 indexp[1] = {0};
vpi_put_value_array(object, 0, indexp, 4);
CHECK_RESULT_NZ(vpi_chk_error(0));
}
{
// test unsupported TestVpiHandle
TestVpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"test", NULL);
CHECK_RESULT_NZ(object);
int datap[4] = {0, 0, 0, 0};
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiIntVal;
arrayvalue.flags = 0;
arrayvalue.value.integers = datap;
PLI_INT32 indexp[1] = {0};
vpi_put_value_array(object, &arrayvalue, indexp, 4);
CHECK_RESULT_NZ(vpi_chk_error(0));
}
{
// test unsupported type
TestVpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"test.write_scalar", NULL);
CHECK_RESULT_NZ(object);
int datap[4] = {0, 0, 0, 0};
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiIntVal;
arrayvalue.flags = 0;
arrayvalue.value.integers = datap;
PLI_INT32 indexp[1] = {0};
vpi_put_value_array(object, &arrayvalue, indexp, 4);
CHECK_RESULT_NZ(vpi_chk_error(0));
}
{
// test index out of bounds
TestVpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"test.write_bounds", NULL);
CHECK_RESULT_NZ(object);
int datap[4] = {0, 0, 0, 0};
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiIntVal;
arrayvalue.flags = 0;
arrayvalue.value.integers = datap;
PLI_INT32 indexp[1] = {4};
vpi_put_value_array(object, &arrayvalue, indexp, 4);
CHECK_RESULT_NZ(vpi_chk_error(0));
indexp[0] = 0;
vpi_put_value_array(object, &arrayvalue, indexp, 4);
CHECK_RESULT_NZ(vpi_chk_error(0));
}
{
// test inaccessible
TestVpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"test.write_inaccessible", NULL);
CHECK_RESULT_NZ(object);
int datap[4] = {0, 0, 0, 0};
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiIntVal;
arrayvalue.flags = 0;
arrayvalue.value.integers = datap;
PLI_INT32 indexp[1] = {0};
vpi_put_value_array(object, &arrayvalue, indexp, 4);
CHECK_RESULT_NZ(vpi_chk_error(0));
}
{
// test unsupported flags
TestVpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"test.write_words", NULL);
CHECK_RESULT_NZ(object);
int datap[4] = {0, 0, 0, 0};
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiPropagateOff;
arrayvalue.flags = 0;
arrayvalue.value.integers = datap;
PLI_INT32 indexp[1] = {0};
vpi_put_value_array(object, &arrayvalue, indexp, 4);
CHECK_RESULT_NZ(vpi_chk_error(0));
arrayvalue.flags = vpiOneValue;
vpi_put_value_array(object, &arrayvalue, indexp, 4);
CHECK_RESULT_NZ(vpi_chk_error(0));
}
{
// test unsupported format & type combination
TestVpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"test.write_words", NULL);
CHECK_RESULT_NZ(object);
int datap[4] = {0, 0, 0, 0};
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiShortIntVal;
arrayvalue.flags = 0;
arrayvalue.value.integers = datap;
PLI_INT32 indexp[1] = {0};
vpi_put_value_array(object, &arrayvalue, indexp, 4);
CHECK_RESULT_NZ(vpi_chk_error(0));
arrayvalue.flags = vpiOneValue;
vpi_put_value_array(object, &arrayvalue, indexp, 4);
CHECK_RESULT_NZ(vpi_chk_error(0));
}
{
// test num out of bounds
TestVpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"test.write_words", NULL);
CHECK_RESULT_NZ(object);
int datap[4] = {0, 0, 0, 0};
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiIntVal;
arrayvalue.flags = 0;
arrayvalue.value.integers = datap;
PLI_INT32 indexp[1] = {0};
vpi_put_value_array(object, &arrayvalue, indexp, 5);
CHECK_RESULT_NZ(~vpi_chk_error(0));
}
{
// test null arrayvalue
TestVpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"test.write_words", NULL);
CHECK_RESULT_NZ(object);
PLI_INT32 indexp[1] = {0};
vpi_get_value_array(object, 0, indexp, 0);
CHECK_RESULT_NZ(vpi_chk_error(0));
}
{
// test null indexp
TestVpiHandle object = vpi_handle_by_name((PLI_BYTE8*)"test.write_words", NULL);
CHECK_RESULT_NZ(object);
int datap[4] = {0, 0, 0, 0};
s_vpi_arrayvalue arrayvalue;
arrayvalue.format = vpiIntVal;
arrayvalue.flags = 0;
arrayvalue.value.integers = datap;
vpi_get_value_array(object, &arrayvalue, 0, 0);
CHECK_RESULT_NZ(vpi_chk_error(0));
}
return 0;
}
extern "C" int mon_check(void) { return mon_check_props(); }
#ifdef IS_VPI
static int mon_check_vpi() {
TestVpiHandle href = vpi_handle(vpiSysTfCall, 0);
s_vpi_value vpi_value;
vpi_value.format = vpiIntVal;
vpi_value.value.integer = mon_check();
vpi_put_value(href, &vpi_value, NULL, vpiNoDelay);
return 0;
}
static s_vpi_systf_data vpi_systf_data[] = {{vpiSysFunc, vpiIntFunc, (PLI_BYTE8*)"$mon_check",
(PLI_INT32(*)(PLI_BYTE8*))mon_check_vpi, 0, 0, 0},
0};
// cver entry
void vpi_compat_bootstrap(void) {
p_vpi_systf_data systf_data_p;
systf_data_p = &(vpi_systf_data[0]);
while (systf_data_p->type != 0) vpi_register_systf(systf_data_p++);
}
// icarus entry
void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0};
#else
int main(int argc, char** argv) {
Verilated::commandArgs(argc, argv);
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
const std::unique_ptr<VM_PREFIX> top{new VM_PREFIX{contextp.get(), ""}};
contextp->fatalOnVpiError(0);
#ifdef VERILATOR
#ifdef TEST_VERBOSE
contextp->scopesDump();
#endif
#endif
while (!contextp->gotFinish()) { top->eval(); }
return 0;
}
#endif

View File

@ -0,0 +1,23 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2024 by Wilson Snyder. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('simulator')
test.compile(make_top_shell=False,
make_main=False,
make_pli=True,
verilator_flags2=["--exe --vpi --no-l2name", test.pli_filename],
iv_flags2=["-g2005-sv -D USE_VPI_NOT_DPI"],
v_flags2=["+define+USE_VPI_NOT_DPI +define+VERILATOR_COMMENTS"])
test.execute(use_libvpi=True)
test.passes()

View File

@ -0,0 +1,76 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// Copyright 2024 by Diego Roux. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
`ifdef VERILATOR_COMMENTS
`define PUBLIC_FLAT_RD /*verilator public_flat_rd*/
`define PUBLIC_FLAT_RW /*verilator public_flat_rw*/
`else
`define PUBLIC_FLAT_RD
`define PUBLIC_FLAT_RW
`endif
module test ();
`ifdef VERILATOR
`systemc_header
extern "C" int mon_check();
`verilog
`endif
reg [7:0] write_bytes [0:3] `PUBLIC_FLAT_RW;
reg [7:0] write_bytes_rl [3:0] `PUBLIC_FLAT_RW;
reg [7:0] write_bytes_nonzero_index [1:4] `PUBLIC_FLAT_RW;
reg [15:0] write_shorts [0:3] `PUBLIC_FLAT_RW;
reg [31:0] write_words [0:3] `PUBLIC_FLAT_RW;
reg [63:0] write_longs [0:3] `PUBLIC_FLAT_RW;
reg [68:0] write_customs [0:3] `PUBLIC_FLAT_RW;
reg [68:0] write_customs_nonzero_index_rl [4:1] `PUBLIC_FLAT_RW;
integer write_integers [0:3] `PUBLIC_FLAT_RW;
reg [7:0] write_scalar `PUBLIC_FLAT_RW;
reg [7:0] write_bounds [1:3] `PUBLIC_FLAT_RW;
reg [7:0] write_inaccessible [0:3] `PUBLIC_FLAT_RD;
`ifdef IVERILOG
// stop icarus optimizing signals away
wire redundant = write_bytes[0][0] |
write_bytes[0][0] |
write_bytes_rl[0][0] |
write_bytes_nonzero_index[1][0] |
write_shorts[0][0] |
write_words[0][0] |
write_longs[0][0] |
write_customs[0][0] |
write_customs_nonzero_index_rl[1][0] |
write_integers[0][0] |
write_scalar[0] |
write_bounds[1][0] |
write_inaccessible[0][0];
`endif
integer status;
initial begin
`ifdef IVERILOG
status = $mon_check;
`endif
`ifdef VERILATOR
status = $c32("mon_check()");
`endif
if (status != 0) begin
$write("%%Error: t_vpi_put_value_array.cpp:%0d: C Test failed\n", status);
$stop;
end
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -57,8 +57,6 @@ int _mon_check_unimpl(p_cb_data cb_data) {
vpi_get64(0, NULL);
vpi_get_delays(NULL, NULL);
vpi_put_delays(NULL, NULL);
vpi_get_value_array(NULL, NULL, NULL, 0);
vpi_put_value_array(NULL, NULL, NULL, 0);
vpi_get_time(NULL, NULL);
vpi_mcd_name(0);
vpi_compare_objects(NULL, NULL);