diff --git a/include/verilated.cpp b/include/verilated.cpp index 852cfb20e..eba94136c 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -2445,12 +2445,12 @@ vluint32_t VerilatedVarProps::entSize() const { size_t VerilatedVarProps::totalSize() const { size_t size = entSize(); - for (int dim = 0; dim <= dims(); ++dim) size *= m_unpacked[dim].elements(); + for (int udim = 0; udim <= udims(); ++udim) size *= m_unpacked[udim].elements(); return size; } void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const { - if (VL_UNLIKELY(dim <= 0 || dim > m_udims || dim > 3)) return NULL; + if (VL_UNLIKELY(dim <= 0 || dim > udims())) return NULL; if (VL_UNLIKELY(indx < low(dim) || indx > high(dim))) return NULL; int indxAdj = indx - low(dim); vluint8_t* bytep = reinterpret_cast(datap); @@ -2539,7 +2539,7 @@ void VerilatedScope::varInsert(int finalize, const char* namep, void* datap, if (i == 0) { var.m_packed.m_left = msb; var.m_packed.m_right = lsb; - } else if (i >= 1 && i <= 3) { + } else if (i >= 1 && i <= var.udims()) { var.m_unpacked[i - 1].m_left = msb; var.m_unpacked[i - 1].m_right = lsb; } else { diff --git a/include/verilated_sym_props.h b/include/verilated_sym_props.h index bc1dfdd94..e95b67ad6 100644 --- a/include/verilated_sym_props.h +++ b/include/verilated_sym_props.h @@ -29,6 +29,8 @@ #include "verilatedos.h" +#include + //=========================================================================== /// Verilator range /// Thread safety: Assume is constructed only with model, then any number of readers @@ -78,7 +80,14 @@ class VerilatedVarProps { const int m_pdims; // Packed dimensions const int m_udims; // Unpacked dimensions VerilatedRange m_packed; // Packed array range - VerilatedRange m_unpacked[3]; // Unpacked array range + std::vector m_unpacked; // Unpacked array ranges + void initUnpacked(const int* ulims) { + for (int i = 0; i < m_udims; ++i) { + const int left = ulims ? ulims[2 * i + 0] : 0; + const int right = ulims ? ulims[2 * i + 1] : 0; + m_unpacked.push_back(VerilatedRange(left, right)); + } + } // CONSTRUCTORS protected: friend class VerilatedScope; @@ -87,7 +96,9 @@ protected: , m_vltype(vltype) , m_vlflags(vlflags) , m_pdims(pdims) - , m_udims(udims) {} + , m_udims(udims) { + initUnpacked(NULL); + } public: class Unpacked {}; @@ -98,34 +109,13 @@ public: , m_vlflags(VerilatedVarFlags(vlflags)) , m_pdims(0) , m_udims(0) {} - VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int u0l, int u0r) + VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int udims, const int* ulims) : m_magic(MAGIC) , m_vltype(vltype) , m_vlflags(VerilatedVarFlags(vlflags)) , m_pdims(0) - , m_udims(1) { - m_unpacked[0].init(u0l, u0r); - } - VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int u0l, int u0r, int u1l, - int u1r) - : m_magic(MAGIC) - , m_vltype(vltype) - , m_vlflags(VerilatedVarFlags(vlflags)) - , m_pdims(0) - , m_udims(2) { - m_unpacked[0].init(u0l, u0r); - m_unpacked[1].init(u1l, u1r); - } - VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int u0l, int u0r, int u1l, - int u1r, int u2l, int u2r) - : m_magic(MAGIC) - , m_vltype(vltype) - , m_vlflags(VerilatedVarFlags(vlflags)) - , m_pdims(0) - , m_udims(3) { - m_unpacked[0].init(u0l, u0r); - m_unpacked[1].init(u1l, u1r); - m_unpacked[2].init(u2l, u2r); + , m_udims(udims) { + initUnpacked(ulims); } // With packed class Packed {}; @@ -137,37 +127,14 @@ public: , m_udims(0) , m_packed(pl, pr) {} VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked, - int u0l, int u0r) + int udims, const int* ulims) : m_magic(MAGIC) , m_vltype(vltype) , m_vlflags(VerilatedVarFlags(vlflags)) , m_pdims(1) - , m_udims(1) + , m_udims(udims) , m_packed(pl, pr) { - m_unpacked[0].init(u0l, u0r); - } - VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked, - int u0l, int u0r, int u1l, int u1r) - : m_magic(MAGIC) - , m_vltype(vltype) - , m_vlflags(VerilatedVarFlags(vlflags)) - , m_pdims(1) - , m_udims(2) - , m_packed(pl, pr) { - m_unpacked[0].init(u0l, u0r); - m_unpacked[1].init(u1l, u1r); - } - VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked, - int u0l, int u0r, int u1l, int u1r, int u2l, int u2r) - : m_magic(MAGIC) - , m_vltype(vltype) - , m_vlflags(VerilatedVarFlags(vlflags)) - , m_pdims(1) - , m_udims(3) - , m_packed(pl, pr) { - m_unpacked[0].init(u0l, u0r); - m_unpacked[1].init(u1l, u1r); - m_unpacked[2].init(u2l, u2r); + initUnpacked(ulims); } public: @@ -189,27 +156,29 @@ public: // DPI accessors int left(int dim) const { return dim == 0 ? m_packed.left() - : VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].left() : 0; + : VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].left() : 0; } int right(int dim) const { return dim == 0 ? m_packed.right() - : VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].right() : 0; + : VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].right() : 0; } int low(int dim) const { return dim == 0 ? m_packed.low() - : VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].low() : 0; + : VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].low() : 0; } int high(int dim) const { return dim == 0 ? m_packed.high() - : VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].high() : 0; + : VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].high() : 0; } int increment(int dim) const { - return dim == 0 ? m_packed.increment() - : VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].increment() : 0; + return dim == 0 + ? m_packed.increment() + : VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].increment() : 0; } int elements(int dim) const { - return dim == 0 ? m_packed.elements() - : VL_LIKELY(dim >= 1 && dim <= 3) ? m_unpacked[dim - 1].elements() : 0; + return dim == 0 + ? m_packed.elements() + : VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].elements() : 0; } /// Total size in bytes (note DPI limited to 4GB) size_t totalSize() const; diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index bcfc68fa0..a046ee027 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -282,16 +282,16 @@ string AstVar::verilogKwd() const { class AstVar::VlArgTypeRecursed { public: - string m_oref; // To output, reference part before name, "&" - string m_osuffix; // To output, suffixed after name, "[3]" - string m_oprefix; // To output, prefixed before name, "Foo_t" - void clear() { - m_oref.clear(); - m_osuffix.clear(); - m_oprefix.clear(); - } - string refParen(const string& name) { - return m_oref.empty() ? name : "(" + m_oref + " " + name + ")"; + bool m_isRef; // Is it a reference? + string m_type; // The base type, e.g.: "Foo_t"s + string m_dims; // Array dimensions, e.g.: "[3][2][1]" + string render(const string& name) { + string out; + out += m_type; + out += " "; + out += m_isRef ? "(&" + name + ")" : name; + out += m_dims; + return out; } }; @@ -301,126 +301,86 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& string ostatic; if (isStatic() && namespc.empty()) ostatic = "static "; - VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep(), false); + VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, dtypep()); string oname; if (named) { - oname += " "; if (!namespc.empty()) oname += namespc + "::"; oname += VIdProtect::protectIf(name(), protect()); } - return ostatic + info.m_oprefix + info.refParen(oname) + info.m_osuffix; + return ostatic + info.render(oname); } AstVar::VlArgTypeRecursed AstVar::vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep, - bool arrayed) const { + bool compound) const { + VlArgTypeRecursed info; + info.m_isRef + = isDpiOpenArray() || (forFunc && (isWritable() || direction().isRefOrConstRef())); + dtypep = dtypep->skipRefp(); if (const AstAssocArrayDType* adtypep = VN_CAST_CONST(dtypep, AssocArrayDType)) { - VlArgTypeRecursed key = vlArgTypeRecurse(forFunc, adtypep->keyDTypep(), true); - VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true); - string out = "VlAssocArray<"; - out += key.m_oprefix; - if (!key.m_osuffix.empty() || !key.m_oref.empty()) { - out += " " + key.m_osuffix + key.m_oref; - } - out += ", "; - out += sub.m_oprefix; - if (!sub.m_osuffix.empty() || !sub.m_oref.empty()) { - out += " " + sub.m_osuffix + sub.m_oref; - } - out += "> "; - VlArgTypeRecursed info; - info.m_oprefix = out; - return info; + const VlArgTypeRecursed key = vlArgTypeRecurse(false, adtypep->keyDTypep(), true); + const VlArgTypeRecursed val = vlArgTypeRecurse(false, adtypep->subDTypep(), true); + info.m_type = "VlAssocArray<" + key.m_type + ", " + val.m_type + ">"; } else if (const AstDynArrayDType* adtypep = VN_CAST_CONST(dtypep, DynArrayDType)) { - VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true); - string out = "VlQueue<"; - out += sub.m_oprefix; - if (!sub.m_osuffix.empty() || !sub.m_oref.empty()) { - out += " " + sub.m_osuffix + sub.m_oref; - } - out += "> "; - VlArgTypeRecursed info; - info.m_oprefix = out; - return info; + const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), true); + info.m_type = "VlQueue<" + sub.m_type + ">"; } else if (const AstQueueDType* adtypep = VN_CAST_CONST(dtypep, QueueDType)) { - VlArgTypeRecursed sub = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), true); - VlArgTypeRecursed info; - string out = "VlQueue<" + sub.m_oprefix; - if (!sub.m_osuffix.empty() || !sub.m_oref.empty()) { - out += " " + sub.m_osuffix + sub.m_oref; - } + const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), true); + info.m_type = "VlQueue<" + sub.m_type; // + 1 below as VlQueue uses 0 to mean unlimited, 1 to mean size() max is 1 - if (adtypep->boundp()) out += ", " + cvtToStr(adtypep->boundConst() + 1); - out += "> "; - info.m_oprefix = out; - return info; + if (adtypep->boundp()) info.m_type += ", " + cvtToStr(adtypep->boundConst() + 1); + info.m_type += ">"; } else if (const AstClassRefDType* adtypep = VN_CAST_CONST(dtypep, ClassRefDType)) { - VlArgTypeRecursed info; - info.m_oprefix = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">"; - return info; + info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">"; } else if (const AstUnpackArrayDType* adtypep = VN_CAST_CONST(dtypep, UnpackArrayDType)) { - VlArgTypeRecursed info = vlArgTypeRecurse(forFunc, adtypep->subDTypep(), arrayed); - info.m_osuffix = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + info.m_osuffix; - return info; - } else if (const AstBasicDType* bdtypep = dtypep->basicp()) { - string otype; - string oarray; - bool strtype = bdtypep->keyword() == AstBasicDTypeKwd::STRING; - string bitvec; - if (!bdtypep->isOpaque() && !v3Global.opt.protectIds()) { - // We don't print msb()/lsb() as multidim packed would require recursion, - // and may confuse users as C++ data is stored always with bit 0 used - bitvec += "/*" + cvtToStr(dtypep->width() - 1) + ":0*/"; + if (compound) { + v3fatalSrc("Dynamic arrays or queues with unpacked elements are not yet supported"); } - if ((forFunc && isReadOnly()) || bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR - || bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) - otype += "const "; + const VlArgTypeRecursed sub = vlArgTypeRecurse(false, adtypep->subDTypep(), compound); + info.m_type = sub.m_type; + info.m_dims = "[" + cvtToStr(adtypep->declRange().elements()) + "]" + sub.m_dims; + } else if (const AstBasicDType* bdtypep = dtypep->basicp()) { + // We don't print msb()/lsb() as multidim packed would require recursion, + // and may confuse users as C++ data is stored always with bit 0 used + const string bitvec = (!bdtypep->isOpaque() && !v3Global.opt.protectIds()) + ? "/*" + cvtToStr(dtypep->width() - 1) + ":0*/" + : ""; if (bdtypep->keyword() == AstBasicDTypeKwd::CHARPTR) { - otype += "char*"; + info.m_type = "const char*"; } else if (bdtypep->keyword() == AstBasicDTypeKwd::SCOPEPTR) { - otype += "VerilatedScope*"; + info.m_type = "const VerilatedScope*"; } else if (bdtypep->keyword() == AstBasicDTypeKwd::DOUBLE) { - otype += "double"; + info.m_type = "double"; } else if (bdtypep->keyword() == AstBasicDTypeKwd::FLOAT) { - otype += "float"; - } else if (strtype) { - otype += "std::string"; + info.m_type = "float"; + } else if (bdtypep->keyword() == AstBasicDTypeKwd::STRING) { + info.m_type = "std::string"; } else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width - otype += "CData" + bitvec; + info.m_type = "CData" + bitvec; } else if (dtypep->widthMin() <= 16) { - otype += "SData" + bitvec; + info.m_type = "SData" + bitvec; } else if (dtypep->widthMin() <= VL_IDATASIZE) { - otype += "IData" + bitvec; + info.m_type = "IData" + bitvec; } else if (dtypep->isQuad()) { - otype += "QData" + bitvec; + info.m_type = "QData" + bitvec; } else if (dtypep->isWide()) { - if (arrayed) { - otype += "VlWide<" + cvtToStr(dtypep->widthWords()) + "> "; + if (compound) { + info.m_type = "VlWide<" + cvtToStr(dtypep->widthWords()) + "> "; } else { - otype += "WData" + bitvec; // []'s added later - oarray += "[" + cvtToStr(dtypep->widthWords()) + "]"; + info.m_type += "WData" + bitvec; // []'s added later + info.m_dims = "[" + cvtToStr(dtypep->widthWords()) + "]"; } } - - string oref; - if (isDpiOpenArray() - || (forFunc - && (isWritable() || direction() == VDirection::REF - || direction() == VDirection::CONSTREF || (strtype && isNonOutput())))) { - oref = "&"; - } - - VlArgTypeRecursed info; - info.m_oprefix = otype; - info.m_osuffix = oarray; - info.m_oref = oref; - // UINFO(9, "vlArgRec "<<"oprefix="<prettyName()); } + + UASSERT_OBJ(!compound || info.m_dims.empty(), this, "Declaring C array inside compound type"); + + if (forFunc && isReadOnly() && info.m_isRef) { info.m_type = "const " + info.m_type; } + + return info; } string AstVar::vlEnumType() const { @@ -472,29 +432,52 @@ string AstVar::vlEnumDir() const { return out; } -string AstVar::vlPropInit() const { +string AstVar::vlPropDecl(string propName) const { string out; - out = vlEnumType(); // VLVT_UINT32 etc - out += ", " + vlEnumDir(); // VLVD_IN etc - if (AstBasicDType* bdtypep = basicp()) { - out += ", VerilatedVarProps::Packed()"; - out += ", " + cvtToStr(bdtypep->left()) + ", " + cvtToStr(bdtypep->right()); - } - bool first = true; - for (AstNodeDType* dtp = dtypep(); dtp;) { + + std::vector ulims; // Unpacked dimension limits + for (const AstNodeDType* dtp = dtypep(); dtp;) { dtp = dtp->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node - if (AstNodeArrayDType* adtypep = VN_CAST(dtp, NodeArrayDType)) { - if (first) { - out += ", VerilatedVarProps::Unpacked()"; - first = false; - } - out += ", " + cvtToStr(adtypep->declRange().left()) + ", " - + cvtToStr(adtypep->declRange().right()); + if (const AstNodeArrayDType* const adtypep = VN_CAST_CONST(dtp, NodeArrayDType)) { + ulims.push_back(adtypep->declRange().left()); + ulims.push_back(adtypep->declRange().right()); dtp = adtypep->subDTypep(); } else { break; // AstBasicDType - nothing below } } + + if (!ulims.empty()) { + out += "static const int " + propName + "__ulims["; + out += cvtToStr(ulims.size()); + out += "] = {"; + std::vector::const_iterator it = ulims.begin(); + out += cvtToStr(*it); + while (++it != ulims.end()) { + 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 += ", " + cvtToStr(ulims.size() / 2); + out += ", " + propName + "__ulims"; + } + + out += ");\n"; return out; } diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 55e98c362..39e91aec7 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -1918,7 +1918,7 @@ public: string vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc = "") const; string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc - string vlPropInit() const; // Return VerilatorVarProps initializer + string vlPropDecl(string propName) const; // Return VerilatorVarProps declaration void combineType(AstVarType type); AstNodeDType* getChildDTypep() const { return childDTypep(); } // op1 = Range of variable @@ -2078,7 +2078,7 @@ public: private: class VlArgTypeRecursed; VlArgTypeRecursed vlArgTypeRecurse(bool forFunc, const AstNodeDType* dtypep, - bool arrayed) const; + bool compound = false) const; }; class AstDefParam : public AstNode { diff --git a/src/V3Task.cpp b/src/V3Task.cpp index bdb75e68d..537e77b6f 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -875,12 +875,17 @@ private: if (args != "") args += ", "; if (portp->isDpiOpenArray()) { + AstNodeDType* dtypep = portp->dtypep()->skipRefp(); + if (VN_IS(dtypep, DynArrayDType) || VN_IS(dtypep, QueueDType)) { + v3fatalSrc("Passing dynamic array or queue as actual argument to DPI " + "open array is not yet supported"); + } + // Ideally we'd make a table of variable // characteristics, and reuse it wherever we can // At least put them into the module's CTOR as static? string propName = portp->name() + "__Vopenprops"; - string propCode = ("static const VerilatedVarProps " + propName + "(" - + portp->vlPropInit() + ");\n"); + string propCode = portp->vlPropDecl(propName); cfuncp->addStmtsp(new AstCStmt(portp->fileline(), propCode)); // // At runtime we need the svOpenArrayHandle to diff --git a/test_regress/t/t_dpi_open_query.cpp b/test_regress/t/t_dpi_open_query.cpp new file mode 100644 index 000000000..21f7eab1c --- /dev/null +++ b/test_regress/t/t_dpi_open_query.cpp @@ -0,0 +1,72 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2020 by Geza Lore. 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 +// +//************************************************************************* + +// clang-format off + +#include "svdpi.h" + +#if defined(VERILATOR) // Verilator +# include "Vt_dpi_open_query__Dpi.h" +#elif defined(VCS) // VCS +# include "../vc_hdrs.h" +#elif defined(NCSC) // NC +# include "dpi-imp.h" +#elif defined(MS) // ModelSim +# include "dpi.h" +#else +# error "Unknown simulator for DPI test" +#endif + +// clang-format on + +//====================================================================== +// Implementations of imported functions +//====================================================================== + +// These are simple wrappers for the array querying functions themselves, +// see IEEE 1800-2017 H.12.2. Sadly on the SV side these have different +// signagures, and hence need to have different names here as well. + +// 1 open dimension +int cSvLeft1(const svOpenArrayHandle h, int d) { return svLeft(h, d); } +int cSvRight1(const svOpenArrayHandle h, int d) { return svRight(h, d); } +int cSvLow1(const svOpenArrayHandle h, int d) { return svLow(h, d); } +int cSvHigh1(const svOpenArrayHandle h, int d) { return svHigh(h, d); } +int cSvIncrement1(const svOpenArrayHandle h, int d) { return svIncrement(h, d); } +int cSvSize1(const svOpenArrayHandle h, int d) { return svSize(h, d); } +int cSvDimensions1(const svOpenArrayHandle h) { return svDimensions(h); } + +// 2 open dimensions +int cSvLeft2(const svOpenArrayHandle h, int d) { return svLeft(h, d); } +int cSvRight2(const svOpenArrayHandle h, int d) { return svRight(h, d); } +int cSvLow2(const svOpenArrayHandle h, int d) { return svLow(h, d); } +int cSvHigh2(const svOpenArrayHandle h, int d) { return svHigh(h, d); } +int cSvIncrement2(const svOpenArrayHandle h, int d) { return svIncrement(h, d); } +int cSvSize2(const svOpenArrayHandle h, int d) { return svSize(h, d); } +int cSvDimensions2(const svOpenArrayHandle h) { return svDimensions(h); } + +// 3 open dimensions +int cSvLeft3(const svOpenArrayHandle h, int d) { return svLeft(h, d); } +int cSvRight3(const svOpenArrayHandle h, int d) { return svRight(h, d); } +int cSvLow3(const svOpenArrayHandle h, int d) { return svLow(h, d); } +int cSvHigh3(const svOpenArrayHandle h, int d) { return svHigh(h, d); } +int cSvIncrement3(const svOpenArrayHandle h, int d) { return svIncrement(h, d); } +int cSvSize3(const svOpenArrayHandle h, int d) { return svSize(h, d); } +int cSvDimensions3(const svOpenArrayHandle h) { return svDimensions(h); } + +// 4 open dimensions +int cSvLeft4(const svOpenArrayHandle h, int d) { return svLeft(h, d); } +int cSvRight4(const svOpenArrayHandle h, int d) { return svRight(h, d); } +int cSvLow4(const svOpenArrayHandle h, int d) { return svLow(h, d); } +int cSvHigh4(const svOpenArrayHandle h, int d) { return svHigh(h, d); } +int cSvIncrement4(const svOpenArrayHandle h, int d) { return svIncrement(h, d); } +int cSvSize4(const svOpenArrayHandle h, int d) { return svSize(h, d); } +int cSvDimensions4(const svOpenArrayHandle h) { return svDimensions(h); } diff --git a/test_regress/t/t_dpi_open_query.pl b/test_regress/t/t_dpi_open_query.pl new file mode 100755 index 000000000..8a94dbf67 --- /dev/null +++ b/test_regress/t/t_dpi_open_query.pl @@ -0,0 +1,36 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Geza Lore. 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 + +scenarios(simulator => 1); + +if ($Self->{nc}) { + # For NC, compile twice, first just to generate DPI headers + compile( + nc_flags2 => ["+ncdpiimpheader+$Self->{obj_dir}/dpi-imp.h"] + ); +} + +compile( + v_flags2 => ["t/t_dpi_open_query.cpp"], + verilator_flags2 => ["-Wall -Wno-DECLFILENAME"], + # NC: Gdd the obj_dir to the C include path + nc_flags2 => ["+ncscargs+-I$Self->{obj_dir}"], + # ModelSim: Generate DPI header, add obj_dir to the C include path + ms_flags2 => ["-dpiheader $Self->{obj_dir}/dpi.h", + "-ccflags -I$Self->{obj_dir}"], + ); + +execute( + check_finished => 1, + ms_pli => 0 + ); + +ok(1); +1; diff --git a/test_regress/t/t_dpi_open_query.v b/test_regress/t/t_dpi_open_query.v new file mode 100644 index 000000000..9da5579f2 --- /dev/null +++ b/test_regress/t/t_dpi_open_query.v @@ -0,0 +1,314 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2020 by Geza Lore. 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 + +`define check(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0) +`define unless(cond,gotv,expv) do if (!(cond)) `check(gotv, expv); while(0) + +`ifdef VERILATOR + `define NO_DYNAMIC + `define NO_QUEUE +`endif + +`ifdef VCS + `define NO_QUEUE +`endif + +`ifdef NC + `define NO_DYNAMIC + `define NO_QUEUE +`endif + +`ifdef NC + `define ONNC 1 +`else + `define ONNC 0 +`endif + +`ifdef MS + `define ONMS 1 +`else + `define ONMS 0 +`endif + +module t; + + // 1 open dimension + import "DPI-C" function int cSvLeft1( input bit h [], int d); + import "DPI-C" function int cSvRight1( input bit h [], int d); + import "DPI-C" function int cSvLow1( input bit h [], int d); + import "DPI-C" function int cSvHigh1( input bit h [], int d); + import "DPI-C" function int cSvIncrement1( input bit h [], int d); + import "DPI-C" function int cSvSize1( input bit h [], int d); + import "DPI-C" function int cSvDimensions1( input bit h []); + + // 2 open dimensions + import "DPI-C" function int cSvLeft2( input bit h [][], int d); + import "DPI-C" function int cSvRight2( input bit h [][], int d); + import "DPI-C" function int cSvLow2( input bit h [][], int d); + import "DPI-C" function int cSvHigh2( input bit h [][], int d); + import "DPI-C" function int cSvIncrement2( input bit h [][], int d); + import "DPI-C" function int cSvSize2( input bit h [][], int d); + import "DPI-C" function int cSvDimensions2( input bit h [][]); + + // 3 open dimensions + import "DPI-C" function int cSvLeft3( input bit h [][][], int d); + import "DPI-C" function int cSvRight3( input bit h [][][], int d); + import "DPI-C" function int cSvLow3( input bit h [][][], int d); + import "DPI-C" function int cSvHigh3( input bit h [][][], int d); + import "DPI-C" function int cSvIncrement3( input bit h [][][], int d); + import "DPI-C" function int cSvSize3( input bit h [][][], int d); + import "DPI-C" function int cSvDimensions3( input bit h [][][]); + + // 4 open dimensions + import "DPI-C" function int cSvLeft4( input bit h [][][][], int d); + import "DPI-C" function int cSvRight4( input bit h [][][][], int d); + import "DPI-C" function int cSvLow4( input bit h [][][][], int d); + import "DPI-C" function int cSvHigh4( input bit h [][][][], int d); + import "DPI-C" function int cSvIncrement4( input bit h [][][][], int d); + import "DPI-C" function int cSvSize4( input bit h [][][][], int d); + import "DPI-C" function int cSvDimensions4( input bit h [][][][]); + + // verilator lint_off UNDRIVEN + bit a1 [1:0]; + bit a2 [1:0][2:0]; + bit a3 [1:0][2:0][3:0]; + bit a4 [1:0][2:0][3:0][4:0]; + + bit b1 [0:1]; + bit b2 [0:1][0:2]; + bit b3 [0:1][0:2][0:3]; + bit b4 [0:1][0:2][0:3][0:4]; + + bit c1 [-1:1]; + bit c2 [-1:1][-2:2]; + bit c3 [-1:1][-2:2][-3:3]; + bit c4 [-1:1][-2:2][-3:3][-4:4]; + +`ifndef NO_DYNAMIC + bit d1 []; + bit d2 [][-2:2]; + bit d3 [][-2:2][-3:3]; + bit d4 [][-2:2][-3:3][-4:4]; +`endif + +`ifndef NO_QUEUE + bit e1 [$]; +`endif + // verilator lint_on UNDRIVEN + + initial begin +`ifndef NO_DYNAMIC + d1 = new[3]; + d2 = new[3]; + d3 = new[3]; + d4 = new[3]; +`endif + +`ifndef NO_QUEUE + e1.push_back(0); + e1.push_back(0); + e1.push_back(0); +`endif + + // 1 open dimension + `check(cSvDimensions1(a1), 1); + `check(cSvDimensions1(b1), 1); + `check(cSvDimensions1(c1), 1); +`ifndef NO_DYNAMIC + `check(cSvDimensions1(d1), 1); +`endif +`ifndef NO_QUEUE + `check(cSvDimensions1(e1), 1); +`endif + for (int d = 0 ; d < 2 ; d++) begin + if (`ONNC && d == 0) continue; + + `check(cSvLeft1(a1, d), d); + `check(cSvRight1(a1, d), 0); + `check(cSvLow1(a1, d), 0); + `check(cSvHigh1(a1, d), d); + `unless(`ONMS && d == 0, cSvIncrement1(a1, d), 1); + `check(cSvSize1(a1, d), d+1); + + `check(cSvLeft1(b1, d), 0); + `check(cSvRight1(b1, d), d); + `check(cSvLow1(b1, d), 0); + `check(cSvHigh1(b1, d), d); +`ifndef NC + `unless(`ONMS && d == 0, cSvIncrement1(b1, d), d == 0 ? 1 : -1); +`endif + `check(cSvSize1(b1, d), d+1); + + `check(cSvLeft1(c1, d), -d); + `check(cSvRight1(c1, d), d); + `check(cSvLow1(c1, d), -d); + `check(cSvHigh1(c1, d), d); +`ifndef NC + `unless(`ONMS && d == 0, cSvIncrement1(c1, d), d == 0 ? 1 : -1); +`endif + `check(cSvSize1(c1, d), 2*d+1); + +`ifndef NO_DYNAMIC + `check(cSvLeft1(d1, d), d == 1 ? 0 : -d); + `check(cSvRight1(d1, d), d == 1 ? 2 : d); + `check(cSvLow1(d1, d), d == 1 ? 0 : -d); + `check(cSvHigh1(d1, d), d == 1 ? 2 : d); + `unless(`ONMS && d == 0, cSvIncrement1(d1, d), d == 0 ? 1 : -1); + `check(cSvSize1(d1, d), 2*d+1); +`endif + +`ifndef NO_QUEUE + `check(cSvLeft1(e1, d), d == 1 ? 0 : -d); + `check(cSvRight1(e1, d), d == 1 ? 2 : d); + `check(cSvLow1(e1, d), d == 1 ? 0 : -d); + `check(cSvHigh1(e1, d), d == 1 ? 2 : d); + `unless(`ONMS && d == 0, cSvIncrement1(e1, d), d == 0 ? 1 : -1); + `check(cSvSize1(e1, d), 2*d+1); +`endif + end + + // 2 open dimensions + `check(cSvDimensions2(a2), 2); + `check(cSvDimensions2(b2), 2); + `check(cSvDimensions2(c2), 2); +`ifndef NO_DYNAMIC + `check(cSvDimensions2(d2), 2); +`endif + for (int d = 0 ; d < 3 ; d++) begin + if (`ONNC && d == 0) continue; + + `check(cSvLeft2(a2, d), d); + `check(cSvRight2(a2, d), 0); + `check(cSvLow2(a2, d), 0); + `check(cSvHigh2(a2, d), d); + `unless(`ONMS && d == 0, cSvIncrement2(a2, d), 1); + `check(cSvSize2(a2, d), d+1); + + `check(cSvLeft2(b2, d), 0); + `check(cSvRight2(b2, d), d); + `check(cSvLow2(b2, d), 0); + `check(cSvHigh2(b2, d), d); +`ifndef NC + `unless(`ONMS && d == 0, cSvIncrement2(b2, d), d == 0 ? 1 : -1); +`endif + `check(cSvSize2(b2, d), d+1); + + `check(cSvLeft2(c2, d), -d); + `check(cSvRight2(c2, d), d); + `check(cSvLow2(c2, d), -d); + `check(cSvHigh2(c2, d), d); +`ifndef NC + `unless(`ONMS && d == 0, cSvIncrement2(c2, d), d == 0 ? 1 : -1); +`endif + `check(cSvSize2(c2, d), 2*d+1); + +`ifndef NO_DYNAMIC + `check(cSvLeft2(d2, d), d == 1 ? 0 : -d); + `check(cSvRight2(d2, d), d == 1 ? 2 : d); + `check(cSvLow2(d2, d), d == 1 ? 0 : -d); + `check(cSvHigh2(d2, d), d == 1 ? 2 : d); + `unless(`ONMS && d == 0, cSvIncrement2(d2, d), d == 0 ? 1 : -1); + `check(cSvSize2(d2, d), 2*d+1); +`endif + end + + // 3 open dimensions + `check(cSvDimensions3(a3), 3); + `check(cSvDimensions3(b3), 3); + `check(cSvDimensions3(c3), 3); +`ifndef NO_DYNAMIC + `check(cSvDimensions3(d3), 3); +`endif + for (int d = 0 ; d < 4 ; d++) begin + if (`ONNC && d == 0) continue; + + `check(cSvLeft3(a3, d), d); + `check(cSvRight3(a3, d), 0); + `check(cSvLow3(a3, d), 0); + `check(cSvHigh3(a3, d), d); + `unless(`ONMS && d == 0, cSvIncrement3(a3, d), 1); + `check(cSvSize3(a3, d), d+1); + + `check(cSvLeft3(b3, d), 0); + `check(cSvRight3(b3, d), d); + `check(cSvLow3(b3, d), 0); + `check(cSvHigh3(b3, d), d); +`ifndef NC + `unless(`ONMS && d == 0, cSvIncrement3(b3, d), d == 0 ? 1 : -1); +`endif + `check(cSvSize3(b3, d), d+1); + + `check(cSvLeft3(c3, d), -d); + `check(cSvRight3(c3, d), d); + `check(cSvLow3(c3, d), -d); + `check(cSvHigh3(c3, d), d); +`ifndef NC + `unless(`ONMS && d == 0, cSvIncrement3(c3, d), d == 0 ? 1 : -1); +`endif + `check(cSvSize3(c3, d), 2*d+1); + +`ifndef NO_DYNAMIC + `check(cSvLeft3(d3, d), d == 1 ? 0 : -d); + `check(cSvRight3(d3, d), d == 1 ? 2 : d); + `check(cSvLow3(d3, d), d == 1 ? 0 : -d); + `check(cSvHigh3(d3, d), d == 1 ? 2 : d); + `unless(`ONMS && d == 0, cSvIncrement3(d3, d), d == 0 ? 1 : -1); + `check(cSvSize3(d3, d), 2*d+1); +`endif + end + + // 4 open dimension + `check(cSvDimensions4(a4), 4); + `check(cSvDimensions4(b4), 4); + `check(cSvDimensions4(c4), 4); +`ifndef NO_DYNAMIC + `check(cSvDimensions4(d4), 4); +`endif + for (int d = 0 ; d < 5 ; d++) begin + if (`ONNC && d == 0) continue; + + `check(cSvLeft4(a4, d), d); + `check(cSvRight4(a4, d), 0); + `check(cSvLow4(a4, d), 0); + `check(cSvHigh4(a4, d), d); + `unless(`ONMS && d == 0, cSvIncrement4(a4, d), 1); + `check(cSvSize4(a4, d), d+1); + + `check(cSvLeft4(b4, d), 0); + `check(cSvRight4(b4, d), d); + `check(cSvLow4(b4, d), 0); + `check(cSvHigh4(b4, d), d); +`ifndef NC + `unless(`ONMS && d == 0, cSvIncrement4(b4, d), d == 0 ? 1 : -1); +`endif + `check(cSvSize4(b4, d), d+1); + + `check(cSvLeft4(c4, d), -d); + `check(cSvRight4(c4, d), d); + `check(cSvLow4(c4, d), -d); + `check(cSvHigh4(c4, d), d); +`ifndef NC + `unless(`ONMS && d == 0, cSvIncrement4(c4, d), d == 0 ? 1 : -1); +`endif + `check(cSvSize4(c4, d), 2*d+1); + +`ifndef NO_DYNAMIC + `check(cSvLeft4(d4, d), d == 1 ? 0 : -d); + `check(cSvRight4(d4, d), d == 1 ? 2 : d); + `check(cSvLow4(d4, d), d == 1 ? 0 : -d); + `check(cSvHigh4(d4, d), d == 1 ? 2 : d); + `unless(`ONMS && d == 0, cSvIncrement4(d4, d), d == 0 ? 1 : -1); + `check(cSvSize4(d4, d), 2*d+1); +`endif + end + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule