diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index ea9a0b110..9fd2ac91e 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -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 diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index be027161e..ac885332d 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -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 +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 +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::value, "type T is not an integral type"); + static_assert(std::is_unsigned::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(-1) + : ~(static_cast(-1) << (element_size_bytes * 8)); + for (unsigned i = 0; i < num; i++) { + dst[index] = src[i] & static_cast(mask); + index = leftIsLow ? index == (size - 1) ? 0 : index + 1 + : index == 0 ? size - 1 + : index - 1; + } +} + +template +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::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(src[index]); + dst[i * 2].bval = 0; + dst[(i * 2) + 1].aval = static_cast(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 +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::value, "type T is not unsigned"); + static_assert(std::is_integral::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(-1) + : ~(static_cast(-1) << (element_size_bytes * 8)); + for (unsigned i = 0; i < num; i++) { + dst[index] = src[i * 2].aval; + dst[index] + |= (static_cast(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(-1) + : ~(static_cast(-1) << ((element_size_bytes - bytes_stored) * 8)); + dst[(index * element_size_words) + j] + = static_cast(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 +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::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 +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(0xFF) & 0xFF) << (k * 8)); + dst_data |= ((static_cast(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(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(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(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(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(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(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 diff --git a/include/verilatedos.h b/include/verilatedos.h index 4022ac2b0..be0cd59a2 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -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 diff --git a/test_regress/t/TestVpi.h b/test_regress/t/TestVpi.h index 4a87b8e51..4c3bbc651 100644 --- a/test_regress/t/TestVpi.h +++ b/test_regress/t/TestVpi.h @@ -11,6 +11,7 @@ #include "sv_vpi_user.h" #include "vpi_user.h" +#include // Avoid C++11 in this file as not all simulators allow it diff --git a/test_regress/t/t_vpi_get_value_array.cpp b/test_regress/t/t_vpi_get_value_array.cpp new file mode 100644 index 000000000..86796eb04 --- /dev/null +++ b/test_regress/t/t_vpi_get_value_array.cpp @@ -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 + +//====================================================================== + +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 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(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 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(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 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 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(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(0xad), static_cast(0xde), + static_cast(0xef), static_cast(0xbe)}; + + PLI_BYTE8 read_shorts[NUM_ELEMENTS * 2] = { + static_cast(0xad), static_cast(0xde), static_cast(0xef), + static_cast(0xbe), static_cast(0xfe), static_cast(0xca), + static_cast(0x0d), static_cast(0xf0)}; + + PLI_BYTE8 read_words[NUM_ELEMENTS * 4] = { + static_cast(0xef), static_cast(0xbe), static_cast(0xad), + static_cast(0xde), static_cast(0x0d), static_cast(0xf0), + static_cast(0xfe), static_cast(0xca), static_cast(0x03), + static_cast(0x02), static_cast(0x01), static_cast(0x00), + static_cast(0x07), static_cast(0x06), static_cast(0x05), + static_cast(0x04)}; + + PLI_BYTE8 read_longs[NUM_ELEMENTS * 8] = { + static_cast(0x0d), static_cast(0xf0), static_cast(0xfe), + static_cast(0xca), static_cast(0xef), static_cast(0xbe), + static_cast(0xad), static_cast(0xde), static_cast(0x07), + static_cast(0x06), static_cast(0x05), static_cast(0x04), + static_cast(0x03), static_cast(0x02), static_cast(0x01), + static_cast(0x00), static_cast(0x0F), static_cast(0x0E), + static_cast(0x0D), static_cast(0x0C), static_cast(0x0B), + static_cast(0x0A), static_cast(0x09), static_cast(0x08), + static_cast(0x17), static_cast(0x16), static_cast(0x15), + static_cast(0x14), static_cast(0x13), static_cast(0x12), + static_cast(0x11), static_cast(0x10)}; + + PLI_BYTE8 read_customs[NUM_ELEMENTS * 9] = { + static_cast(0x0d), static_cast(0xf0), static_cast(0xfe), + static_cast(0xca), static_cast(0xef), static_cast(0xbe), + static_cast(0xad), static_cast(0xde), static_cast(0x1A), + static_cast(0x07), static_cast(0x06), static_cast(0x05), + static_cast(0x04), static_cast(0x03), static_cast(0x02), + static_cast(0x01), static_cast(0x00), static_cast(0x15), + static_cast(0x0F), static_cast(0x0E), static_cast(0x0D), + static_cast(0x0C), static_cast(0x0B), static_cast(0x0A), + static_cast(0x09), static_cast(0x08), static_cast(0x0A), + static_cast(0x17), static_cast(0x16), static_cast(0x15), + static_cast(0x14), static_cast(0x13), static_cast(0x12), + static_cast(0x11), static_cast(0x10), static_cast(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 contextp{new VerilatedContext}; + const std::unique_ptr 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 diff --git a/test_regress/t/t_vpi_get_value_array.py b/test_regress/t/t_vpi_get_value_array.py new file mode 100755 index 000000000..9f7ed1832 --- /dev/null +++ b/test_regress/t/t_vpi_get_value_array.py @@ -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() diff --git a/test_regress/t/t_vpi_get_value_array.v b/test_regress/t/t_vpi_get_value_array.v new file mode 100644 index 000000000..86a82df92 --- /dev/null +++ b/test_regress/t/t_vpi_get_value_array.v @@ -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 diff --git a/test_regress/t/t_vpi_put_value_array.cpp b/test_regress/t/t_vpi_put_value_array.cpp new file mode 100644 index 000000000..2e9008ba4 --- /dev/null +++ b/test_regress/t/t_vpi_put_value_array.cpp @@ -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 + +//====================================================================== + +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 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 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(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 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(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 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 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(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(0xad), static_cast(0xde), + static_cast(0xef), static_cast(0xbe)}; + + PLI_BYTE8 write_shorts[NUM_ELEMENTS * 2] = { + static_cast(0xad), static_cast(0xde), static_cast(0xef), + static_cast(0xbe), static_cast(0xfe), static_cast(0xca), + static_cast(0x0d), static_cast(0xf0)}; + + PLI_BYTE8 write_words[NUM_ELEMENTS * 4] = { + static_cast(0xef), static_cast(0xbe), static_cast(0xad), + static_cast(0xde), static_cast(0x0d), static_cast(0xf0), + static_cast(0xfe), static_cast(0xca), static_cast(0x03), + static_cast(0x02), static_cast(0x01), static_cast(0x00), + static_cast(0x07), static_cast(0x06), static_cast(0x05), + static_cast(0x04)}; + + PLI_BYTE8 write_longs[NUM_ELEMENTS * 8] = { + static_cast(0x0d), static_cast(0xf0), static_cast(0xfe), + static_cast(0xca), static_cast(0xef), static_cast(0xbe), + static_cast(0xad), static_cast(0xde), static_cast(0x07), + static_cast(0x06), static_cast(0x05), static_cast(0x04), + static_cast(0x03), static_cast(0x02), static_cast(0x01), + static_cast(0x00), static_cast(0x0F), static_cast(0x0E), + static_cast(0x0D), static_cast(0x0C), static_cast(0x0B), + static_cast(0x0A), static_cast(0x09), static_cast(0x08), + static_cast(0x17), static_cast(0x16), static_cast(0x15), + static_cast(0x14), static_cast(0x13), static_cast(0x12), + static_cast(0x11), static_cast(0x10)}; + + PLI_BYTE8 write_customs[NUM_ELEMENTS * 9] = { + static_cast(0x0d), static_cast(0xf0), static_cast(0xfe), + static_cast(0xca), static_cast(0xef), static_cast(0xbe), + static_cast(0xad), static_cast(0xde), static_cast(0x1A), + static_cast(0x07), static_cast(0x06), static_cast(0x05), + static_cast(0x04), static_cast(0x03), static_cast(0x02), + static_cast(0x01), static_cast(0x00), static_cast(0x15), + static_cast(0x0F), static_cast(0x0E), static_cast(0x0D), + static_cast(0x0C), static_cast(0x0B), static_cast(0x0A), + static_cast(0x09), static_cast(0x08), static_cast(0x0A), + static_cast(0x17), static_cast(0x16), static_cast(0x15), + static_cast(0x14), static_cast(0x13), static_cast(0x12), + static_cast(0x11), static_cast(0x10), static_cast(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 contextp{new VerilatedContext}; + const std::unique_ptr 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 diff --git a/test_regress/t/t_vpi_put_value_array.py b/test_regress/t/t_vpi_put_value_array.py new file mode 100755 index 000000000..9f7ed1832 --- /dev/null +++ b/test_regress/t/t_vpi_put_value_array.py @@ -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() diff --git a/test_regress/t/t_vpi_put_value_array.v b/test_regress/t/t_vpi_put_value_array.v new file mode 100644 index 000000000..f0aefe35b --- /dev/null +++ b/test_regress/t/t_vpi_put_value_array.v @@ -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 diff --git a/test_regress/t/t_vpi_unimpl.cpp b/test_regress/t/t_vpi_unimpl.cpp index c6d73f324..732b30d53 100644 --- a/test_regress/t/t_vpi_unimpl.cpp +++ b/test_regress/t/t_vpi_unimpl.cpp @@ -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);