parent
052812bb87
commit
69dce205d3
|
@ -3289,7 +3289,7 @@ uint32_t VerilatedVarProps::entSize() const VL_MT_SAFE {
|
|||
case VLVT_UINT16: size = sizeof(SData); break;
|
||||
case VLVT_UINT32: size = sizeof(IData); break;
|
||||
case VLVT_UINT64: size = sizeof(QData); break;
|
||||
case VLVT_WDATA: size = VL_WORDS_I(packed().elements()) * sizeof(IData); break;
|
||||
case VLVT_WDATA: size = VL_WORDS_I(entBits()) * sizeof(IData); break;
|
||||
default: size = 0; break; // LCOV_EXCL_LINE
|
||||
}
|
||||
return size;
|
||||
|
@ -3308,7 +3308,7 @@ void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const
|
|||
uint8_t* bytep = reinterpret_cast<uint8_t*>(datap);
|
||||
// If on index 1 of a 2 index array, then each index 1 is index2sz*entsz
|
||||
size_t slicesz = entSize();
|
||||
for (int d = dim + 1; d <= m_udims; ++d) slicesz *= elements(d);
|
||||
for (int d = dim + 1; d <= udims(); ++d) slicesz *= elements(d);
|
||||
bytep += indxAdj * slicesz;
|
||||
return bytep;
|
||||
}
|
||||
|
@ -3369,32 +3369,28 @@ void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) VL_
|
|||
}
|
||||
|
||||
void VerilatedScope::varInsert(int finalize, const char* namep, void* datap, bool isParam,
|
||||
VerilatedVarType vltype, int vlflags, int dims, ...) VL_MT_UNSAFE {
|
||||
VerilatedVarType vltype, int vlflags, int udims, int pdims ...) VL_MT_UNSAFE {
|
||||
// Grab dimensions
|
||||
// In the future we may just create a large table at emit time and
|
||||
// statically construct from that.
|
||||
if (!finalize) return;
|
||||
|
||||
if (!m_varsp) m_varsp = new VerilatedVarNameMap;
|
||||
VerilatedVar var(namep, datap, vltype, static_cast<VerilatedVarFlags>(vlflags), dims, isParam);
|
||||
VerilatedVar var(namep, datap, vltype, static_cast<VerilatedVarFlags>(vlflags), udims, pdims, isParam);
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, dims);
|
||||
for (int i = 0; i < dims; ++i) {
|
||||
va_start(ap, pdims);
|
||||
for (int i = 0; i < udims; ++i) {
|
||||
const int msb = va_arg(ap, int);
|
||||
const int lsb = va_arg(ap, int);
|
||||
if (i == 0) {
|
||||
var.m_packed.m_left = msb;
|
||||
var.m_packed.m_right = lsb;
|
||||
} else if (i >= 1 && i <= var.udims()) {
|
||||
var.m_unpacked[i - 1].m_left = msb;
|
||||
var.m_unpacked[i - 1].m_right = lsb;
|
||||
} else {
|
||||
// We could have a linked list of ranges, but really this whole thing needs
|
||||
// to be generalized to support structs and unions, etc.
|
||||
const std::string msg = "Unsupported multi-dimensional public varInsert: "s + namep;
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
|
||||
}
|
||||
var.m_unpacked[i].m_left = msb;
|
||||
var.m_unpacked[i].m_right = lsb;
|
||||
}
|
||||
for (int i = 0; i < pdims; ++i) {
|
||||
const int msb = va_arg(ap, int);
|
||||
const int lsb = va_arg(ap, int);
|
||||
var.m_packed[i].m_left = msb;
|
||||
var.m_packed[i].m_right = lsb;
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
|
|
|
@ -726,7 +726,7 @@ public: // But internals only - called from VerilatedModule's
|
|||
const Type& type) VL_MT_UNSAFE;
|
||||
void exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE;
|
||||
void varInsert(int finalize, const char* namep, void* datap, bool isParam,
|
||||
VerilatedVarType vltype, int vlflags, int dims, ...) VL_MT_UNSAFE;
|
||||
VerilatedVarType vltype, int vlflags, int udims, int pdims, ...) VL_MT_UNSAFE;
|
||||
// ACCESSORS
|
||||
const char* name() const VL_MT_SAFE_POSTINIT { return m_namep; }
|
||||
const char* identifier() const VL_MT_SAFE_POSTINIT { return m_identifierp; }
|
||||
|
|
|
@ -289,7 +289,7 @@ static void _vl_svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
|||
}
|
||||
case VLVT_WDATA: {
|
||||
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
||||
for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) d[i] = wdatap[i];
|
||||
for (int i = 0; i < VL_WORDS_I(varp->entBits()); ++i) d[i] = wdatap[i];
|
||||
return;
|
||||
}
|
||||
default: // LCOV_EXCL_START // Errored earlier
|
||||
|
@ -328,7 +328,7 @@ static void _vl_svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandl
|
|||
}
|
||||
case VLVT_WDATA: {
|
||||
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
||||
for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) {
|
||||
for (int i = 0; i < VL_WORDS_I(varp->entBits()); ++i) {
|
||||
d[i].aval = wdatap[i];
|
||||
d[i].bval = 0;
|
||||
}
|
||||
|
@ -354,7 +354,7 @@ static void _vl_svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecV
|
|||
case VLVT_UINT64: *(reinterpret_cast<QData*>(datap)) = VL_SET_QII(s[1], s[0]); break;
|
||||
case VLVT_WDATA: {
|
||||
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
||||
for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) wdatap[i] = s[i];
|
||||
for (int i = 0; i < VL_WORDS_I(varp->entBits()); ++i) wdatap[i] = s[i];
|
||||
return;
|
||||
}
|
||||
default: // LCOV_EXCL_START // Errored earlier
|
||||
|
@ -376,7 +376,7 @@ static void _vl_svPutLogicArrElemVecVal(const svOpenArrayHandle d, const svLogic
|
|||
case VLVT_UINT64: *(reinterpret_cast<QData*>(datap)) = VL_SET_QII(s[1].aval, s[0].aval); break;
|
||||
case VLVT_WDATA: {
|
||||
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
||||
for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) wdatap[i] = s[i].aval;
|
||||
for (int i = 0; i < VL_WORDS_I(varp->entBits()); ++i) wdatap[i] = s[i].aval;
|
||||
return;
|
||||
}
|
||||
default: // LCOV_EXCL_START // Errored earlier
|
||||
|
|
|
@ -74,27 +74,41 @@ class VerilatedVarProps VL_NOT_FINAL {
|
|||
const uint32_t m_magic; // Magic number
|
||||
const VerilatedVarType m_vltype; // Data type
|
||||
const VerilatedVarFlags m_vlflags; // Direction
|
||||
const int m_pdims; // Packed dimensions, 0 = none
|
||||
const int m_udims; // Unpacked dimensions, 0 = none
|
||||
VerilatedRange m_packed; // Packed array range
|
||||
std::vector<VerilatedRange> m_unpacked; // Unpacked array ranges
|
||||
void initUnpacked(const int* ulims) {
|
||||
for (int i = 0; i < m_udims; ++i) {
|
||||
std::vector<VerilatedRange> m_packed; // Packed array ranges
|
||||
VerilatedRange m_packedDpi; // Flattened packed array range
|
||||
void initUnpacked(int udims, const int* ulims) {
|
||||
for (int i = 0; i < udims; ++i) {
|
||||
const int uleft = ulims ? ulims[2 * i + 0] : 0;
|
||||
const int uright = ulims ? ulims[2 * i + 1] : 0;
|
||||
m_unpacked.emplace_back(uleft, uright);
|
||||
}
|
||||
}
|
||||
void initPacked(int pdims, const int* plims) {
|
||||
int packedSize = 1;
|
||||
for (int i = 0; i < pdims; ++i) {
|
||||
const int pleft = plims ? plims[2 * i + 0] : 0;
|
||||
const int pright = plims ? plims[2 * i + 1] : 0;
|
||||
m_packed.emplace_back(pleft, pright);
|
||||
packedSize *= abs(pleft - pright) + 1;
|
||||
}
|
||||
if (pdims == 1) {
|
||||
// Preserve packed array range if the packed component is 1-D
|
||||
m_packedDpi = m_packed.front();
|
||||
} else {
|
||||
m_packedDpi = VerilatedRange{packedSize - 1, 0};
|
||||
}
|
||||
}
|
||||
// CONSTRUCTORS
|
||||
protected:
|
||||
friend class VerilatedScope;
|
||||
VerilatedVarProps(VerilatedVarType vltype, VerilatedVarFlags vlflags, int pdims, int udims)
|
||||
VerilatedVarProps(VerilatedVarType vltype, VerilatedVarFlags vlflags, int udims, int pdims)
|
||||
: m_magic{MAGIC}
|
||||
, m_vltype{vltype}
|
||||
, m_vlflags{vlflags}
|
||||
, m_pdims{pdims}
|
||||
, m_udims{udims} {
|
||||
initUnpacked(nullptr);
|
||||
, m_vlflags{vlflags} {
|
||||
// Only preallocate the ranges
|
||||
initUnpacked(udims, nullptr);
|
||||
initPacked(pdims, nullptr);
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -103,35 +117,29 @@ public:
|
|||
VerilatedVarProps(VerilatedVarType vltype, int vlflags)
|
||||
: m_magic{MAGIC}
|
||||
, m_vltype{vltype}
|
||||
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
|
||||
, m_pdims{0}
|
||||
, m_udims{0} {}
|
||||
, m_vlflags(VerilatedVarFlags(vlflags)) {} // Need () or GCC 4.8 false warning
|
||||
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int udims, const int* ulims)
|
||||
: m_magic{MAGIC}
|
||||
, m_vltype{vltype}
|
||||
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
|
||||
, m_pdims{0}
|
||||
, m_udims{udims} {
|
||||
initUnpacked(ulims);
|
||||
, m_vlflags(VerilatedVarFlags(vlflags)) { // Need () or GCC 4.8 false warning
|
||||
initUnpacked(udims, ulims);
|
||||
}
|
||||
// With packed
|
||||
class Packed {};
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr)
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pdims, const int* plims)
|
||||
: m_magic{MAGIC}
|
||||
, m_vltype{vltype}
|
||||
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
|
||||
, m_pdims{1}
|
||||
, m_udims{0}
|
||||
, m_packed{pl, pr} {}
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked,
|
||||
int udims, const int* ulims)
|
||||
, m_vlflags(VerilatedVarFlags(vlflags)) { // Need () or GCC 4.8 false warning
|
||||
initPacked(pdims, plims);
|
||||
}
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int udims, const int* ulims,
|
||||
Packed, int pdims, const int* plims)
|
||||
: m_magic{MAGIC}
|
||||
, m_vltype{vltype}
|
||||
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
|
||||
, m_pdims{1}
|
||||
, m_udims{udims}
|
||||
, m_packed{pl, pr} {
|
||||
initUnpacked(ulims);
|
||||
, m_vlflags(VerilatedVarFlags(vlflags)) { // Need () or GCC 4.8 false warning
|
||||
initUnpacked(udims, ulims);
|
||||
initPacked(pdims, plims);
|
||||
}
|
||||
|
||||
~VerilatedVarProps() = default;
|
||||
|
@ -142,41 +150,56 @@ public:
|
|||
return static_cast<VerilatedVarFlags>(static_cast<int>(m_vlflags) & VLVF_MASK_DIR);
|
||||
}
|
||||
uint32_t entSize() const VL_MT_SAFE;
|
||||
uint32_t entBits() const VL_MT_SAFE {
|
||||
uint32_t bits = 1;
|
||||
for (auto it : m_packed)
|
||||
bits *= it.elements();
|
||||
return bits;
|
||||
}
|
||||
bool isPublicRW() const { return ((m_vlflags & VLVF_PUB_RW) != 0); }
|
||||
// DPI compatible C standard layout
|
||||
bool isDpiCLayout() const { return ((m_vlflags & VLVF_DPI_CLAY) != 0); }
|
||||
int udims() const VL_MT_SAFE { return m_udims; }
|
||||
int dims() const { return m_pdims + m_udims; }
|
||||
const VerilatedRange& packed() const VL_MT_SAFE { return m_packed; }
|
||||
const VerilatedRange& unpacked() const { return m_unpacked[0]; }
|
||||
// DPI accessors
|
||||
int udims() const VL_MT_SAFE { return m_unpacked.size(); }
|
||||
int pdims() const VL_MT_SAFE { return m_packed.size(); }
|
||||
int dims() const VL_MT_SAFE { return pdims() + udims(); }
|
||||
const std::vector<VerilatedRange>& packedRanges() const VL_MT_SAFE { return m_packed; }
|
||||
const std::vector<VerilatedRange>& unpackedRanges() const VL_MT_SAFE { return m_unpacked; }
|
||||
const VerilatedRange* range(int dim) const VL_MT_SAFE {
|
||||
if (dim < udims())
|
||||
return &m_unpacked[dim];
|
||||
else if (dim < dims())
|
||||
return &m_packed[dim - udims()];
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
// DPI accessors (with packed dimensions flattened!)
|
||||
int left(int dim) const VL_MT_SAFE {
|
||||
return dim == 0 ? m_packed.left()
|
||||
return dim == 0 ? m_packedDpi.left()
|
||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].left()
|
||||
: 0;
|
||||
}
|
||||
int right(int dim) const VL_MT_SAFE {
|
||||
return dim == 0 ? m_packed.right()
|
||||
return dim == 0 ? m_packedDpi.right()
|
||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].right()
|
||||
: 0;
|
||||
}
|
||||
int low(int dim) const VL_MT_SAFE {
|
||||
return dim == 0 ? m_packed.low()
|
||||
return dim == 0 ? m_packedDpi.low()
|
||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].low()
|
||||
: 0;
|
||||
}
|
||||
int high(int dim) const VL_MT_SAFE {
|
||||
return dim == 0 ? m_packed.high()
|
||||
return dim == 0 ? m_packedDpi.high()
|
||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].high()
|
||||
: 0;
|
||||
}
|
||||
int increment(int dim) const {
|
||||
return dim == 0 ? m_packed.increment()
|
||||
return dim == 0 ? m_packedDpi.increment()
|
||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].increment()
|
||||
: 0;
|
||||
}
|
||||
int elements(int dim) const VL_MT_SAFE {
|
||||
return dim == 0 ? m_packed.elements()
|
||||
return dim == 0 ? m_packedDpi.elements()
|
||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].elements()
|
||||
: 0;
|
||||
}
|
||||
|
@ -208,8 +231,7 @@ public:
|
|||
bool magicOk() const { return m_propsp->magicOk(); }
|
||||
VerilatedVarType vltype() const { return m_propsp->vltype(); }
|
||||
bool isDpiStdLayout() const { return m_propsp->isDpiCLayout(); }
|
||||
const VerilatedRange& packed() const { return m_propsp->packed(); }
|
||||
const VerilatedRange& unpacked() const { return m_propsp->unpacked(); }
|
||||
int entBits() const { return m_propsp->entBits(); }
|
||||
int udims() const VL_MT_SAFE { return m_propsp->udims(); }
|
||||
int left(int dim) const VL_MT_SAFE { return m_propsp->left(dim); }
|
||||
int right(int dim) const VL_MT_SAFE { return m_propsp->right(dim); }
|
||||
|
@ -236,8 +258,8 @@ protected:
|
|||
friend class VerilatedScope;
|
||||
// CONSTRUCTORS
|
||||
VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype,
|
||||
VerilatedVarFlags vlflags, int dims, bool isParam)
|
||||
: VerilatedVarProps{vltype, vlflags, (dims > 0 ? 1 : 0), ((dims > 1) ? dims - 1 : 0)}
|
||||
VerilatedVarFlags vlflags, int udims, int pdims, bool isParam)
|
||||
: VerilatedVarProps{vltype, vlflags, udims, pdims}
|
||||
, m_datap{datap}
|
||||
, m_namep{namep}
|
||||
, m_isParam{isParam} {}
|
||||
|
@ -246,8 +268,6 @@ public:
|
|||
~VerilatedVar() = default;
|
||||
// ACCESSORS
|
||||
void* datap() const { return m_datap; }
|
||||
const VerilatedRange& range() const { return packed(); } // Deprecated
|
||||
const VerilatedRange& array() const { return unpacked(); } // Deprecated
|
||||
const char* name() const { return m_namep; }
|
||||
bool isParam() const { return m_isParam; }
|
||||
};
|
||||
|
|
|
@ -85,7 +85,7 @@ public:
|
|||
// To simplify our free list, we use a size large enough for all derived types
|
||||
// We reserve word zero for the next pointer, as that's safer in case a
|
||||
// dangling reference to the original remains around.
|
||||
static constexpr size_t CHUNK_SIZE = 96;
|
||||
static constexpr size_t CHUNK_SIZE = 128;
|
||||
if (VL_UNCOVERABLE(size > CHUNK_SIZE))
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", "increase CHUNK_SIZE");
|
||||
if (VL_LIKELY(t_freeHeadp)) {
|
||||
|
@ -171,9 +171,9 @@ protected:
|
|||
const VerilatedVar* m_varp = nullptr;
|
||||
const VerilatedScope* m_scopep = nullptr;
|
||||
std::string m_fullname;
|
||||
const VerilatedRange& get_range() const {
|
||||
// Determine number of dimensions and return outermost
|
||||
return (m_varp->dims() > 1) ? m_varp->unpacked() : m_varp->packed();
|
||||
int32_t m_indexedDim = -1;
|
||||
const VerilatedRange* get_range() const {
|
||||
return m_varp->range(m_indexedDim + 1);
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -186,6 +186,7 @@ public:
|
|||
m_varp = varp->m_varp;
|
||||
m_scopep = varp->m_scopep;
|
||||
m_fullname = varp->m_fullname;
|
||||
m_indexedDim = varp->m_indexedDim;
|
||||
}
|
||||
}
|
||||
static VerilatedVpioVarBase* castp(vpiHandle h) {
|
||||
|
@ -193,10 +194,36 @@ public:
|
|||
}
|
||||
const VerilatedVar* varp() const { return m_varp; }
|
||||
const VerilatedScope* scopep() const { return m_scopep; }
|
||||
uint32_t size() const override { return get_range().elements(); }
|
||||
const VerilatedRange* rangep() const override { return &get_range(); }
|
||||
// Returns the number of the currently indexed dimension (starting at -1 for none).
|
||||
int32_t indexedDim() const { return m_indexedDim; }
|
||||
// Returns whether the currently indexed dimension is unpacked.
|
||||
bool isIndexedDimUnpacked() const { return indexedDim() + 1 < varp()->udims(); }
|
||||
// Returns a maximum accessible dimension number, counting only unpacked dimensions
|
||||
// (if onlyUnpacked == true), or both unpacked + packed.
|
||||
int32_t maxDim(bool onlyUnpacked) const {
|
||||
return onlyUnpacked ? varp()->udims() - 1 : varp()->dims() - 1;
|
||||
}
|
||||
// Returns a number of elements in the array, stopping at the unpacked-packed boundary.
|
||||
uint32_t size() const override {
|
||||
const int maxDimNum = maxDim(isIndexedDimUnpacked());
|
||||
int size = 1;
|
||||
for (int dim = indexedDim() + 1; dim <= maxDimNum; dim++)
|
||||
size *= varp()->range(dim)->elements();
|
||||
return size;
|
||||
}
|
||||
// If the array is unpacked, returns the bitsize of a single underlying packed element.
|
||||
// If the array is packed, returns the bitsize of the whole array.
|
||||
uint32_t bitSize() const {
|
||||
if (isIndexedDimUnpacked())
|
||||
return varp()->entBits();
|
||||
else
|
||||
return size();
|
||||
}
|
||||
const VerilatedRange* rangep() const override { return get_range(); }
|
||||
const char* name() const override { return m_varp->name(); }
|
||||
const char* fullname() const override { return m_fullname.c_str(); }
|
||||
virtual void* varDatap() const { return m_varp->datap(); }
|
||||
virtual uint32_t bitOffset() const { return 0; }
|
||||
};
|
||||
|
||||
class VerilatedVpioParam final : public VerilatedVpioVarBase {
|
||||
|
@ -221,7 +248,6 @@ public:
|
|||
default: return vpiUndefined;
|
||||
}
|
||||
}
|
||||
void* varDatap() const { return m_varp->datap(); }
|
||||
};
|
||||
|
||||
class VerilatedVpioRange final : public VerilatedVpio {
|
||||
|
@ -240,25 +266,27 @@ public:
|
|||
};
|
||||
|
||||
class VerilatedVpioRangeIter final : public VerilatedVpio {
|
||||
// Only supports 1 dimension
|
||||
const VerilatedRange* const m_rangep;
|
||||
bool m_done = false;
|
||||
const std::vector<VerilatedRange> m_ranges;
|
||||
std::vector<VerilatedRange>::const_iterator m_iter;
|
||||
|
||||
public:
|
||||
explicit VerilatedVpioRangeIter(const VerilatedRange* rangep)
|
||||
: m_rangep{rangep} {}
|
||||
explicit VerilatedVpioRangeIter(const std::vector<VerilatedRange>& ranges)
|
||||
: m_ranges{ranges} {
|
||||
m_iter = m_ranges.begin();
|
||||
}
|
||||
~VerilatedVpioRangeIter() override = default;
|
||||
static VerilatedVpioRangeIter* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioRangeIter*>(reinterpret_cast<VerilatedVpio*>(h));
|
||||
}
|
||||
uint32_t type() const override { return vpiIterator; }
|
||||
vpiHandle dovpi_scan() override {
|
||||
if (VL_UNLIKELY(m_done)) {
|
||||
if (VL_UNLIKELY(m_iter == m_ranges.end())) {
|
||||
delete this; // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle
|
||||
return nullptr;
|
||||
}
|
||||
m_done = true;
|
||||
return ((new VerilatedVpioRange{m_rangep})->castVpiHandle());
|
||||
VerilatedRange* const rangep = new VerilatedRange(*m_iter);
|
||||
++m_iter;
|
||||
return ((new VerilatedVpioRange{rangep})->castVpiHandle());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -297,14 +325,15 @@ class VerilatedVpioVar VL_NOT_FINAL : public VerilatedVpioVarBase {
|
|||
uint32_t u32;
|
||||
} m_mask; // memoized variable mask
|
||||
uint32_t m_entSize = 0; // memoized variable size
|
||||
uint32_t m_bitOffset = 0;
|
||||
protected:
|
||||
void* m_varDatap = nullptr; // varp()->datap() adjusted for array entries
|
||||
int32_t m_index = 0;
|
||||
std::vector<int32_t> m_index;
|
||||
|
||||
public:
|
||||
VerilatedVpioVar(const VerilatedVar* varp, const VerilatedScope* scopep)
|
||||
: VerilatedVpioVarBase{varp, scopep} {
|
||||
m_mask.u32 = VL_MASK_I(varp->packed().elements());
|
||||
m_mask.u32 = VL_MASK_I(varp->entBits());
|
||||
m_entSize = varp->entSize();
|
||||
m_varDatap = varp->datap();
|
||||
}
|
||||
|
@ -326,10 +355,30 @@ public:
|
|||
static VerilatedVpioVar* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioVar*>(reinterpret_cast<VerilatedVpio*>(h));
|
||||
}
|
||||
uint32_t bitOffset() const override { return m_bitOffset; }
|
||||
uint32_t mask() const { return m_mask.u32; }
|
||||
uint8_t mask_byte(int idx) const { return m_mask.u8[idx & 3]; }
|
||||
uint32_t entSize() const { return m_entSize; }
|
||||
uint32_t index() const { return m_index; }
|
||||
const std::vector<int32_t>& index() const { return m_index; }
|
||||
VerilatedVpioVar* withIndex(int32_t index) const {
|
||||
if (VL_UNLIKELY(indexedDim() + 1 >= varp()->dims()))
|
||||
return nullptr;
|
||||
|
||||
auto ret = new VerilatedVpioVar{this};
|
||||
ret->m_index.push_back(index);
|
||||
ret->m_indexedDim++;
|
||||
|
||||
int chunkSize = 1;
|
||||
for (int dim = maxDim(isIndexedDimUnpacked()); dim > indexedDim() + 1; dim--)
|
||||
chunkSize *= varp()->range(dim)->elements();
|
||||
|
||||
if (isIndexedDimUnpacked())
|
||||
ret->m_varDatap = (static_cast<uint8_t*>(ret->m_varDatap)) + entSize() * chunkSize * (index - get_range()->low());
|
||||
else
|
||||
ret->m_bitOffset += chunkSize * (index - get_range()->low());
|
||||
|
||||
return ret;
|
||||
}
|
||||
uint32_t type() const override {
|
||||
uint32_t type = vpiReg;
|
||||
switch (varp()->vltype()) {
|
||||
|
@ -337,10 +386,21 @@ public:
|
|||
case VLVT_STRING: type = vpiStringVar; break;
|
||||
default: break;
|
||||
}
|
||||
return (varp()->dims() > 1) ? vpiMemory : type; // but might be wire, logic
|
||||
if (isIndexedDimUnpacked())
|
||||
return vpiRegArray;
|
||||
else
|
||||
return type;
|
||||
}
|
||||
const char* fullname() const override {
|
||||
static thread_local std::string t_out;
|
||||
t_out = std::string{scopep()->name()} + "." + name();
|
||||
for (auto idx : index()) {
|
||||
t_out += "[" + std::to_string(idx) + "]";
|
||||
}
|
||||
return t_out.c_str();
|
||||
}
|
||||
void* prevDatap() const { return m_prevDatap; }
|
||||
void* varDatap() const { return m_varDatap; }
|
||||
void* varDatap() const override { return m_varDatap; }
|
||||
void createPrevDatap() {
|
||||
if (VL_UNLIKELY(!m_prevDatap)) {
|
||||
m_prevDatap = new uint8_t[entSize()];
|
||||
|
@ -349,31 +409,6 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class VerilatedVpioMemoryWord final : public VerilatedVpioVar {
|
||||
public:
|
||||
VerilatedVpioMemoryWord(const VerilatedVar* varp, const VerilatedScope* scopep, int32_t index,
|
||||
int offset)
|
||||
: VerilatedVpioVar{varp, scopep} {
|
||||
m_index = index;
|
||||
m_varDatap = (static_cast<uint8_t*>(varp->datap())) + entSize() * offset;
|
||||
}
|
||||
~VerilatedVpioMemoryWord() override = default;
|
||||
static VerilatedVpioMemoryWord* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioMemoryWord*>(reinterpret_cast<VerilatedVpio*>(h));
|
||||
}
|
||||
uint32_t type() const override { return vpiMemoryWord; }
|
||||
uint32_t size() const override { return varp()->packed().elements(); }
|
||||
const VerilatedRange* rangep() const override { return &(varp()->packed()); }
|
||||
const char* fullname() const override {
|
||||
static thread_local std::string t_out;
|
||||
constexpr size_t LEN_MAX_INDEX = 25;
|
||||
char num[LEN_MAX_INDEX];
|
||||
VL_SNPRINTF(num, LEN_MAX_INDEX, "%d", m_index);
|
||||
t_out = std::string{scopep()->name()} + "." + name() + "[" + num + "]";
|
||||
return t_out.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedVpioVarIter final : public VerilatedVpio {
|
||||
const VerilatedScope* const m_scopep;
|
||||
VerilatedVarNameMap::const_iterator m_it;
|
||||
|
@ -433,35 +468,54 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class VerilatedVpioMemoryWordIter final : public VerilatedVpio {
|
||||
const vpiHandle m_handle;
|
||||
const VerilatedVar* const m_varp;
|
||||
int32_t m_iteration;
|
||||
const int32_t m_direction;
|
||||
bool m_done = false;
|
||||
class VerilatedVpioRegIter final : public VerilatedVpio {
|
||||
VerilatedVpioVar* m_var;
|
||||
std::vector<VerilatedRange> m_ranges;
|
||||
std::vector<int> m_nextIndex;
|
||||
const int32_t m_maxDim;
|
||||
|
||||
public:
|
||||
VerilatedVpioMemoryWordIter(const vpiHandle handle, const VerilatedVar* varp)
|
||||
: m_handle{handle}
|
||||
, m_varp{varp}
|
||||
, m_iteration{varp->unpacked().right()}
|
||||
, m_direction{VL_LIKELY(varp->unpacked().left() > varp->unpacked().right()) ? 1 : -1} {}
|
||||
~VerilatedVpioMemoryWordIter() override = default;
|
||||
static VerilatedVpioMemoryWordIter* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioMemoryWordIter*>(reinterpret_cast<VerilatedVpio*>(h));
|
||||
explicit VerilatedVpioRegIter(const VerilatedVpioVar* vop)
|
||||
: m_var{new VerilatedVpioVar(vop)}
|
||||
, m_maxDim{vop->varp()->udims() - 1} {
|
||||
for (auto it = vop->indexedDim() + 1; it <= m_maxDim; it++)
|
||||
m_ranges.push_back(*vop->varp()->range(it));
|
||||
for (auto it : m_ranges)
|
||||
m_nextIndex.push_back(it.right());
|
||||
}
|
||||
~VerilatedVpioRegIter() override = default;
|
||||
static VerilatedVpioRegIter* castp(vpiHandle h) {
|
||||
return dynamic_cast<VerilatedVpioRegIter*>(reinterpret_cast<VerilatedVpio*>(h));
|
||||
}
|
||||
uint32_t type() const override { return vpiIterator; }
|
||||
void iterationInc() {
|
||||
if (!(m_done = (m_iteration == m_varp->unpacked().left()))) m_iteration += m_direction;
|
||||
}
|
||||
vpiHandle dovpi_scan() override {
|
||||
if (VL_UNLIKELY(m_done)) {
|
||||
delete this; // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle
|
||||
if (VL_UNLIKELY(m_var->indexedDim() >= m_maxDim)) {
|
||||
// Trying to iterate over a non-array object
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
const vpiHandle result = vpi_handle_by_index(m_handle, m_iteration);
|
||||
iterationInc();
|
||||
return result;
|
||||
if (m_nextIndex.front() > m_ranges.front().high() ||
|
||||
m_nextIndex.front() < m_ranges.front().low()) {
|
||||
// Finished iterating
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VerilatedVpioVar* ret = m_var;
|
||||
for (auto it : m_nextIndex)
|
||||
ret = ret->withIndex(it);
|
||||
|
||||
// Increase the index, pretending the dimensions are flattened
|
||||
for (int32_t it = m_ranges.size() - 1; it >= 0; it--) {
|
||||
m_nextIndex.at(it) += m_ranges.at(it).increment();
|
||||
if (m_nextIndex.at(it) <= m_ranges.at(it).high() &&
|
||||
m_nextIndex.at(it) >= m_ranges.at(it).low())
|
||||
break;
|
||||
else if (it > 0)
|
||||
m_nextIndex.at(it) = m_ranges.at(it).right();
|
||||
}
|
||||
|
||||
return ret->castVpiHandle();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -686,7 +740,7 @@ public:
|
|||
break;
|
||||
}
|
||||
case VLVT_WDATA: {
|
||||
words = VL_WORDS_I(vop->varp()->packed().elements());
|
||||
words = VL_WORDS_I(vop->varp()->entBits());
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
|
@ -2047,26 +2101,17 @@ vpiHandle vpi_handle_by_index(vpiHandle object, PLI_INT32 indx) {
|
|||
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_handle_by_index %p %d\n", object, indx););
|
||||
VerilatedVpiImp::assertOneCheck();
|
||||
VL_VPI_ERROR_RESET_();
|
||||
// Memory words are not indexable
|
||||
const VerilatedVpioMemoryWord* const vop = VerilatedVpioMemoryWord::castp(object);
|
||||
if (VL_UNLIKELY(vop)) return nullptr;
|
||||
const VerilatedVpioVar* const varop = VerilatedVpioVar::castp(object);
|
||||
if (VL_LIKELY(varop)) {
|
||||
if (varop->varp()->dims() < 2) return nullptr;
|
||||
if (VL_LIKELY(varop->varp()->unpacked().left() >= varop->varp()->unpacked().right())) {
|
||||
if (VL_UNLIKELY(indx > varop->varp()->unpacked().left()
|
||||
|| indx < varop->varp()->unpacked().right()))
|
||||
return nullptr;
|
||||
return (new VerilatedVpioMemoryWord{varop->varp(), varop->scopep(), indx,
|
||||
indx - varop->varp()->unpacked().right()})
|
||||
->castVpiHandle();
|
||||
}
|
||||
if (VL_UNLIKELY(indx < varop->varp()->unpacked().left()
|
||||
|| indx > varop->varp()->unpacked().right()))
|
||||
// Case: no dimensions left to index
|
||||
if (VL_UNLIKELY(varop->indexedDim() + 1 > varop->varp()->dims() - 1))
|
||||
return nullptr;
|
||||
return (new VerilatedVpioMemoryWord{varop->varp(), varop->scopep(), indx,
|
||||
indx - varop->varp()->unpacked().left()})
|
||||
->castVpiHandle();
|
||||
|
||||
// Case: index out of range
|
||||
if (VL_UNLIKELY(indx < varop->rangep()->low() || indx > varop->rangep()->high()))
|
||||
return nullptr;
|
||||
|
||||
return varop->withIndex(indx)->castVpiHandle();
|
||||
}
|
||||
VL_VPI_INTERNAL_(__FILE__, __LINE__, "%s : can't resolve handle", __func__);
|
||||
return nullptr;
|
||||
|
@ -2108,7 +2153,7 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
|
|||
case vpiIndex: {
|
||||
const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return nullptr;
|
||||
const int32_t val = vop->index();
|
||||
const int32_t val = vop->index().back();
|
||||
return (new VerilatedVpioConst{val})->castVpiHandle();
|
||||
}
|
||||
case vpiScope: {
|
||||
|
@ -2117,7 +2162,7 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle object) {
|
|||
return (new VerilatedVpioScope{vop->scopep()})->castVpiHandle();
|
||||
}
|
||||
case vpiParent: {
|
||||
const VerilatedVpioMemoryWord* const vop = VerilatedVpioMemoryWord::castp(object);
|
||||
const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return nullptr;
|
||||
return (new VerilatedVpioVar{vop->varp(), vop->scopep()})->castVpiHandle();
|
||||
}
|
||||
|
@ -2139,35 +2184,26 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle object) {
|
|||
VerilatedVpiImp::assertOneCheck();
|
||||
VL_VPI_ERROR_RESET_();
|
||||
switch (type) {
|
||||
case vpiMemoryWord: {
|
||||
const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return nullptr;
|
||||
if (vop->varp()->dims() < 2) return nullptr;
|
||||
if (vop->varp()->dims() > 2) {
|
||||
VL_VPI_WARNING_(__FILE__, __LINE__,
|
||||
"%s: %s, object %s has unsupported number of indices (%d)", __func__,
|
||||
VerilatedVpiError::strFromVpiMethod(type), vop->fullname(),
|
||||
vop->varp()->dims());
|
||||
}
|
||||
return (new VerilatedVpioMemoryWordIter{object, vop->varp()})->castVpiHandle();
|
||||
}
|
||||
case vpiRange: {
|
||||
const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return nullptr;
|
||||
if (vop->varp()->dims() < 2) return nullptr;
|
||||
// Unsupported is multidim list
|
||||
if (vop->varp()->dims() > 2) {
|
||||
VL_VPI_WARNING_(__FILE__, __LINE__,
|
||||
"%s: %s, object %s has unsupported number of indices (%d)", __func__,
|
||||
VerilatedVpiError::strFromVpiMethod(type), vop->fullname(),
|
||||
vop->varp()->dims());
|
||||
}
|
||||
return ((new VerilatedVpioRangeIter{vop->rangep()})->castVpiHandle());
|
||||
|
||||
std::vector<VerilatedRange> ranges;
|
||||
const int maxDim = vop->maxDim(vop->isIndexedDimUnpacked());
|
||||
for (int dim = vop->indexedDim() + 1; dim <= maxDim; dim++)
|
||||
ranges.emplace_back(*vop->varp()->range(dim));
|
||||
|
||||
// allow one more range layer (regbit)
|
||||
if (ranges.empty())
|
||||
ranges.emplace_back(VerilatedRange(0, 0));
|
||||
return ((new VerilatedVpioRangeIter{ranges})->castVpiHandle());
|
||||
}
|
||||
case vpiReg: {
|
||||
const VerilatedVpioScope* const vop = VerilatedVpioScope::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return nullptr;
|
||||
return ((new VerilatedVpioVarIter{vop})->castVpiHandle());
|
||||
const VerilatedVpioScope* const vscopep = VerilatedVpioScope::castp(object);
|
||||
if (vscopep) return ((new VerilatedVpioVarIter{vscopep, false})->castVpiHandle());
|
||||
const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object);
|
||||
if (vop) return ((new VerilatedVpioRegIter{vop})->castVpiHandle());
|
||||
return nullptr;
|
||||
}
|
||||
case vpiParameter: {
|
||||
const VerilatedVpioScope* const vop = VerilatedVpioScope::castp(object);
|
||||
|
@ -2249,7 +2285,7 @@ PLI_INT32 vpi_get(PLI_INT32 property, vpiHandle object) {
|
|||
case vpiVector: {
|
||||
const VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object);
|
||||
if (VL_UNLIKELY(!vop)) return vpiUndefined;
|
||||
return (property == vpiVector) ^ (vop->varp()->dims() == 0);
|
||||
return (property == vpiVector) ^ (vop->varp()->packedRanges().empty() || !vop->rangep());
|
||||
}
|
||||
case vpiSize: {
|
||||
const VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object);
|
||||
|
@ -2347,7 +2383,9 @@ bool vl_check_format(const VerilatedVar* varp, const p_vpi_value valuep, const c
|
|||
switch (varp->vltype()) {
|
||||
case VLVT_UINT8:
|
||||
case VLVT_UINT16:
|
||||
case VLVT_UINT32: return status;
|
||||
case VLVT_UINT32:
|
||||
case VLVT_UINT64:
|
||||
case VLVT_WDATA: return status;
|
||||
default: status = false;
|
||||
}
|
||||
} else if (valuep->format == vpiRealVal) {
|
||||
|
@ -2384,11 +2422,136 @@ static void vl_strprintf(std::string& buffer, char const* fmt, ...) {
|
|||
va_end(args);
|
||||
}
|
||||
|
||||
void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
||||
const char* fullname) {
|
||||
// Information about how to access packed array data.
|
||||
// If underlying type is multi-word (VLVT_WDATA), the packed element might straddle word boundaries,
|
||||
// in which case m_maskHi != 0.
|
||||
template<typename T>
|
||||
struct VarAccessInfo final {
|
||||
T* m_datap; // Typed pointer to packed array base address
|
||||
size_t m_bitOffset; // Data start location (bit offset)
|
||||
size_t m_wordOffset; // Data start location (word offset, VLVT_WDATA only)
|
||||
T m_maskLo; // Access mask for m_datap[m_wordOffset]
|
||||
T m_maskHi; // Access mask for m_datap[m_wordOffset + 1] (VLVT_WDATA only)
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
VarAccessInfo<T> vl_vpi_var_access_info(const VerilatedVpioVarBase* vop, size_t bitCount, size_t addOffset) {
|
||||
// VarAccessInfo generation
|
||||
// vop - variable to access (already indexed)
|
||||
// bitCount - how many bits to write/read
|
||||
// addOffset - additional offset to apply (within the packed array element)
|
||||
|
||||
const size_t wordBits = sizeof(T) * 8;
|
||||
uint32_t varBits = vop->bitSize();
|
||||
|
||||
if (vop->varp()->vltype() == VLVT_REAL)
|
||||
varBits *= sizeof(double) * 8;
|
||||
|
||||
// make sure we're not trying to write outside var bounds
|
||||
assert(varBits > addOffset);
|
||||
bitCount = std::min(bitCount, varBits - addOffset);
|
||||
|
||||
VarAccessInfo<T> info;
|
||||
info.m_datap = reinterpret_cast<T*>(vop->varDatap());
|
||||
if (vop->varp()->vltype() == VLVT_WDATA) {
|
||||
assert(sizeof(T) == sizeof(EData));
|
||||
assert(bitCount <= wordBits);
|
||||
info.m_wordOffset = (vop->bitOffset() + addOffset) / wordBits;
|
||||
info.m_bitOffset = (vop->bitOffset() + addOffset) % wordBits;
|
||||
if (bitCount + info.m_bitOffset <= wordBits) {
|
||||
// within single word
|
||||
if (bitCount == wordBits)
|
||||
info.m_maskLo = ~static_cast<T>(0);
|
||||
else
|
||||
info.m_maskLo = (static_cast<T>(1) << bitCount) - 1;
|
||||
info.m_maskLo = info.m_maskLo << info.m_bitOffset;
|
||||
info.m_maskHi = 0;
|
||||
} else {
|
||||
// straddles word boundary
|
||||
info.m_maskLo = (static_cast<T>(1) << (wordBits - info.m_bitOffset)) - 1;
|
||||
info.m_maskLo = info.m_maskLo << info.m_bitOffset;
|
||||
info.m_maskHi = (static_cast<T>(1) << (bitCount + info.m_bitOffset - wordBits)) - 1;
|
||||
}
|
||||
} else {
|
||||
info.m_wordOffset = 0;
|
||||
info.m_bitOffset = vop->bitOffset() + addOffset;
|
||||
assert(bitCount + info.m_bitOffset <= wordBits);
|
||||
if (bitCount < wordBits) {
|
||||
info.m_maskLo = (static_cast<T>(1) << bitCount) - 1;
|
||||
info.m_maskLo = info.m_maskLo << info.m_bitOffset;
|
||||
} else {
|
||||
info.m_maskLo = ~static_cast<T>(0);
|
||||
}
|
||||
info.m_maskHi = 0;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T vl_vpi_get_word_gen(const VerilatedVpioVarBase* vop, size_t bitCount, size_t addOffset) {
|
||||
const size_t wordBits = sizeof(T) * 8;
|
||||
const VarAccessInfo<T> info = vl_vpi_var_access_info<T>(vop, bitCount, addOffset);
|
||||
if (info.m_maskHi)
|
||||
return ((info.m_datap[info.m_wordOffset] & info.m_maskLo) >> info.m_bitOffset) |
|
||||
((info.m_datap[info.m_wordOffset + 1] & info.m_maskHi) << (wordBits - info.m_bitOffset));
|
||||
else
|
||||
return (info.m_datap[info.m_wordOffset] & info.m_maskLo) >> info.m_bitOffset;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void vl_vpi_put_word_gen(const VerilatedVpioVar* vop, T word, size_t bitCount, size_t addOffset) {
|
||||
const size_t wordBits = sizeof(T) * 8;
|
||||
const VarAccessInfo<T> info = vl_vpi_var_access_info<T>(vop, bitCount, addOffset);
|
||||
|
||||
if (info.m_maskHi) {
|
||||
info.m_datap[info.m_wordOffset + 1] = (info.m_datap[info.m_wordOffset+1] & ~info.m_maskHi) |
|
||||
((word >> (wordBits - info.m_bitOffset)) & info.m_maskHi);
|
||||
}
|
||||
info.m_datap[info.m_wordOffset] = (info.m_datap[info.m_wordOffset] & ~info.m_maskLo) |
|
||||
((word << info.m_bitOffset) & info.m_maskLo);
|
||||
}
|
||||
|
||||
// bitCount: maximum number of bits to read, will stop earlier if it reaches the var bounds
|
||||
// addOffset: additional read bitoffset
|
||||
QData vl_vpi_get_word(const VerilatedVpioVarBase* vop, size_t bitCount, size_t addOffset) {
|
||||
switch (vop->varp()->vltype()) {
|
||||
case VLVT_UINT8: return vl_vpi_get_word_gen<CData>(vop, bitCount, addOffset);
|
||||
case VLVT_UINT16: return vl_vpi_get_word_gen<SData>(vop, bitCount, addOffset);
|
||||
case VLVT_UINT32: return vl_vpi_get_word_gen<IData>(vop, bitCount, addOffset);
|
||||
case VLVT_UINT64: return vl_vpi_get_word_gen<QData>(vop, bitCount, addOffset);
|
||||
case VLVT_WDATA: return vl_vpi_get_word_gen<EData>(vop, bitCount, addOffset);
|
||||
default:
|
||||
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported vltype (%d)", __func__, vop->varp()->vltype());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// word: data to be written
|
||||
// bitCount: maximum number of bits to write, will stop earlier if it reaches the var bounds
|
||||
// addOffset: additional write bitoffset
|
||||
void vl_vpi_put_word(const VerilatedVpioVar* vop, QData word, size_t bitCount, size_t addOffset) {
|
||||
switch (vop->varp()->vltype()) {
|
||||
case VLVT_UINT8: vl_vpi_put_word_gen<CData>(vop, word, bitCount, addOffset); break;
|
||||
case VLVT_UINT16: vl_vpi_put_word_gen<SData>(vop, word, bitCount, addOffset); break;
|
||||
case VLVT_UINT32: vl_vpi_put_word_gen<IData>(vop, word, bitCount, addOffset); break;
|
||||
case VLVT_UINT64: vl_vpi_put_word_gen<QData>(vop, word, bitCount, addOffset); break;
|
||||
case VLVT_WDATA: vl_vpi_put_word_gen<EData>(vop, word, bitCount, addOffset); break;
|
||||
default:
|
||||
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported vltype (%d)", __func__, vop->varp()->vltype());
|
||||
}
|
||||
}
|
||||
|
||||
void vl_vpi_get_value(const VerilatedVpioVarBase* vop, p_vpi_value valuep) {
|
||||
const VerilatedVar* varp = vop->varp();
|
||||
void* varDatap = vop->varDatap();
|
||||
const char* fullname = vop->fullname();
|
||||
|
||||
if (!vl_check_format(varp, valuep, fullname, true)) return;
|
||||
// string data type is dynamic and may vary in size during simulation
|
||||
static thread_local std::string t_outDynamicStr;
|
||||
|
||||
const int varBits = vop->bitSize();
|
||||
|
||||
// We used to presume vpiValue.format = vpiIntVal or if single bit vpiScalarVal
|
||||
// This may cause backward compatibility issues with older code.
|
||||
if (valuep->format == vpiVectorVal) {
|
||||
|
@ -2396,27 +2559,8 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
|||
// It only needs to persist until the next vpi_get_value
|
||||
static thread_local t_vpi_vecval t_out[VL_VALUE_STRING_MAX_WORDS * 2];
|
||||
valuep->value.vector = t_out;
|
||||
if (varp->vltype() == VLVT_UINT8) {
|
||||
t_out[0].aval = *(reinterpret_cast<CData*>(varDatap));
|
||||
t_out[0].bval = 0;
|
||||
return;
|
||||
} else if (varp->vltype() == VLVT_UINT16) {
|
||||
t_out[0].aval = *(reinterpret_cast<SData*>(varDatap));
|
||||
t_out[0].bval = 0;
|
||||
return;
|
||||
} else if (varp->vltype() == VLVT_UINT32) {
|
||||
t_out[0].aval = *(reinterpret_cast<IData*>(varDatap));
|
||||
t_out[0].bval = 0;
|
||||
return;
|
||||
} else if (varp->vltype() == VLVT_UINT64) {
|
||||
const QData data = *(reinterpret_cast<QData*>(varDatap));
|
||||
t_out[1].aval = static_cast<IData>(data >> 32ULL);
|
||||
t_out[1].bval = 0;
|
||||
t_out[0].aval = static_cast<IData>(data);
|
||||
t_out[0].bval = 0;
|
||||
return;
|
||||
} else if (varp->vltype() == VLVT_WDATA) {
|
||||
const int words = VL_WORDS_I(varp->packed().elements());
|
||||
if (varp->vltype() == VLVT_WDATA) {
|
||||
const int words = VL_WORDS_I(varBits);
|
||||
if (VL_UNCOVERABLE(words >= VL_VALUE_STRING_MAX_WORDS)) {
|
||||
VL_VPI_ERROR_(
|
||||
__FILE__, __LINE__,
|
||||
|
@ -2424,82 +2568,63 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
|||
"recompile");
|
||||
return;
|
||||
}
|
||||
const WDataInP datap = (reinterpret_cast<EData*>(varDatap));
|
||||
for (int i = 0; i < words; ++i) {
|
||||
t_out[i].aval = datap[i];
|
||||
t_out[i].aval = vl_vpi_get_word(vop, 32, i * 32);
|
||||
t_out[i].bval = 0;
|
||||
}
|
||||
return;
|
||||
} else if (varp->vltype() == VLVT_UINT64 && varBits > 32) {
|
||||
const QData data = vl_vpi_get_word(vop, 64, 0);
|
||||
t_out[1].aval = static_cast<IData>(data >> 32ULL);
|
||||
t_out[1].bval = 0;
|
||||
t_out[0].aval = static_cast<IData>(data);
|
||||
t_out[0].bval = 0;
|
||||
return;
|
||||
} else {
|
||||
t_out[0].aval = vl_vpi_get_word(vop, 32, 0);
|
||||
t_out[0].bval = 0;
|
||||
return;
|
||||
}
|
||||
} else if (valuep->format == vpiBinStrVal) {
|
||||
int bits = varp->packed().elements();
|
||||
t_outDynamicStr.resize(bits);
|
||||
t_outDynamicStr.resize(varBits);
|
||||
const CData* datap = (reinterpret_cast<CData*>(varDatap));
|
||||
for (size_t i = 0; i < bits; ++i) {
|
||||
const char val = (datap[i >> 3] >> (i & 7)) & 1;
|
||||
t_outDynamicStr[bits - i - 1] = val ? '1' : '0';
|
||||
for (size_t i = 0; i < varBits; ++i) {
|
||||
const size_t pos = i + vop->bitOffset();
|
||||
const char val = (datap[pos >> 3] >> (pos & 7)) & 1;
|
||||
t_outDynamicStr[varBits - i - 1] = val ? '1' : '0';
|
||||
}
|
||||
valuep->value.str = const_cast<PLI_BYTE8*>(t_outDynamicStr.c_str());
|
||||
return;
|
||||
} else if (valuep->format == vpiOctStrVal) {
|
||||
int chars = (varp->packed().elements() + 2) / 3;
|
||||
const int chars = (varBits + 2) / 3;
|
||||
t_outDynamicStr.resize(chars);
|
||||
const int bytes = VL_BYTES_I(varp->packed().elements());
|
||||
const CData* datap = (reinterpret_cast<CData*>(varDatap));
|
||||
for (size_t i = 0; i < chars; ++i) {
|
||||
const div_t idx = div(i * 3, 8);
|
||||
int val = datap[idx.quot];
|
||||
if ((idx.quot + 1) < bytes) {
|
||||
// if the next byte is valid or that in
|
||||
// for when the required 3 bits straddle adjacent bytes
|
||||
val |= datap[idx.quot + 1] << 8;
|
||||
}
|
||||
// align so least significant 3 bits represent octal char
|
||||
val >>= idx.rem;
|
||||
if (i == (chars - 1)) {
|
||||
// most significant char, mask off nonexistent bits when vector
|
||||
// size is not a multiple of 3
|
||||
const unsigned int rem = varp->packed().elements() % 3;
|
||||
if (rem) {
|
||||
// generate bit mask & zero nonexistent bits
|
||||
val &= (1 << rem) - 1;
|
||||
}
|
||||
}
|
||||
t_outDynamicStr[chars - i - 1] = '0' + (val & 7);
|
||||
const char val = vl_vpi_get_word(vop, 3, i * 3);
|
||||
t_outDynamicStr[chars - i - 1] = '0' + val;
|
||||
}
|
||||
valuep->value.str = const_cast<PLI_BYTE8*>(t_outDynamicStr.c_str());
|
||||
return;
|
||||
} else if (valuep->format == vpiDecStrVal) {
|
||||
if (varp->vltype() == VLVT_UINT8) {
|
||||
vl_strprintf(t_outDynamicStr, "%hhu",
|
||||
static_cast<unsigned char>(*(reinterpret_cast<CData*>(varDatap))));
|
||||
static_cast<unsigned char>(vl_vpi_get_word(vop, 8, 0)));
|
||||
} else if (varp->vltype() == VLVT_UINT16) {
|
||||
vl_strprintf(t_outDynamicStr, "%hu",
|
||||
static_cast<unsigned short>(*(reinterpret_cast<SData*>(varDatap))));
|
||||
static_cast<unsigned short>(vl_vpi_get_word(vop, 16, 0)));
|
||||
} else if (varp->vltype() == VLVT_UINT32) {
|
||||
vl_strprintf(t_outDynamicStr, "%u",
|
||||
static_cast<unsigned int>(*(reinterpret_cast<IData*>(varDatap))));
|
||||
static_cast<unsigned int>(vl_vpi_get_word(vop, 32, 0)));
|
||||
} else if (varp->vltype() == VLVT_UINT64) {
|
||||
vl_strprintf(t_outDynamicStr, "%llu", // lintok-format-ll
|
||||
static_cast<unsigned long long>(*(reinterpret_cast<QData*>(varDatap))));
|
||||
static_cast<unsigned long long>(vl_vpi_get_word(vop, 64, 0)));
|
||||
}
|
||||
valuep->value.str = const_cast<PLI_BYTE8*>(t_outDynamicStr.c_str());
|
||||
return;
|
||||
} else if (valuep->format == vpiHexStrVal) {
|
||||
int chars = (varp->packed().elements() + 3) >> 2;
|
||||
const int chars = (varBits + 3) >> 2;
|
||||
t_outDynamicStr.resize(chars);
|
||||
const CData* datap = (reinterpret_cast<CData*>(varDatap));
|
||||
for (size_t i = 0; i < chars; ++i) {
|
||||
char val = (datap[i >> 1] >> ((i & 1) << 2)) & 15;
|
||||
if (i == (chars - 1)) {
|
||||
// most significant char, mask off nonexistent bits when vector
|
||||
// size is not a multiple of 4
|
||||
const unsigned int rem = varp->packed().elements() & 3;
|
||||
if (rem) {
|
||||
// generate bit mask & zero nonexistent bits
|
||||
val &= (1 << rem) - 1;
|
||||
}
|
||||
}
|
||||
const char val = vl_vpi_get_word(vop, 4, i * 4);
|
||||
t_outDynamicStr[chars - i - 1] = "0123456789abcdef"[static_cast<int>(val)];
|
||||
}
|
||||
valuep->value.str = const_cast<PLI_BYTE8*>(t_outDynamicStr.c_str());
|
||||
|
@ -2515,28 +2640,19 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
|||
return;
|
||||
}
|
||||
} else {
|
||||
int bytes = VL_BYTES_I(varp->packed().elements());
|
||||
t_outDynamicStr.resize(bytes);
|
||||
const CData* datap = (reinterpret_cast<CData*>(varDatap));
|
||||
for (size_t i = 0; i < bytes; ++i) {
|
||||
const char val = datap[bytes - i - 1];
|
||||
const int chars = VL_BYTES_I(varBits);
|
||||
t_outDynamicStr.resize(chars);
|
||||
for (size_t i = 0; i < chars; ++i) {
|
||||
const char val = vl_vpi_get_word(vop, 8, i * 8);
|
||||
// other simulators replace [leading?] zero chars with spaces, replicate here.
|
||||
t_outDynamicStr[i] = val ? val : ' ';
|
||||
t_outDynamicStr[chars - i - 1] = val ? val : ' ';
|
||||
}
|
||||
valuep->value.str = const_cast<PLI_BYTE8*>(t_outDynamicStr.c_str());
|
||||
return;
|
||||
}
|
||||
} else if (valuep->format == vpiIntVal) {
|
||||
if (varp->vltype() == VLVT_UINT8) {
|
||||
valuep->value.integer = *(reinterpret_cast<CData*>(varDatap));
|
||||
return;
|
||||
} else if (varp->vltype() == VLVT_UINT16) {
|
||||
valuep->value.integer = *(reinterpret_cast<SData*>(varDatap));
|
||||
return;
|
||||
} else if (varp->vltype() == VLVT_UINT32) {
|
||||
valuep->value.integer = *(reinterpret_cast<IData*>(varDatap));
|
||||
return;
|
||||
}
|
||||
valuep->value.integer = vl_vpi_get_word(vop, 32, 0);
|
||||
return;
|
||||
} else if (valuep->format == vpiRealVal) {
|
||||
valuep->value.real = *(reinterpret_cast<double*>(varDatap));
|
||||
return;
|
||||
|
@ -2554,10 +2670,10 @@ void vpi_get_value(vpiHandle object, p_vpi_value valuep) {
|
|||
if (VL_UNLIKELY(!valuep)) return;
|
||||
|
||||
if (const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object)) {
|
||||
vl_get_value(vop->varp(), vop->varDatap(), valuep, vop->fullname());
|
||||
vl_vpi_get_value(vop, valuep);
|
||||
return;
|
||||
} else if (const VerilatedVpioParam* const vop = VerilatedVpioParam::castp(object)) {
|
||||
vl_get_value(vop->varp(), vop->varDatap(), valuep, vop->fullname());
|
||||
vl_vpi_get_value(vop, valuep);
|
||||
return;
|
||||
} else if (const VerilatedVpioConst* const vop = VerilatedVpioConst::castp(object)) {
|
||||
if (valuep->format == vpiIntVal) {
|
||||
|
@ -2580,7 +2696,7 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
|
|||
VL_VPI_WARNING_(__FILE__, __LINE__, "Ignoring vpi_put_value with nullptr value pointer");
|
||||
return nullptr;
|
||||
}
|
||||
PLI_INT32 delay_mode = flags & 0xfff;
|
||||
const PLI_INT32 delay_mode = flags & 0xfff;
|
||||
if (const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object)) {
|
||||
VL_DEBUG_IF_PLI(
|
||||
VL_DBG_MSGF("- vpi: vpi_put_value name=%s fmt=%d vali=%d\n", vop->fullname(),
|
||||
|
@ -2607,97 +2723,51 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
|
|||
return object;
|
||||
}
|
||||
VerilatedVpiImp::evalNeeded(true);
|
||||
const int varBits = vop->bitSize();
|
||||
if (valuep->format == vpiVectorVal) {
|
||||
if (VL_UNLIKELY(!valuep->value.vector)) return nullptr;
|
||||
if (vop->varp()->vltype() == VLVT_UINT8) {
|
||||
*(reinterpret_cast<CData*>(vop->varDatap()))
|
||||
= valuep->value.vector[0].aval & vop->mask();
|
||||
if (vop->varp()->vltype() == VLVT_WDATA) {
|
||||
const int words = VL_WORDS_I(varBits);
|
||||
for (int i = 0; i < words; ++i)
|
||||
vl_vpi_put_word(vop, valuep->value.vector[i].aval, 32, i * 32);
|
||||
return object;
|
||||
} else if (vop->varp()->vltype() == VLVT_UINT16) {
|
||||
*(reinterpret_cast<SData*>(vop->varDatap()))
|
||||
= valuep->value.vector[0].aval & vop->mask();
|
||||
} else if (vop->varp()->vltype() == VLVT_UINT64 && varBits > 32) {
|
||||
const QData val = (static_cast<QData>(valuep->value.vector[1].aval) << 32) |
|
||||
static_cast<QData>(valuep->value.vector[0].aval);
|
||||
vl_vpi_put_word(vop, val, 64, 0);
|
||||
return object;
|
||||
} else if (vop->varp()->vltype() == VLVT_UINT32) {
|
||||
*(reinterpret_cast<IData*>(vop->varDatap()))
|
||||
= valuep->value.vector[0].aval & vop->mask();
|
||||
return object;
|
||||
} else if (vop->varp()->vltype() == VLVT_UINT64) {
|
||||
*(reinterpret_cast<QData*>(vop->varDatap())) = VL_SET_QII(
|
||||
valuep->value.vector[1].aval & vop->mask(), valuep->value.vector[0].aval);
|
||||
return object;
|
||||
} else if (vop->varp()->vltype() == VLVT_WDATA) {
|
||||
const int words = VL_WORDS_I(vop->varp()->packed().elements());
|
||||
WDataOutP datap = (reinterpret_cast<EData*>(vop->varDatap()));
|
||||
for (int i = 0; i < words; ++i) {
|
||||
datap[i] = valuep->value.vector[i].aval;
|
||||
if (i == (words - 1)) datap[i] &= vop->mask();
|
||||
}
|
||||
} else {
|
||||
vl_vpi_put_word(vop, valuep->value.vector[0].aval, 32, 0);
|
||||
return object;
|
||||
}
|
||||
} else if (valuep->format == vpiBinStrVal) {
|
||||
const int bits = vop->varp()->packed().elements();
|
||||
const int len = std::strlen(valuep->value.str);
|
||||
CData* const datap = (reinterpret_cast<CData*>(vop->varDatap()));
|
||||
for (int i = 0; i < bits; ++i) {
|
||||
const char set = (i < len) ? (valuep->value.str[len - i - 1] == '1') : 0;
|
||||
// zero bits 7:1 of byte when assigning to bit 0, else
|
||||
// or in 1 if bit set
|
||||
if (i & 7) {
|
||||
datap[i >> 3] |= set << (i & 7);
|
||||
} else {
|
||||
datap[i >> 3] = set;
|
||||
}
|
||||
for (int i = 0; i < varBits; ++i) {
|
||||
const bool set = (i < len) && (valuep->value.str[len - i - 1] == '1');
|
||||
const size_t pos = vop->bitOffset() + i;
|
||||
|
||||
if (set)
|
||||
datap[pos >> 3] |= 1 << (pos & 7);
|
||||
else
|
||||
datap[pos >> 3] &= ~(1 << (pos & 7));
|
||||
}
|
||||
return object;
|
||||
} else if (valuep->format == vpiOctStrVal) {
|
||||
const int chars = (vop->varp()->packed().elements() + 2) / 3;
|
||||
const int bytes = VL_BYTES_I(vop->varp()->packed().elements());
|
||||
const int chars = (varBits + 2) / 3;
|
||||
const int len = std::strlen(valuep->value.str);
|
||||
CData* const datap = (reinterpret_cast<CData*>(vop->varDatap()));
|
||||
div_t idx;
|
||||
datap[0] = 0; // reset zero'th byte
|
||||
for (int i = 0; i < chars; ++i) {
|
||||
union {
|
||||
char byte[2];
|
||||
uint16_t half;
|
||||
} val;
|
||||
idx = div(i * 3, 8);
|
||||
if (i < len) {
|
||||
// ignore illegal chars
|
||||
const char digit = valuep->value.str[len - i - 1];
|
||||
if (digit >= '0' && digit <= '7') {
|
||||
val.half = digit - '0';
|
||||
} else {
|
||||
VL_VPI_WARNING_(__FILE__, __LINE__,
|
||||
"%s: Non octal character '%c' in '%s' as value %s for %s",
|
||||
__func__, digit, valuep->value.str,
|
||||
VerilatedVpiError::strFromVpiVal(valuep->format),
|
||||
vop->fullname());
|
||||
val.half = 0;
|
||||
}
|
||||
} else {
|
||||
val.half = 0;
|
||||
}
|
||||
// align octal character to position within vector, note that
|
||||
// the three bits may straddle a byte boundary so two byte wide
|
||||
// assignments are made to adjacent bytes - but not if the least
|
||||
// significant byte of the aligned value is the most significant
|
||||
// byte of the destination.
|
||||
val.half <<= idx.rem;
|
||||
datap[idx.quot] |= val.byte[0]; // or in value
|
||||
if ((idx.quot + 1) < bytes) {
|
||||
datap[idx.quot + 1] = val.byte[1]; // this also resets
|
||||
// all bits to 0 prior to or'ing above
|
||||
for (int i = 0; i < len; ++i) {
|
||||
char digit = valuep->value.str[len - i - 1] - '0';
|
||||
if (digit < 0 || digit > 7) {
|
||||
VL_VPI_WARNING_(__FILE__, __LINE__,
|
||||
"%s: Non octal character '%c' in '%s' as value %s for %s",
|
||||
__func__, digit + '0', valuep->value.str,
|
||||
VerilatedVpiError::strFromVpiVal(valuep->format),
|
||||
vop->fullname());
|
||||
digit = 0;
|
||||
}
|
||||
vl_vpi_put_word(vop, digit, 3, i * 3);
|
||||
}
|
||||
// mask off non-existent bits in the most significant byte
|
||||
if (idx.quot == (bytes - 1)) {
|
||||
datap[idx.quot] &= vop->mask_byte(idx.quot);
|
||||
} else if (idx.quot + 1 == (bytes - 1)) {
|
||||
datap[idx.quot + 1] &= vop->mask_byte(idx.quot + 1);
|
||||
}
|
||||
// zero off remaining top bytes
|
||||
for (int i = idx.quot + 2; i < bytes; ++i) datap[i] = 0;
|
||||
return object;
|
||||
} else if (valuep->format == vpiDecStrVal) {
|
||||
char remainder[16];
|
||||
|
@ -2716,23 +2786,10 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
|
|||
remainder, valuep->value.str,
|
||||
VerilatedVpiError::strFromVpiVal(valuep->format), vop->fullname());
|
||||
}
|
||||
if (vop->varp()->vltype() == VLVT_UINT8) {
|
||||
*(reinterpret_cast<CData*>(vop->varDatap())) = val & vop->mask();
|
||||
return object;
|
||||
} else if (vop->varp()->vltype() == VLVT_UINT16) {
|
||||
*(reinterpret_cast<SData*>(vop->varDatap())) = val & vop->mask();
|
||||
return object;
|
||||
} else if (vop->varp()->vltype() == VLVT_UINT32) {
|
||||
*(reinterpret_cast<IData*>(vop->varDatap())) = val & vop->mask();
|
||||
return object;
|
||||
} else if (vop->varp()->vltype() == VLVT_UINT64) {
|
||||
*(reinterpret_cast<QData*>(vop->varDatap())) = val;
|
||||
(reinterpret_cast<IData*>(vop->varDatap()))[1] &= vop->mask();
|
||||
return object;
|
||||
}
|
||||
vl_vpi_put_word(vop, val, 64, 0);
|
||||
return object;
|
||||
} else if (valuep->format == vpiHexStrVal) {
|
||||
const int chars = (vop->varp()->packed().elements() + 3) >> 2;
|
||||
CData* const datap = (reinterpret_cast<CData*>(vop->varDatap()));
|
||||
const int chars = (varBits + 3) >> 2;
|
||||
const char* val = valuep->value.str;
|
||||
// skip hex ident if one is detected at the start of the string
|
||||
if (val[0] == '0' && (val[1] == 'x' || val[1] == 'X')) val += 2;
|
||||
|
@ -2760,41 +2817,26 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
|
|||
hex = 0;
|
||||
}
|
||||
// assign hex digit value to destination
|
||||
if (i & 1) {
|
||||
datap[i >> 1] |= hex << 4;
|
||||
} else {
|
||||
datap[i >> 1] = hex; // this also resets all
|
||||
// bits to 0 prior to or'ing above of the msb
|
||||
}
|
||||
vl_vpi_put_word(vop, hex, 4, i * 4);
|
||||
}
|
||||
// apply bit mask to most significant byte
|
||||
datap[(chars - 1) >> 1] &= vop->mask_byte((chars - 1) >> 1);
|
||||
return object;
|
||||
} else if (valuep->format == vpiStringVal) {
|
||||
if (vop->varp()->vltype() == VLVT_STRING) {
|
||||
*(reinterpret_cast<std::string*>(vop->varDatap())) = valuep->value.str;
|
||||
return object;
|
||||
} else {
|
||||
const int bytes = VL_BYTES_I(vop->varp()->packed().elements());
|
||||
const int chars = VL_BYTES_I(varBits);
|
||||
const int len = std::strlen(valuep->value.str);
|
||||
CData* const datap = (reinterpret_cast<CData*>(vop->varDatap()));
|
||||
for (int i = 0; i < bytes; ++i) {
|
||||
for (int i = 0; i < chars; ++i) {
|
||||
// prepend with 0 values before placing string the least significant bytes
|
||||
datap[i] = (i < len) ? valuep->value.str[len - i - 1] : 0;
|
||||
const char c = (i < len) ? valuep->value.str[len - i - 1] : 0;
|
||||
vl_vpi_put_word(vop, c, 8, i * 8);
|
||||
}
|
||||
}
|
||||
return object;
|
||||
} else if (valuep->format == vpiIntVal) {
|
||||
if (vop->varp()->vltype() == VLVT_UINT8) {
|
||||
*(reinterpret_cast<CData*>(vop->varDatap())) = vop->mask() & valuep->value.integer;
|
||||
return object;
|
||||
} else if (vop->varp()->vltype() == VLVT_UINT16) {
|
||||
*(reinterpret_cast<SData*>(vop->varDatap())) = vop->mask() & valuep->value.integer;
|
||||
return object;
|
||||
} else if (vop->varp()->vltype() == VLVT_UINT32) {
|
||||
*(reinterpret_cast<IData*>(vop->varDatap())) = vop->mask() & valuep->value.integer;
|
||||
return object;
|
||||
}
|
||||
vl_vpi_put_word(vop, valuep->value.integer, 64, 0);
|
||||
return object;
|
||||
} else if (valuep->format == vpiRealVal) {
|
||||
if (vop->varp()->vltype() == VLVT_REAL) {
|
||||
*(reinterpret_cast<double*>(vop->varDatap())) = valuep->value.real;
|
||||
|
|
|
@ -570,15 +570,28 @@ string AstVar::vlEnumDir() const {
|
|||
string AstVar::vlPropDecl(const string& propName) const {
|
||||
string out;
|
||||
|
||||
std::vector<int> plims; // Packed dimension limits
|
||||
std::vector<int> ulims; // Unpacked dimension limits
|
||||
for (const AstNodeDType* dtp = dtypep(); dtp;) {
|
||||
dtp = dtp->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
||||
if (const AstNodeArrayDType* const adtypep = VN_CAST(dtp, NodeArrayDType)) {
|
||||
ulims.push_back(adtypep->declRange().left());
|
||||
ulims.push_back(adtypep->declRange().right());
|
||||
dtp = adtypep->subDTypep();
|
||||
} else {
|
||||
break; // AstBasicDType - nothing below
|
||||
|
||||
if (const AstBasicDType* const bdtypep = basicp()) {
|
||||
for (const AstNodeDType* dtp = dtypep(); dtp;) {
|
||||
dtp = dtp->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
||||
if (const AstNodeArrayDType* const adtypep = VN_CAST(dtp, NodeArrayDType)) {
|
||||
if (VN_IS(dtp, PackArrayDType)) {
|
||||
plims.push_back(adtypep->declRange().left());
|
||||
plims.push_back(adtypep->declRange().right());
|
||||
} else {
|
||||
ulims.push_back(adtypep->declRange().left());
|
||||
ulims.push_back(adtypep->declRange().right());
|
||||
}
|
||||
dtp = adtypep->subDTypep();
|
||||
} else {
|
||||
if (bdtypep->isRanged()) {
|
||||
plims.push_back(bdtypep->left());
|
||||
plims.push_back(bdtypep->right());
|
||||
}
|
||||
break; // AstBasicDType - nothing below
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -595,23 +608,37 @@ string AstVar::vlPropDecl(const string& propName) const {
|
|||
out += "};\n";
|
||||
}
|
||||
|
||||
if (!plims.empty()) {
|
||||
out += "static const int " + propName + "__plims[";
|
||||
out += cvtToStr(plims.size());
|
||||
out += "] = {";
|
||||
auto it = plims.cbegin();
|
||||
out += cvtToStr(*it);
|
||||
while (++it != plims.cend()) {
|
||||
out += ", ";
|
||||
out += cvtToStr(*it);
|
||||
}
|
||||
out += "};\n";
|
||||
}
|
||||
|
||||
out += "static const VerilatedVarProps ";
|
||||
out += propName;
|
||||
out += "(";
|
||||
out += vlEnumType(); // VLVT_UINT32 etc
|
||||
out += ", " + vlEnumDir(); // VLVD_IN etc
|
||||
if (const AstBasicDType* const bdtypep = basicp()) {
|
||||
out += ", VerilatedVarProps::Packed()";
|
||||
out += ", " + cvtToStr(bdtypep->left());
|
||||
out += ", " + cvtToStr(bdtypep->right());
|
||||
}
|
||||
|
||||
if (!ulims.empty()) {
|
||||
out += ", VerilatedVarProps::Unpacked()";
|
||||
out += ", VerilatedVarProps::Unpacked{}";
|
||||
out += ", " + cvtToStr(ulims.size() / 2);
|
||||
out += ", " + propName + "__ulims";
|
||||
}
|
||||
|
||||
if (!plims.empty()) {
|
||||
out += ", VerilatedVarProps::Packed{}";
|
||||
out += ", " + cvtToStr(plims.size() / 2);
|
||||
out += ", " + propName + "__plims";
|
||||
}
|
||||
|
||||
out += ");\n";
|
||||
return out;
|
||||
}
|
||||
|
|
|
@ -929,21 +929,11 @@ void EmitCSyms::emitSymImp() {
|
|||
checkSplit(true);
|
||||
AstScope* const scopep = it->second.m_scopep;
|
||||
AstVar* const varp = it->second.m_varp;
|
||||
//
|
||||
int pwidth = 1;
|
||||
int pdim = 0;
|
||||
int udim = 0;
|
||||
string bounds;
|
||||
if (AstBasicDType* const basicp = varp->basicp()) {
|
||||
// Range is always first, it's not in "C" order
|
||||
if (basicp->isRanged()) {
|
||||
bounds += " ,";
|
||||
bounds += cvtToStr(basicp->hi());
|
||||
bounds += ",";
|
||||
bounds += cvtToStr(basicp->lo());
|
||||
pdim++;
|
||||
pwidth *= basicp->elements();
|
||||
}
|
||||
for (AstNodeDType* dtypep = varp->dtypep(); dtypep;) {
|
||||
dtypep
|
||||
= dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
||||
|
@ -952,28 +942,25 @@ void EmitCSyms::emitSymImp() {
|
|||
bounds += cvtToStr(adtypep->left());
|
||||
bounds += ",";
|
||||
bounds += cvtToStr(adtypep->right());
|
||||
if (VN_IS(dtypep, PackArrayDType)) {
|
||||
if (VN_IS(dtypep, PackArrayDType))
|
||||
pdim++;
|
||||
pwidth *= adtypep->elementsConst();
|
||||
} else {
|
||||
else
|
||||
udim++;
|
||||
}
|
||||
dtypep = adtypep->subDTypep();
|
||||
} else {
|
||||
if (basicp->isRanged()) {
|
||||
bounds += " ,";
|
||||
bounds += cvtToStr(basicp->hi());
|
||||
bounds += ",";
|
||||
bounds += cvtToStr(basicp->lo());
|
||||
pdim++;
|
||||
}
|
||||
break; // AstBasicDType - nothing below, 1
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: actually expose packed arrays as vpiRegArray
|
||||
if (pdim > 1 && udim == 0) {
|
||||
bounds = ", ";
|
||||
bounds += cvtToStr(pwidth - 1);
|
||||
bounds += ",0";
|
||||
pdim = 1;
|
||||
}
|
||||
if (pdim > 1 || udim > 1) {
|
||||
puts("//UNSUP "); // VerilatedImp can't deal with >2d or packed arrays
|
||||
}
|
||||
|
||||
|
||||
putns(scopep, protect("__Vscope_" + it->second.m_scopeName));
|
||||
putns(varp, ".varInsert(__Vfinal,");
|
||||
putsQuoted(protect(it->second.m_varBasePretty));
|
||||
|
@ -1005,7 +992,9 @@ void EmitCSyms::emitSymImp() {
|
|||
puts(",");
|
||||
puts(varp->vlEnumDir()); // VLVD_IN etc
|
||||
puts(",");
|
||||
puts(cvtToStr(pdim + udim));
|
||||
puts(cvtToStr(udim));
|
||||
puts(",");
|
||||
puts(cvtToStr(pdim));
|
||||
puts(bounds);
|
||||
puts(");\n");
|
||||
++m_numStmts;
|
||||
|
|
|
@ -50,8 +50,8 @@ int main(int argc, char** argv) {
|
|||
|
||||
for (const auto& varname : *varNameMap) {
|
||||
const VerilatedVar* varp = &(varname.second);
|
||||
int varLeft = varp->packed().left();
|
||||
int varRight = varp->packed().right();
|
||||
int varLeft = varp->range(0)->left();
|
||||
int varRight = varp->range(0)->right();
|
||||
|
||||
#ifdef TEST_VERBOSE
|
||||
VL_PRINTF("\tVar = %s\n", varname.first);
|
||||
|
@ -125,7 +125,7 @@ int main(int argc, char** argv) {
|
|||
|
||||
for (const auto& varname : *varNameMap) {
|
||||
const VerilatedVar* varp = &(varname.second);
|
||||
int varLeft = varp->packed().left();
|
||||
int varLeft = varp->range(0)->left();
|
||||
int varBits = varLeft + 1;
|
||||
uint8_t* varData = reinterpret_cast<uint8_t*>(varp->datap());
|
||||
|
||||
|
|
|
@ -7,18 +7,18 @@ t (vpiModule) t
|
|||
count (vpiReg) t.count
|
||||
do_generate (vpiParameter) t.do_generate
|
||||
vpiConstType=vpiDecConst
|
||||
fourthreetwoone (vpiMemory) t.fourthreetwoone
|
||||
vpiMemoryWord:
|
||||
fourthreetwoone (vpiMemoryWord) t.fourthreetwoone[3]
|
||||
fourthreetwoone (vpiMemoryWord) t.fourthreetwoone[4]
|
||||
fourthreetwoone (vpiRegArray) t.fourthreetwoone
|
||||
vpiReg:
|
||||
fourthreetwoone (vpiReg) t.fourthreetwoone[3]
|
||||
fourthreetwoone (vpiReg) t.fourthreetwoone[4]
|
||||
half_count (vpiReg) t.half_count
|
||||
long_int (vpiParameter) t.long_int
|
||||
vpiConstType=vpiDecConst
|
||||
onebit (vpiReg) t.onebit
|
||||
quads (vpiMemory) t.quads
|
||||
vpiMemoryWord:
|
||||
quads (vpiMemoryWord) t.quads[3]
|
||||
quads (vpiMemoryWord) t.quads[2]
|
||||
quads (vpiRegArray) t.quads
|
||||
vpiReg:
|
||||
quads (vpiReg) t.quads[3]
|
||||
quads (vpiReg) t.quads[2]
|
||||
real1 (vpiRealVar) t.real1
|
||||
status (vpiReg) t.status
|
||||
str1 (vpiStringVar) t.str1
|
||||
|
|
|
@ -49,7 +49,7 @@ static int _mon_check_props(TestVpiHandle& handle, int size, int direction, int
|
|||
CHECK_RESULT(vpisize, size);
|
||||
|
||||
// icarus verilog does not support vpiScalar, vpiVector or vpi*Range
|
||||
if (TestSimulator::has_get_scalar()) {
|
||||
if (TestSimulator::has_get_scalar() && type != vpiParameter) {
|
||||
int vpiscalar = vpi_get(vpiScalar, handle);
|
||||
CHECK_RESULT((bool)vpiscalar, (bool)scalar);
|
||||
int vpivector = vpi_get(vpiVector, handle);
|
||||
|
@ -57,23 +57,29 @@ static int _mon_check_props(TestVpiHandle& handle, int size, int direction, int
|
|||
}
|
||||
|
||||
// Icarus only supports ranges on memories
|
||||
if (!scalar && !(TestSimulator::is_icarus() && type != vpiMemory)) {
|
||||
TestVpiHandle left_h, right_h;
|
||||
|
||||
if (!scalar && type != vpiIntVar && type != vpiParameter
|
||||
&& !(TestSimulator::is_icarus() && type != vpiMemory)) {
|
||||
// check coherency for vectors
|
||||
// get left hand side of range
|
||||
left_h = vpi_handle(vpiLeftRange, handle);
|
||||
CHECK_RESULT_NZ(left_h);
|
||||
vpi_get_value(left_h, &value);
|
||||
int coherency = value.value.integer;
|
||||
// get right hand side of range
|
||||
right_h = vpi_handle(vpiRightRange, handle);
|
||||
CHECK_RESULT_NZ(right_h);
|
||||
vpi_get_value(right_h, &value);
|
||||
TEST_MSG("%d:%d\n", coherency, value.value.integer);
|
||||
coherency -= value.value.integer;
|
||||
// calculate size & check
|
||||
coherency = abs(coherency) + 1;
|
||||
|
||||
int coherency = 1;
|
||||
TestVpiHandle iter_h = vpi_iterate(vpiRange, handle);
|
||||
while (TestVpiHandle range_h = vpi_scan(iter_h)) {
|
||||
int rangeSize;
|
||||
TestVpiHandle left_h, right_h;
|
||||
// get left hand side of range
|
||||
left_h = vpi_handle(vpiLeftRange, range_h);
|
||||
CHECK_RESULT_NZ(left_h);
|
||||
vpi_get_value(left_h, &value);
|
||||
rangeSize = value.value.integer;
|
||||
// get right hand side of range
|
||||
right_h = vpi_handle(vpiRightRange, range_h);
|
||||
CHECK_RESULT_NZ(right_h);
|
||||
vpi_get_value(right_h, &value);
|
||||
rangeSize = abs(rangeSize - value.value.integer) + 1;
|
||||
coherency *= rangeSize;
|
||||
}
|
||||
iter_h.freed();
|
||||
|
||||
CHECK_RESULT(coherency, size);
|
||||
}
|
||||
|
||||
|
@ -83,12 +89,12 @@ static int _mon_check_props(TestVpiHandle& handle, int size, int direction, int
|
|||
int vpidir = vpi_get(vpiDirection, handle);
|
||||
// Don't check port directions in verilator
|
||||
// See issue #681
|
||||
if (!TestSimulator::is_verilator()) CHECK_RESULT(vpidir, direction);
|
||||
if (!TestSimulator::is_verilator() && !TestSimulator::is_questa()) CHECK_RESULT(vpidir, direction);
|
||||
}
|
||||
|
||||
// check type of object
|
||||
int vpitype = vpi_get(vpiType, handle);
|
||||
if (!(TestSimulator::is_verilator() && type == vpiPort)) {
|
||||
if (!TestSimulator::is_verilator() && !TestSimulator::is_questa() && type == vpiPort) {
|
||||
// Don't check for ports in verilator
|
||||
// See issue #681
|
||||
CHECK_RESULT(vpitype, type);
|
||||
|
@ -117,13 +123,11 @@ int mon_check_props() {
|
|||
static struct params values[]
|
||||
= {{"onebit", {1, vpiNoDirection, 1, vpiReg}, {0, 0, 0, 0}},
|
||||
{"twoone", {2, vpiNoDirection, 0, vpiReg}, {0, 0, 0, 0}},
|
||||
{"onetwo",
|
||||
{2, vpiNoDirection, 0, TestSimulator::is_verilator() ? vpiReg : vpiMemory},
|
||||
{0, 0, 0, 0}},
|
||||
{"onetwo", {2, vpiNoDirection, 1, vpiRegArray}, {0, 0, 0, 0}},
|
||||
{"fourthreetwoone",
|
||||
{2, vpiNoDirection, 0, vpiMemory},
|
||||
{2, vpiNoDirection, 0, vpiMemoryWord}},
|
||||
{"theint", {32, vpiNoDirection, 0, vpiReg}, {0, 0, 0, 0}},
|
||||
{2, vpiNoDirection, 0, vpiRegArray},
|
||||
{2, vpiNoDirection, 0, vpiReg}},
|
||||
{"theint", {32, vpiNoDirection, 0, TestSimulator::is_verilator() ? vpiReg : vpiIntVar}, {0, 0, 0, 0}},
|
||||
{"clk", {1, vpiInput, 1, vpiPort}, {0, 0, 0, 0}},
|
||||
{"testin", {16, vpiInput, 0, vpiPort}, {0, 0, 0, 0}},
|
||||
{"testout", {24, vpiOutput, 0, vpiPort}, {0, 0, 0, 0}},
|
||||
|
@ -145,7 +149,7 @@ int mon_check_props() {
|
|||
return status;
|
||||
if (value->children.size) {
|
||||
int size = 0;
|
||||
TestVpiHandle iter_h = vpi_iterate(vpiMemoryWord, h);
|
||||
TestVpiHandle iter_h = vpi_iterate(vpiReg, h);
|
||||
while (TestVpiHandle word_h = vpi_scan(iter_h)) {
|
||||
// check size and range
|
||||
if (int status
|
||||
|
|
|
@ -52,25 +52,27 @@ void _mon_check_range(const TestVpiHandle& handle, int size, int left, int right
|
|||
int vpisize = vpi_get(vpiSize, handle);
|
||||
TEST_CHECK_EQ(vpisize, size);
|
||||
}
|
||||
int coherency;
|
||||
// check coherency
|
||||
int coherency = 1;
|
||||
{
|
||||
// check left hand side of range
|
||||
TestVpiHandle left_h = vpi_handle(vpiLeftRange, handle);
|
||||
TEST_CHECK_NZ(left_h);
|
||||
vpi_get_value(left_h, &value);
|
||||
TEST_CHECK_EQ(value.value.integer, left);
|
||||
coherency = value.value.integer;
|
||||
TestVpiHandle iter_h = vpi_iterate(vpiRange, handle);
|
||||
while (TestVpiHandle range_h = vpi_scan(iter_h)) {
|
||||
int rangeSize;
|
||||
TestVpiHandle left_h, right_h;
|
||||
// get left hand side of range
|
||||
left_h = vpi_handle(vpiLeftRange, range_h);
|
||||
TEST_CHECK_NZ(left_h);
|
||||
vpi_get_value(left_h, &value);
|
||||
rangeSize = value.value.integer;
|
||||
// get right hand side of range
|
||||
right_h = vpi_handle(vpiRightRange, range_h);
|
||||
TEST_CHECK_NZ(right_h);
|
||||
vpi_get_value(right_h, &value);
|
||||
rangeSize = abs(rangeSize - value.value.integer) + 1;
|
||||
coherency *= rangeSize;
|
||||
}
|
||||
iter_h.freed();
|
||||
}
|
||||
{
|
||||
// check right hand side of range
|
||||
TestVpiHandle right_h = vpi_handle(vpiRightRange, handle);
|
||||
TEST_CHECK_NZ(right_h);
|
||||
vpi_get_value(right_h, &value);
|
||||
TEST_CHECK_EQ(value.value.integer, right);
|
||||
coherency -= value.value.integer;
|
||||
}
|
||||
// calculate size & check
|
||||
coherency = abs(coherency) + 1;
|
||||
TEST_CHECK_EQ(coherency, size);
|
||||
}
|
||||
|
||||
|
@ -83,8 +85,8 @@ void _mem_check(const char* name, int size, int left, int right, int words) {
|
|||
TEST_CHECK_NZ(mem_h);
|
||||
// check type
|
||||
int vpitype = vpi_get(vpiType, mem_h);
|
||||
if (vpitype != vpiMemory && vpitype != vpiReg) {
|
||||
printf("%%Error: %s:%d vpiType neither vpiMemory or vpiReg: %d\n", FILENM, __LINE__,
|
||||
if (vpitype != vpiRegArray && vpitype != vpiReg) {
|
||||
printf("%%Error: %s:%d vpiType neither vpiRegArray or vpiReg: %d\n", FILENM, __LINE__,
|
||||
vpitype);
|
||||
errors++;
|
||||
}
|
||||
|
@ -96,9 +98,9 @@ void _mem_check(const char* name, int size, int left, int right, int words) {
|
|||
}
|
||||
}
|
||||
// iterate and store
|
||||
if (vpitype == vpiMemory) {
|
||||
if (vpitype == vpiRegArray) {
|
||||
_mon_check_range(mem_h, words, words, 1);
|
||||
TestVpiHandle iter_h = vpi_iterate(vpiMemoryWord, mem_h);
|
||||
TestVpiHandle iter_h = vpi_iterate(vpiReg, mem_h);
|
||||
int cnt = 0;
|
||||
while (TestVpiHandle lcl_h = vpi_scan(iter_h)) {
|
||||
value.format = vpiIntVal;
|
||||
|
@ -112,15 +114,15 @@ void _mem_check(const char* name, int size, int left, int right, int words) {
|
|||
TEST_CHECK_EQ(cnt, words); // should be words addresses
|
||||
} else {
|
||||
int expSize = size * words;
|
||||
_mon_check_range(mem_h, expSize, expSize - 1, 0);
|
||||
_mon_check_range(mem_h, expSize, words, 1);
|
||||
value.format = vpiBinStrVal;
|
||||
value.value.str = const_cast<char*>(binStr.c_str());
|
||||
vpi_put_value(mem_h, &value, NULL, vpiNoDelay);
|
||||
TEST_CHECK_Z(vpi_chk_error(&e));
|
||||
}
|
||||
if (vpitype == vpiMemory) {
|
||||
if (vpitype == vpiRegArray) {
|
||||
// iterate and accumulate
|
||||
TestVpiHandle iter_h = vpi_iterate(vpiMemoryWord, mem_h);
|
||||
TestVpiHandle iter_h = vpi_iterate(vpiReg, mem_h);
|
||||
int cnt = 0;
|
||||
while (TestVpiHandle lcl_h = vpi_scan(iter_h)) {
|
||||
++cnt;
|
||||
|
@ -148,7 +150,7 @@ void _mem_check(const char* name, int size, int left, int right, int words) {
|
|||
{
|
||||
// make sure trying to get properties that don't exist
|
||||
// doesn't crash
|
||||
TestVpiHandle iter_h = vpi_iterate(vpiMemoryWord, mem_h);
|
||||
TestVpiHandle iter_h = vpi_iterate(vpiReg, mem_h);
|
||||
int should_be_undefined = vpi_get(vpiSize, iter_h);
|
||||
TEST_CHECK_EQ(should_be_undefined, vpiUndefined);
|
||||
should_be_undefined = vpi_get(vpiIndex, iter_h);
|
||||
|
@ -160,7 +162,7 @@ void _mem_check(const char* name, int size, int left, int right, int words) {
|
|||
should_be_NULL = vpi_handle(vpiScope, iter_h);
|
||||
TEST_CHECK_EQ(should_be_NULL, 0);
|
||||
}
|
||||
if (vpitype == vpiMemory) {
|
||||
if (vpitype == vpiRegArray) {
|
||||
// check vpiRange
|
||||
TestVpiHandle iter_h = vpi_iterate(vpiRange, mem_h);
|
||||
TEST_CHECK_NZ(iter_h);
|
||||
|
|
|
@ -0,0 +1,462 @@
|
|||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifdef IS_VPI
|
||||
|
||||
#include "vpi_user.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#else
|
||||
|
||||
#include "verilated.h"
|
||||
#include "verilated_vcd_c.h"
|
||||
#include "verilated_vpi.h"
|
||||
|
||||
#include "Vt_vpi_multidim.h"
|
||||
#include "Vt_vpi_multidim__Dpi.h"
|
||||
#include "svdpi.h"
|
||||
|
||||
#endif
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include <cstdlib>
|
||||
|
||||
// These require the above. Comment prevents clang-format moving them
|
||||
#include "TestCheck.h"
|
||||
#include "TestSimulator.h"
|
||||
#include "TestVpi.h"
|
||||
|
||||
int errors = 0;
|
||||
|
||||
// TEST START
|
||||
|
||||
void _arr_type_check(TestVpiHandle& arr_h, int expType, int expSize, int expRangeHigh, int expRangeLow)
|
||||
{
|
||||
const int vpitype = vpi_get(vpiType, arr_h);
|
||||
TEST_CHECK_EQ(vpitype, expType);
|
||||
const int vpisize = vpi_get(vpiSize, arr_h);
|
||||
TEST_CHECK_EQ(vpisize, expSize);
|
||||
|
||||
s_vpi_value value;
|
||||
value.format = vpiIntVal;
|
||||
|
||||
TestVpiHandle left_h = vpi_handle(vpiLeftRange, arr_h);
|
||||
TEST_CHECK_NZ(left_h);
|
||||
vpi_get_value(left_h, &value);
|
||||
TEST_CHECK_EQ(value.value.integer, expRangeHigh);
|
||||
|
||||
TestVpiHandle right_h = vpi_handle(vpiRightRange, arr_h);
|
||||
TEST_CHECK_NZ(right_h);
|
||||
vpi_get_value(right_h, &value);
|
||||
TEST_CHECK_EQ(value.value.integer, expRangeLow);
|
||||
}
|
||||
|
||||
void _arr_iter_check(const char* name, int wordSize, const int* lows) {
|
||||
TestVpiHandle arr_h = vpi_handle_by_name(const_cast<PLI_BYTE8*>(TestSimulator::rooted(name)), NULL);
|
||||
TEST_CHECK_NZ(arr_h);
|
||||
|
||||
_arr_type_check(arr_h, vpiRegArray, 4, lows[0] + 1, lows[0]);
|
||||
|
||||
{
|
||||
// can't iterate through RegArrays on a nested RegArray
|
||||
TestVpiHandle arr_iter_h = vpi_iterate(vpiRegArray, arr_h);
|
||||
TEST_CHECK_Z(vpi_scan(arr_iter_h));
|
||||
arr_iter_h.freed();
|
||||
}
|
||||
|
||||
if (!TestSimulator::is_questa()) {
|
||||
// but we can access them by index (Questa can't)
|
||||
for (int idx = lows[0]; idx < lows[0] + 2; idx++) {
|
||||
TestVpiHandle arr_elem_h = vpi_handle_by_index(arr_h, idx);
|
||||
TEST_CHECK_NZ(arr_elem_h);
|
||||
|
||||
// first indexing yields size-2 RegArrays
|
||||
_arr_type_check(arr_elem_h, vpiRegArray, 2, lows[1] + 1, lows[1]);
|
||||
|
||||
for (int idx2 = lows[1]; idx2 < lows[1] + 2; idx2++) {
|
||||
TestVpiHandle arr_elem2_h = vpi_handle_by_index(arr_elem_h, idx2);
|
||||
TEST_CHECK_NZ(arr_elem2_h);
|
||||
|
||||
// second indexing yields wordSize Regs
|
||||
_arr_type_check(arr_elem2_h, vpiReg, wordSize, lows[2] + 1, lows[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// it's also possible to directly iterate through all four Regs
|
||||
TestVpiHandle arr_iter_h = vpi_iterate(vpiReg, arr_h);
|
||||
for (int idx = 0; idx < 4; idx++) {
|
||||
TestVpiHandle arr_elem_h = vpi_scan(arr_iter_h);
|
||||
TEST_CHECK_NZ(arr_elem_h);
|
||||
|
||||
// which gives us wordSize Regs
|
||||
_arr_type_check(arr_elem_h, vpiReg, wordSize, lows[2] + 1, lows[2]);
|
||||
|
||||
{
|
||||
// can't iterate through Regs on a nested Reg
|
||||
TestVpiHandle arr_iter2_h = vpi_iterate(vpiReg, arr_elem_h);
|
||||
TEST_CHECK_Z(vpi_scan(arr_iter2_h));
|
||||
arr_iter2_h.freed();
|
||||
}
|
||||
|
||||
// but we can access them by index
|
||||
for (int idx2 = lows[2]; idx2 < lows[2] + 2; idx2++) {
|
||||
TestVpiHandle arr_elem2_h = vpi_handle_by_index(arr_elem_h, idx2);
|
||||
TEST_CHECK_NZ(arr_elem2_h);
|
||||
|
||||
// first indexing yields wordSize / 2 Regs
|
||||
_arr_type_check(arr_elem2_h, vpiReg, wordSize / 2, lows[3] + wordSize / 2 - 1, lows[3]);
|
||||
|
||||
for (int idx3 = lows[3]; idx3 < lows[3] + wordSize / 2; idx3++) {
|
||||
TestVpiHandle arr_elem3_h = vpi_handle_by_index(arr_elem2_h, idx3);
|
||||
TEST_CHECK_NZ(arr_elem3_h);
|
||||
{
|
||||
// second indexing yields size-1 RegBits (no support for RegBit VPI type yet)
|
||||
const int vpitype = vpi_get(vpiType, arr_elem3_h);
|
||||
if (TestSimulator::is_verilator()) {
|
||||
TEST_CHECK_EQ(vpitype, vpiReg);
|
||||
} else {
|
||||
TEST_CHECK_EQ(vpitype, vpiRegBit);
|
||||
}
|
||||
const int vpisize = vpi_get(vpiSize, arr_elem3_h);
|
||||
TEST_CHECK_EQ(vpisize, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// iterating through packed ranges
|
||||
TestVpiHandle range_iter_h = vpi_iterate(vpiRange, arr_elem_h);
|
||||
for (int idx2 = 0; idx2 < 2; idx2++) {
|
||||
TestVpiHandle range_h = vpi_scan(range_iter_h);
|
||||
TEST_CHECK_NZ(range_h);
|
||||
{
|
||||
s_vpi_value value;
|
||||
value.format = vpiIntVal;
|
||||
TestVpiHandle side_h = vpi_handle(vpiLeftRange, range_h);
|
||||
TEST_CHECK_NZ(side_h);
|
||||
vpi_get_value(side_h, &value);
|
||||
if (idx2 == 0) {
|
||||
TEST_CHECK_EQ(value.value.integer, lows[2] + 1);
|
||||
} else {
|
||||
TEST_CHECK_EQ(value.value.integer, lows[3] + wordSize / 2 - 1);
|
||||
}
|
||||
side_h = vpi_handle(vpiRightRange, range_h);
|
||||
TEST_CHECK_NZ(side_h);
|
||||
vpi_get_value(side_h, &value);
|
||||
if (idx2 == 0) {
|
||||
TEST_CHECK_EQ(value.value.integer, lows[2]);
|
||||
} else {
|
||||
TEST_CHECK_EQ(value.value.integer, lows[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
TEST_CHECK_Z(vpi_scan(range_iter_h));
|
||||
range_iter_h.freed();
|
||||
}
|
||||
TEST_CHECK_Z(vpi_scan(arr_iter_h));
|
||||
arr_iter_h.freed();
|
||||
}
|
||||
|
||||
{
|
||||
// iterating through unpacked ranges
|
||||
TestVpiHandle range_iter_h = vpi_iterate(vpiRange, arr_h);
|
||||
for (int idx = 0; idx < 2; idx++) {
|
||||
TestVpiHandle range_h = vpi_scan(range_iter_h);
|
||||
TEST_CHECK_NZ(range_h);
|
||||
{
|
||||
s_vpi_value value;
|
||||
value.format = vpiIntVal;
|
||||
TestVpiHandle side_h = vpi_handle(vpiLeftRange, range_h);
|
||||
TEST_CHECK_NZ(side_h);
|
||||
vpi_get_value(side_h, &value);
|
||||
if (idx == 0) {
|
||||
TEST_CHECK_EQ(value.value.integer, lows[0] + 1);
|
||||
} else {
|
||||
TEST_CHECK_EQ(value.value.integer, lows[1] + 1);
|
||||
}
|
||||
side_h = vpi_handle(vpiRightRange, range_h);
|
||||
TEST_CHECK_NZ(side_h);
|
||||
vpi_get_value(side_h, &value);
|
||||
if (idx == 0) {
|
||||
TEST_CHECK_EQ(value.value.integer, lows[0]);
|
||||
} else {
|
||||
TEST_CHECK_EQ(value.value.integer, lows[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
TEST_CHECK_Z(vpi_scan(range_iter_h));
|
||||
range_iter_h.freed();
|
||||
}
|
||||
}
|
||||
|
||||
void _arr_access_format_check(TestVpiHandle ®_h, int wordSize, const int* lows, const char *octVal_s, PLI_INT32 format)
|
||||
{
|
||||
const int spanSize = wordSize / 2;
|
||||
s_vpi_value value_in;
|
||||
s_vpi_value value_out;
|
||||
s_vpi_error_info e;
|
||||
char zero_s[2] = "0";
|
||||
|
||||
// zero out the vector
|
||||
value_in.format = vpiOctStrVal;
|
||||
value_in.value.str = zero_s;
|
||||
vpi_put_value(reg_h, &value_in, NULL, vpiNoDelay);
|
||||
TEST_CHECK_Z(vpi_chk_error(&e));
|
||||
|
||||
value_in.format = format;
|
||||
value_out.format = format;
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
TestVpiHandle subreg_h = vpi_handle_by_index(reg_h, lows[2] + i);
|
||||
TEST_CHECK_NZ(subreg_h);
|
||||
|
||||
char octSpan_s[spanSize / 3 + 1];
|
||||
strncpy(octSpan_s, &octVal_s[spanSize / 3 * (1 - i)], spanSize / 3);
|
||||
octSpan_s[spanSize / 3] = '\0';
|
||||
|
||||
uint64_t intVal;
|
||||
t_vpi_vecval vecVal[2];
|
||||
sscanf(octSpan_s, "%" SCNo64, &intVal);
|
||||
char strVal_s[spanSize + 1]; // max length of the string happens for binary
|
||||
|
||||
if (format == vpiIntVal) {
|
||||
value_in.value.integer = intVal;
|
||||
} else if (format == vpiVectorVal) {
|
||||
if (spanSize > 32) {
|
||||
vecVal[1].aval = intVal >> 32;
|
||||
vecVal[1].bval = 0;
|
||||
}
|
||||
vecVal[0].aval = intVal;
|
||||
vecVal[0].bval = 0;
|
||||
value_in.value.vector = vecVal;
|
||||
} else if (format == vpiBinStrVal) {
|
||||
for (int j = 0; j < spanSize; j++)
|
||||
strVal_s[j] = (intVal >> (spanSize - j - 1)) % 2 + '0';
|
||||
strVal_s[spanSize] = '\0';
|
||||
value_in.value.str = strVal_s;
|
||||
} else if (format == vpiDecStrVal) {
|
||||
sprintf(strVal_s, "%" PRIu64, intVal);
|
||||
value_in.value.str = strVal_s;
|
||||
} else if (format == vpiHexStrVal) {
|
||||
sprintf(strVal_s, "%0*" PRIx64, (spanSize + 3) / 4, intVal);
|
||||
value_in.value.str = strVal_s;
|
||||
} else if (format == vpiOctStrVal) {
|
||||
sprintf(strVal_s, "%" PRIo64, intVal);
|
||||
value_in.value.str = strVal_s;
|
||||
} else if (format == vpiStringVal) {
|
||||
const int byteCount = (spanSize + 7) / 8;
|
||||
for (int j = 0; j < byteCount; j++)
|
||||
strVal_s[j] = (intVal >> (8 * (byteCount - j - 1))) & 0xff;
|
||||
strVal_s[byteCount] = '\0';
|
||||
value_in.value.str = strVal_s;
|
||||
}
|
||||
|
||||
vpi_put_value(subreg_h, &value_in, NULL, vpiNoDelay);
|
||||
TEST_CHECK_Z(vpi_chk_error(&e));
|
||||
|
||||
vpi_get_value(subreg_h, &value_out);
|
||||
switch (format) {
|
||||
case vpiIntVal:
|
||||
TEST_CHECK_EQ(value_out.value.integer, value_in.value.integer);
|
||||
break;
|
||||
case vpiVectorVal:
|
||||
if (spanSize > 32)
|
||||
TEST_CHECK_EQ(value_out.value.vector[1].aval, value_in.value.vector[1].aval);
|
||||
TEST_CHECK_EQ(value_out.value.vector[0].aval, value_in.value.vector[0].aval);
|
||||
break;
|
||||
case vpiStringVal:
|
||||
TEST_CHECK_EQ(value_out.value.str[0], value_in.value.str[0] ? value_in.value.str[0] : ' ');
|
||||
break;
|
||||
case vpiBinStrVal:
|
||||
case vpiDecStrVal:
|
||||
case vpiHexStrVal:
|
||||
case vpiOctStrVal:
|
||||
TEST_CHECK_CSTR(value_out.value.str, value_in.value.str);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// validate the resulting flattened vector
|
||||
value_out.format = vpiOctStrVal;
|
||||
vpi_get_value(reg_h, &value_out);
|
||||
TEST_CHECK_CSTR(value_out.value.str, octVal_s);
|
||||
}
|
||||
|
||||
std::default_random_engine rng;
|
||||
|
||||
void _arr_access_check(const char* name, int wordSize, const int* lows) {
|
||||
TestVpiHandle arr_h = vpi_handle_by_name(const_cast<PLI_BYTE8*>(TestSimulator::rooted(name)), NULL);
|
||||
TEST_CHECK_NZ(arr_h);
|
||||
|
||||
std::uniform_int_distribution<uint64_t> rand64(
|
||||
std::numeric_limits<uint64_t>::min(),
|
||||
std::numeric_limits<uint64_t>::max()
|
||||
);
|
||||
|
||||
char octVal_s[wordSize / 3 + 1];
|
||||
|
||||
// fill octVal_s with random octal digits
|
||||
if (wordSize < 64) {
|
||||
sprintf(octVal_s, "%0*" PRIo64, wordSize / 3, rand64(rng) % (static_cast<uint64_t>(1) << wordSize));
|
||||
} else {
|
||||
sprintf(octVal_s, "%0*" PRIo64, 63 / 3, rand64(rng));
|
||||
sprintf(octVal_s + 63 / 3, "%0*" PRIo64, (wordSize - 63) / 3, rand64(rng) % (static_cast<uint64_t>(1) << (wordSize - 63)));
|
||||
}
|
||||
|
||||
// Assume that reading/writing to the "flattened" packed register is already tested,
|
||||
// check only reading/writing to sub-regs and validate the flattened result.
|
||||
{
|
||||
TestVpiHandle arr_iter_h = vpi_iterate(vpiReg, arr_h);
|
||||
while (TestVpiHandle reg_h = vpi_scan(arr_iter_h)) {
|
||||
s_vpi_value value_in;
|
||||
s_vpi_value value_out;
|
||||
s_vpi_error_info e;
|
||||
|
||||
value_out.format = vpiOctStrVal;
|
||||
value_in.format = vpiOctStrVal;
|
||||
value_in.value.str = octVal_s;
|
||||
vpi_put_value(reg_h, &value_in, NULL, vpiNoDelay);
|
||||
TEST_CHECK_Z(vpi_chk_error(&e));
|
||||
vpi_get_value(reg_h, &value_out);
|
||||
TEST_CHECK_CSTR(value_out.value.str, octVal_s);
|
||||
|
||||
// test each I/O data format
|
||||
if (wordSize <= 64) {
|
||||
_arr_access_format_check(reg_h, wordSize, lows, octVal_s, vpiIntVal);
|
||||
_arr_access_format_check(reg_h, wordSize, lows, octVal_s, vpiDecStrVal);
|
||||
}
|
||||
_arr_access_format_check(reg_h, wordSize, lows, octVal_s, vpiVectorVal);
|
||||
_arr_access_format_check(reg_h, wordSize, lows, octVal_s, vpiBinStrVal);
|
||||
_arr_access_format_check(reg_h, wordSize, lows, octVal_s, vpiOctStrVal);
|
||||
_arr_access_format_check(reg_h, wordSize, lows, octVal_s, vpiHexStrVal);
|
||||
_arr_access_format_check(reg_h, wordSize, lows, octVal_s, vpiStringVal);
|
||||
}
|
||||
arr_iter_h.freed();
|
||||
}
|
||||
}
|
||||
|
||||
struct params {
|
||||
const char* name;
|
||||
int wordSize;
|
||||
const int lows[4];
|
||||
};
|
||||
|
||||
void _multidim_check() {
|
||||
static struct params values[] = {
|
||||
{"arr_cdata", 6, {0, 1, 2, 3}},
|
||||
{"arr_sdata", 12, {4, 5, 6, 7}},
|
||||
{"arr_idata", 30, {8, 9, 10, 11}},
|
||||
{"arr_qdata", 60, {12, 13, 14, 15}},
|
||||
{"arr_wdata", 126, {16, 17, 18, 19}},
|
||||
{nullptr, 0, {0, 0, 0, 0}}
|
||||
};
|
||||
struct params* value = values;
|
||||
while (value->name) {
|
||||
_arr_iter_check(value->name, value->wordSize, value->lows);
|
||||
_arr_access_check(value->name, value->wordSize, value->lows);
|
||||
value++;
|
||||
}
|
||||
}
|
||||
|
||||
// TEST END
|
||||
|
||||
extern "C" int mon_check() {
|
||||
// Callback from initial block in monitor
|
||||
//if (int status = _mon_check_param()) return status;
|
||||
printf("-mon_check()\n");
|
||||
_multidim_check();
|
||||
return errors;
|
||||
}
|
||||
|
||||
#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};
|
||||
|
||||
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++);
|
||||
}
|
||||
|
||||
void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0};
|
||||
|
||||
#else
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||
|
||||
uint64_t sim_time = 1100; // TODO
|
||||
contextp->debug(0);
|
||||
contextp->commandArgs(argc, argv);
|
||||
|
||||
const std::unique_ptr<VM_PREFIX> topp{new VM_PREFIX{contextp.get(),
|
||||
// Note null name - we're flattening it out
|
||||
""}};
|
||||
|
||||
#ifdef VERILATOR
|
||||
#ifdef TEST_VERBOSE
|
||||
contextp->scopesDump();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if VM_TRACE
|
||||
contextp->traceEverOn(true);
|
||||
VL_PRINTF("Enabling waves...\n");
|
||||
VerilatedVcdC* tfp = new VerilatedVcdC;
|
||||
topp->trace(tfp, 99);
|
||||
tfp->open(STRINGIFY(TEST_OBJ_DIR) "/simx.vcd");
|
||||
#endif
|
||||
|
||||
topp->eval();
|
||||
topp->clk = 0;
|
||||
contextp->timeInc(10);
|
||||
|
||||
while (contextp->time() < sim_time && !contextp->gotFinish()) {
|
||||
contextp->timeInc(1);
|
||||
topp->eval();
|
||||
VerilatedVpi::callValueCbs();
|
||||
topp->clk = !topp->clk;
|
||||
// mon_do();
|
||||
#if VM_TRACE
|
||||
if (tfp) tfp->dump(main_time);
|
||||
#endif
|
||||
}
|
||||
if (!contextp->gotFinish()) {
|
||||
vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish");
|
||||
}
|
||||
topp->final();
|
||||
|
||||
#if VM_TRACE
|
||||
if (tfp) tfp->close();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,22 @@
|
|||
#!/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,
|
||||
v_flags2=["+define+USE_VPI_NOT_DPI"],
|
||||
verilator_flags2=["--exe --vpi --no-l2name --public-flat-rw", test.pli_filename])
|
||||
|
||||
test.execute(use_libvpi=True)
|
||||
|
||||
test.passes()
|
|
@ -0,0 +1,44 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// 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
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
); /*verilator public_module*/
|
||||
|
||||
`ifdef VERILATOR
|
||||
`systemc_header
|
||||
extern "C" int mon_check();
|
||||
`verilog
|
||||
`endif
|
||||
|
||||
input clk;
|
||||
|
||||
logic [3:2][5:3] arr_cdata [1:0][2:1]; // 2x3 (6) bit words
|
||||
logic [7:6][12:7] arr_sdata [5:4][6:5]; // 2x6 (12) bit words
|
||||
logic [11:10][25:11] arr_idata [9:8][10:9]; // 2x15 (30) bit words
|
||||
logic [15:14][44:15] arr_qdata [13:12][14:13]; // 2x30 (60) bit words
|
||||
logic [19:18][81:19] arr_wdata [17:16][18:17]; // 2x63 (126) bit words
|
||||
|
||||
int status;
|
||||
|
||||
initial begin
|
||||
`ifdef VERILATOR
|
||||
status = $c32("mon_check()");
|
||||
`else
|
||||
status = $mon_check();
|
||||
`endif
|
||||
if (status!=0) begin
|
||||
$write("%%Error: t_vpi_multidim.cpp:%0d: C Test failed\n", status);
|
||||
$stop;
|
||||
end
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule : t
|
|
@ -297,7 +297,7 @@ int _mon_check_var() {
|
|||
d = vpi_get(vpiVector, vh4);
|
||||
CHECK_RESULT(d, 1);
|
||||
p = vpi_get_str(vpiType, vh4);
|
||||
CHECK_RESULT_CSTR(p, "vpiMemory");
|
||||
CHECK_RESULT_CSTR(p, "vpiRegArray");
|
||||
}
|
||||
|
||||
t_vpi_value tmpValue;
|
||||
|
@ -320,14 +320,14 @@ int _mon_check_var() {
|
|||
CHECK_RESULT_CSTR(p, "vpiConstant");
|
||||
}
|
||||
{
|
||||
TestVpiHandle vh10 = vpi_iterate(vpiMemoryWord, vh4);
|
||||
TestVpiHandle vh10 = vpi_iterate(vpiReg, vh4);
|
||||
CHECK_RESULT_NZ(vh10);
|
||||
p = vpi_get_str(vpiType, vh10);
|
||||
CHECK_RESULT_CSTR(p, "vpiIterator");
|
||||
TestVpiHandle vh11 = vpi_scan(vh10);
|
||||
CHECK_RESULT_NZ(vh11);
|
||||
p = vpi_get_str(vpiType, vh11);
|
||||
CHECK_RESULT_CSTR(p, "vpiMemoryWord");
|
||||
CHECK_RESULT_CSTR(p, "vpiReg");
|
||||
TestVpiHandle vh12 = vpi_handle(vpiLeftRange, vh11);
|
||||
CHECK_RESULT_NZ(vh12);
|
||||
vpi_get_value(vh12, &tmpValue);
|
||||
|
@ -643,15 +643,15 @@ int _mon_check_quad() {
|
|||
TestVpiHandle vhidx3 = vpi_handle_by_index(vh2, 3);
|
||||
CHECK_RESULT_NZ(vhidx3);
|
||||
|
||||
// Memory words should not be indexable
|
||||
// Packed words should be indexable
|
||||
TestVpiHandle vhidx3idx0 = vpi_handle_by_index(vhidx3, 0);
|
||||
CHECK_RESULT(vhidx3idx0, 0);
|
||||
CHECK_RESULT_NZ(vhidx3idx0);
|
||||
TestVpiHandle vhidx2idx2 = vpi_handle_by_index(vhidx2, 2);
|
||||
CHECK_RESULT(vhidx2idx2, 0);
|
||||
CHECK_RESULT_NZ(vhidx2idx2);
|
||||
TestVpiHandle vhidx3idx3 = vpi_handle_by_index(vhidx3, 3);
|
||||
CHECK_RESULT(vhidx3idx3, 0);
|
||||
CHECK_RESULT_NZ(vhidx3idx3);
|
||||
TestVpiHandle vhidx2idx61 = vpi_handle_by_index(vhidx2, 61);
|
||||
CHECK_RESULT(vhidx2idx61, 0);
|
||||
CHECK_RESULT_NZ(vhidx2idx61);
|
||||
|
||||
v.format = vpiVectorVal;
|
||||
v.value.vector = vv;
|
||||
|
|
Loading…
Reference in New Issue