mirror of
https://github.com/verilator/verilator.git
synced 2026-10-06 10:03:44 +02:00
Support unpacked array in DPI-C (#2648)
* Add tests for unpacked array in DPI-C * Add more generic parameter generator to AstNodes * Supports multi dimensional array in DPI ( DPI argmuments <=> Verilator internal type conversion) consider typedef in V3Task fix export test fix inout for scalar support export func of time * V3Premit does not show an error for wide words nor ArraySel * Unnecessary pack func for unapcked array does not appear anymore * Support unpacked array in runtime header - Add an overload for lvalue VL_CVT_PACK_STR_NN - Allow conversion from void * * touch up tests for codacy advices * resolve free functions. no functional change intended.
This commit is contained in:
+104
-31
@@ -455,38 +455,99 @@ string AstVar::cPubArgType(bool named, bool forReturn) const {
|
||||
return arg;
|
||||
}
|
||||
|
||||
string AstVar::dpiArgType(bool named, bool forReturn) const {
|
||||
if (forReturn) named = false;
|
||||
string arg;
|
||||
if (isDpiOpenArray()) {
|
||||
arg = "const svOpenArrayHandle";
|
||||
} else if (!basicp()) {
|
||||
arg = "UNKNOWN";
|
||||
} else if (basicp()->isDpiBitVec()) {
|
||||
if (forReturn) {
|
||||
arg = "svBitVecVal";
|
||||
} else if (isReadOnly()) {
|
||||
arg = "const svBitVecVal*";
|
||||
} else {
|
||||
arg = "svBitVecVal*";
|
||||
}
|
||||
} else if (basicp()->isDpiLogicVec()) {
|
||||
if (forReturn) {
|
||||
arg = "svLogicVecVal";
|
||||
} else if (isReadOnly()) {
|
||||
arg = "const svLogicVecVal*";
|
||||
} else {
|
||||
arg = "svLogicVecVal*";
|
||||
}
|
||||
} else {
|
||||
arg = basicp()->keyword().dpiType();
|
||||
if (basicp()->keyword().isDpiUnsignable() && !basicp()->isSigned()) {
|
||||
arg = "unsigned " + arg;
|
||||
}
|
||||
if (!forReturn && isWritable()) arg += "*";
|
||||
class dpiTypesToStringConverter {
|
||||
public:
|
||||
virtual string openArray(const AstVar*) const { return "const svOpenArrayHandle"; }
|
||||
virtual string bitLogicVector(const AstVar* varp, bool isBit) const {
|
||||
return isBit ? "svBitVecVal" : "svLogicVecVal";
|
||||
}
|
||||
if (named) arg += " " + name();
|
||||
return arg;
|
||||
virtual string primitive(const AstVar* varp) const {
|
||||
string type;
|
||||
if (varp->basicp()->keyword().isDpiUnsignable() && !varp->basicp()->isSigned()) {
|
||||
type = "unsigned ";
|
||||
}
|
||||
type += varp->basicp()->keyword().dpiType();
|
||||
return type;
|
||||
}
|
||||
string convert(const AstVar* varp) const {
|
||||
if (varp->isDpiOpenArray()) {
|
||||
return openArray(varp);
|
||||
} else if (!varp->basicp()) {
|
||||
return "UNKNOWN";
|
||||
} else if (varp->basicp()->isDpiBitVec() || varp->basicp()->isDpiLogicVec()) {
|
||||
return bitLogicVector(varp, varp->basicp()->isDpiBitVec());
|
||||
} else {
|
||||
return primitive(varp);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
string AstVar::dpiArgType(bool named, bool forReturn) const {
|
||||
if (forReturn) {
|
||||
return dpiTypesToStringConverter{}.convert(this);
|
||||
} else {
|
||||
class converter : public dpiTypesToStringConverter {
|
||||
virtual string bitLogicVector(const AstVar* varp, bool isBit) const override {
|
||||
return string(varp->isReadOnly() ? "const " : "")
|
||||
+ dpiTypesToStringConverter::bitLogicVector(varp, isBit) + '*';
|
||||
}
|
||||
virtual string primitive(const AstVar* varp) const override {
|
||||
string type = dpiTypesToStringConverter::primitive(varp);
|
||||
if (varp->isWritable() || VN_IS(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
|
||||
if (!varp->isWritable()
|
||||
&& varp->basicp()->keyword() != AstBasicDTypeKwd::STRING)
|
||||
type = "const " + type;
|
||||
type += "*";
|
||||
}
|
||||
return type;
|
||||
}
|
||||
};
|
||||
string arg = converter{}.convert(this);
|
||||
if (named) arg += " " + name();
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
|
||||
string AstVar::dpiTmpVarType(const string& varName) const {
|
||||
class converter : public dpiTypesToStringConverter {
|
||||
string m_name;
|
||||
string arraySuffix(const AstVar* varp, size_t n) const {
|
||||
if (AstUnpackArrayDType* unpackp
|
||||
= VN_CAST(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
|
||||
// Convert multi dimensional unpacked array to 1D array
|
||||
if (n == 0) n = 1;
|
||||
n *= unpackp->arrayUnpackedElements();
|
||||
return '[' + cvtToStr(n) + ']';
|
||||
} else if (n > 0) {
|
||||
return '[' + cvtToStr(n) + ']';
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
virtual string openArray(const AstVar* varp) const override {
|
||||
return dpiTypesToStringConverter::openArray(varp) + ' ' + m_name
|
||||
+ arraySuffix(varp, 0);
|
||||
}
|
||||
virtual string bitLogicVector(const AstVar* varp, bool isBit) const override {
|
||||
string type = dpiTypesToStringConverter::bitLogicVector(varp, isBit);
|
||||
type += ' ' + m_name + arraySuffix(varp, varp->widthWords());
|
||||
return type;
|
||||
}
|
||||
virtual string primitive(const AstVar* varp) const override {
|
||||
string type = dpiTypesToStringConverter::primitive(varp);
|
||||
if (varp->isWritable() || VN_IS(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
|
||||
if (!varp->isWritable() && varp->basicp()->keyword() == AstBasicDTypeKwd::CHANDLE)
|
||||
type = "const " + type;
|
||||
}
|
||||
type += ' ' + m_name + arraySuffix(varp, 0);
|
||||
return type;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit converter(const string& name)
|
||||
: m_name(name) {}
|
||||
};
|
||||
return converter{varName}.convert(this);
|
||||
}
|
||||
|
||||
string AstVar::scType() const {
|
||||
@@ -1347,6 +1408,18 @@ string AstUnpackArrayDType::prettyDTypeName() const {
|
||||
os << subp->prettyDTypeName() << "$" << ranges;
|
||||
return os.str();
|
||||
}
|
||||
std::vector<AstUnpackArrayDType*> AstUnpackArrayDType::unpackDimensions() {
|
||||
std::vector<AstUnpackArrayDType*> dims;
|
||||
for (AstUnpackArrayDType* unpackp = this; unpackp;) {
|
||||
dims.push_back(unpackp);
|
||||
if (AstNodeDType* subp = unpackp->subDTypep()) {
|
||||
unpackp = VN_CAST(subp, UnpackArrayDType);
|
||||
} else {
|
||||
unpackp = nullptr;
|
||||
}
|
||||
}
|
||||
return dims;
|
||||
}
|
||||
void AstNetlist::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str << " [" << timeunit() << "/" << timeprecision() << "]";
|
||||
|
||||
@@ -721,6 +721,8 @@ public:
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(UnpackArrayDType)
|
||||
virtual string prettyDTypeName() const override;
|
||||
// Outer dimension comes first. The first element is this node.
|
||||
std::vector<AstUnpackArrayDType*> unpackDimensions();
|
||||
};
|
||||
|
||||
class AstUnsizedArrayDType final : public AstNodeDType {
|
||||
@@ -2026,6 +2028,7 @@ public:
|
||||
// Return C /*public*/ type for argument: bool, uint32_t, uint64_t, etc.
|
||||
string cPubArgType(bool named, bool forReturn) const;
|
||||
string dpiArgType(bool named, bool forReturn) const; // Return DPI-C type for argument
|
||||
string dpiTmpVarType(const string& varName) const;
|
||||
// Return Verilator internal type for argument: CData, SData, IData, WData
|
||||
string vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc = "") const;
|
||||
string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc
|
||||
|
||||
+3
-1
@@ -127,7 +127,9 @@ private:
|
||||
} else if (VN_IS(nodep->backp(), Sel)
|
||||
&& VN_CAST(nodep->backp(), Sel)->widthp() == nodep) {
|
||||
// AstSel::width must remain a constant
|
||||
} else if (nodep->firstAbovep() && VN_IS(nodep->firstAbovep(), ArraySel)) {
|
||||
} else if ((nodep->firstAbovep() && VN_IS(nodep->firstAbovep(), ArraySel))
|
||||
|| ((VN_IS(m_stmtp, CCall) || VN_IS(m_stmtp, CStmt))
|
||||
&& VN_IS(nodep, ArraySel))) {
|
||||
// ArraySel's are pointer refs, ignore
|
||||
} else {
|
||||
UINFO(4, "Cre Temp: " << nodep << endl);
|
||||
|
||||
@@ -411,11 +411,12 @@ private:
|
||||
|
||||
string cInputConnection(AstVar* varp) {
|
||||
string frstmt;
|
||||
bool useSetWSvlv = V3Task::dpiToInternalFrStmt(varp, varp->name(), frstmt);
|
||||
string ket;
|
||||
bool useSetWSvlv = V3Task::dpiToInternalFrStmt(varp, varp->name(), frstmt, ket);
|
||||
if (useSetWSvlv) {
|
||||
return frstmt + " handlep__V->" + varp->name() + ", " + varp->name() + ");\n";
|
||||
return frstmt + ket + " handlep__V->" + varp->name() + ", " + varp->name() + ");\n";
|
||||
}
|
||||
return "handlep__V->" + varp->name() + " = " + frstmt + ";\n";
|
||||
return "handlep__V->" + varp->name() + " = " + frstmt + ket + ";\n";
|
||||
}
|
||||
|
||||
void handleClock(AstVar* varp) {
|
||||
|
||||
+126
-35
@@ -641,11 +641,7 @@ private:
|
||||
}
|
||||
|
||||
AstNode* createDpiTemp(AstVar* portp, const string& suffix) {
|
||||
string stmt = portp->dpiArgType(false, true) + " " + portp->name() + suffix;
|
||||
if (!portp->basicp()->isDpiPrimitive()) {
|
||||
stmt += "[" + cvtToStr(portp->widthWords()) + "]";
|
||||
}
|
||||
stmt += ";\n";
|
||||
const string stmt = portp->dpiTmpVarType(portp->name() + suffix) + ";\n";
|
||||
return new AstCStmt(portp->fileline(), stmt);
|
||||
}
|
||||
|
||||
@@ -655,30 +651,80 @@ private:
|
||||
return new AstCStmt(portp->fileline(), stmt);
|
||||
}
|
||||
|
||||
static std::vector<std::pair<AstUnpackArrayDType*, int>> unpackDimsAndStrides(AstVar* varp) {
|
||||
std::vector<std::pair<AstUnpackArrayDType*, int>> dimStrides;
|
||||
if (AstUnpackArrayDType* dtypep = VN_CAST(varp->dtypep()->skipRefp(), UnpackArrayDType)) {
|
||||
const std::vector<AstUnpackArrayDType*> dims = dtypep->unpackDimensions();
|
||||
dimStrides.resize(dims.size(), {nullptr, 0});
|
||||
dimStrides.back() = {dims.back(), 1};
|
||||
for (ssize_t i = dims.size() - 2; i >= 0; --i) {
|
||||
dimStrides[i].first = dims[i];
|
||||
dimStrides[i].second = dimStrides[i + 1].second * dims[i + 1]->elementsConst();
|
||||
}
|
||||
}
|
||||
return dimStrides;
|
||||
}
|
||||
|
||||
AstNode* createAssignDpiToInternal(AstVarScope* portvscp, const string& frName) {
|
||||
// Create assignment from DPI temporary into internal format
|
||||
// DPI temporary is scalar or 1D array (if unpacked array)
|
||||
// Internal representation is scalar, 1D, or multi-dimensional array (similar to SV)
|
||||
AstVar* portp = portvscp->varp();
|
||||
string frstmt;
|
||||
bool useSetWSvlv = V3Task::dpiToInternalFrStmt(portp, frName, frstmt);
|
||||
if (useSetWSvlv) {
|
||||
AstNode* linesp = new AstText(portp->fileline(), frstmt);
|
||||
linesp->addNext(new AstVarRef(portp->fileline(), portvscp, VAccess::WRITE));
|
||||
linesp->addNext(new AstText(portp->fileline(), "," + frName + ");"));
|
||||
return new AstCStmt(portp->fileline(), linesp);
|
||||
}
|
||||
string ket;
|
||||
const bool useSetWSvlv = V3Task::dpiToInternalFrStmt(portp, frName, frstmt, ket);
|
||||
// Use a AstCMath, as we want V3Clean to mask off bits that don't make sense.
|
||||
int cwidth = VL_IDATASIZE;
|
||||
if (portp->basicp()) {
|
||||
if (!useSetWSvlv && portp->basicp()) {
|
||||
if (portp->basicp()->keyword().isBitLogic()) {
|
||||
cwidth = VL_EDATASIZE * portp->widthWords();
|
||||
} else {
|
||||
cwidth = portp->basicp()->keyword().width();
|
||||
}
|
||||
}
|
||||
AstNode* newp = new AstAssign(
|
||||
portp->fileline(), new AstVarRef(portp->fileline(), portvscp, VAccess::WRITE),
|
||||
new AstSel(portp->fileline(), new AstCMath(portp->fileline(), frstmt, cwidth, false),
|
||||
0, portp->width()));
|
||||
|
||||
const std::vector<std::pair<AstUnpackArrayDType*, int>> dimStrides
|
||||
= unpackDimsAndStrides(portvscp->varp());
|
||||
const int total = dimStrides.empty() ? 1
|
||||
: dimStrides.front().first->elementsConst()
|
||||
* dimStrides.front().second;
|
||||
AstNode* newp = nullptr;
|
||||
const int widthWords = portvscp->varp()->basicp()->widthWords();
|
||||
for (int i = 0; i < total; ++i) {
|
||||
AstNode* srcp = new AstVarRef(portvscp->fileline(), portvscp, VAccess::WRITE);
|
||||
// extract a scalar from multi-dimensional array (internal format)
|
||||
for (auto&& dimStride : dimStrides) {
|
||||
const size_t dimIdx = (i / dimStride.second) % dimStride.first->elementsConst();
|
||||
srcp = new AstArraySel(portvscp->fileline(), srcp, dimIdx);
|
||||
}
|
||||
AstNode* stmtp = nullptr;
|
||||
// extract a scalar from DPI temporary var that is scalar or 1D array
|
||||
if (useSetWSvlv) {
|
||||
AstNode* linesp = new AstText(portvscp->fileline(), frstmt + ket);
|
||||
linesp->addNext(srcp);
|
||||
linesp->addNext(
|
||||
new AstText(portvscp->fileline(),
|
||||
"," + frName + " + " + cvtToStr(i * widthWords) + ");\n"));
|
||||
stmtp = new AstCStmt(portvscp->fileline(), linesp);
|
||||
} else {
|
||||
string from = frstmt;
|
||||
if (!dimStrides.empty()) {
|
||||
// e.g. time is 64bit svLogicVector
|
||||
const int coef = portvscp->varp()->basicp()->isDpiLogicVec() ? widthWords : 1;
|
||||
from += "[" + cvtToStr(i * coef) + "]";
|
||||
}
|
||||
from += ket;
|
||||
AstNode* rhsp = new AstSel(portp->fileline(),
|
||||
new AstCMath(portp->fileline(), from, cwidth, false), 0,
|
||||
portp->width());
|
||||
stmtp = new AstAssign(portp->fileline(), srcp, rhsp);
|
||||
}
|
||||
if (i > 0) {
|
||||
newp->addNext(stmtp);
|
||||
} else {
|
||||
newp = stmtp;
|
||||
}
|
||||
}
|
||||
return newp;
|
||||
}
|
||||
|
||||
@@ -749,7 +795,10 @@ private:
|
||||
|
||||
if (portp->isNonOutput()) {
|
||||
std::string frName
|
||||
= portp->isInoutish() && portp->basicp()->isDpiPrimitive() ? "*" : "";
|
||||
= portp->isInoutish() && portp->basicp()->isDpiPrimitive()
|
||||
&& portp->dtypep()->skipRefp()->arrayUnpackedElements() == 1
|
||||
? "*"
|
||||
: "";
|
||||
frName += portp->name();
|
||||
dpip->addStmtsp(createAssignDpiToInternal(outvscp, frName));
|
||||
}
|
||||
@@ -913,7 +962,7 @@ private:
|
||||
args += "&" + name;
|
||||
} else {
|
||||
if (portp->isWritable() && portp->basicp()->isDpiPrimitive()) {
|
||||
args += "&";
|
||||
if (!VN_IS(portp->dtypep()->skipRefp(), UnpackArrayDType)) args += "&";
|
||||
}
|
||||
|
||||
args += portp->name() + tmpSuffixp;
|
||||
@@ -1532,37 +1581,76 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp)
|
||||
string V3Task::assignInternalToDpi(AstVar* portp, bool isPtr, const string& frSuffix,
|
||||
const string& toSuffix, const string& frPrefix) {
|
||||
// Create assignment from internal format into DPI temporary
|
||||
// Internal representation is scalar, 1D, or multi-dimensional array (similar to SV)
|
||||
// DPI temporary is scalar or 1D array (if unpacked array)
|
||||
string stmt;
|
||||
string ket;
|
||||
// Someday we'll have better type support, and this can make variables and casts.
|
||||
// But for now, we'll just text-bash it.
|
||||
string frName = frPrefix + portp->name() + frSuffix;
|
||||
string toName = portp->name() + toSuffix;
|
||||
if (portp->basicp()->isDpiBitVec()) {
|
||||
stmt += ("VL_SET_SVBV_" + string(portp->dtypep()->charIQWN()) + "("
|
||||
+ cvtToStr(portp->width()) + ", " + toName + ", " + frName + ")");
|
||||
} else if (portp->basicp()->isDpiLogicVec()) {
|
||||
stmt += ("VL_SET_SVLV_" + string(portp->dtypep()->charIQWN()) + "("
|
||||
+ cvtToStr(portp->width()) + ", " + toName + ", " + frName + ")");
|
||||
size_t unpackSize = 1; // non-unpacked array is treated as size 1
|
||||
int unpackDim = 0;
|
||||
if (AstUnpackArrayDType* unpackp = VN_CAST(portp->dtypep()->skipRefp(), UnpackArrayDType)) {
|
||||
unpackSize = unpackp->arrayUnpackedElements();
|
||||
unpackDim = unpackp->dimensions(false).second;
|
||||
if (unpackDim > 0) UASSERT_OBJ(unpackSize > 0, portp, "size must be greater than 0");
|
||||
}
|
||||
if (portp->basicp()->isDpiBitVec() || portp->basicp()->isDpiLogicVec()) {
|
||||
const bool isBit = portp->basicp()->isDpiBitVec();
|
||||
const string idx = portp->name() + "__Vidx";
|
||||
stmt = "for (size_t " + idx + " = 0; " + idx + " < " + cvtToStr(unpackSize) + "; ++" + idx
|
||||
+ ") ";
|
||||
stmt += (isBit ? "VL_SET_SVBV_" : "VL_SET_SVLV_")
|
||||
+ string(portp->dtypep()->skipRefp()->charIQWN()) + "(" + cvtToStr(portp->width())
|
||||
+ ", ";
|
||||
stmt += toName + " + " + cvtToStr(portp->dtypep()->skipRefp()->widthWords()) + " * " + idx
|
||||
+ ", ";
|
||||
if (unpackDim > 0) { // Access multi-dimensional array as a 1D array
|
||||
stmt += "(&" + frName;
|
||||
for (int i = 0; i < unpackDim; ++i) stmt += "[0]";
|
||||
stmt += ")[" + idx + "])";
|
||||
} else {
|
||||
stmt += frName + ")";
|
||||
}
|
||||
} else {
|
||||
if (isPtr) stmt += "*"; // DPI outputs are pointers
|
||||
stmt += toName + " = ";
|
||||
if (portp->basicp() && portp->basicp()->keyword() == AstBasicDTypeKwd::CHANDLE) {
|
||||
const bool isChandle
|
||||
= portp->basicp() && portp->basicp()->keyword() == AstBasicDTypeKwd::CHANDLE;
|
||||
const bool isString
|
||||
= portp->basicp() && portp->basicp()->keyword() == AstBasicDTypeKwd::STRING;
|
||||
const string idx = portp->name() + "__Vidx";
|
||||
stmt = "for (size_t " + idx + " = 0; " + idx + " < " + cvtToStr(unpackSize) + "; ++" + idx
|
||||
+ ") ";
|
||||
if (unpackDim > 0) {
|
||||
stmt += toName + "[" + idx + "]";
|
||||
} else {
|
||||
if (isPtr) stmt += "*"; // DPI outputs are pointers
|
||||
stmt += toName;
|
||||
}
|
||||
stmt += " = ";
|
||||
if (isChandle) {
|
||||
stmt += "VL_CVT_Q_VP(";
|
||||
ket += ")";
|
||||
}
|
||||
stmt += frName;
|
||||
if (portp->basicp() && portp->basicp()->keyword() == AstBasicDTypeKwd::STRING) {
|
||||
stmt += ".c_str()";
|
||||
if (unpackDim > 0) {
|
||||
stmt += "(&" + frName;
|
||||
for (int i = 0; i < unpackDim; ++i) stmt += "[0]";
|
||||
stmt += ")[" + idx + "]";
|
||||
} else {
|
||||
stmt += frName;
|
||||
}
|
||||
if (isString) stmt += ".c_str()";
|
||||
}
|
||||
stmt += ket + ";\n";
|
||||
return stmt;
|
||||
}
|
||||
|
||||
bool V3Task::dpiToInternalFrStmt(AstVar* portp, const string& frName, string& frstmt) {
|
||||
bool V3Task::dpiToInternalFrStmt(AstVar* portp, const string& frName, string& frstmt,
|
||||
string& ket) {
|
||||
ket.clear();
|
||||
if (portp->basicp() && portp->basicp()->keyword() == AstBasicDTypeKwd::CHANDLE) {
|
||||
frstmt = "VL_CVT_VP_Q(" + frName + ")";
|
||||
frstmt = "VL_CVT_VP_Q(" + frName;
|
||||
ket = ")";
|
||||
} else if ((portp->basicp() && portp->basicp()->isDpiPrimitive())) {
|
||||
frstmt = frName;
|
||||
} else {
|
||||
@@ -1572,8 +1660,11 @@ bool V3Task::dpiToInternalFrStmt(AstVar* portp, const string& frName, string& fr
|
||||
frstmt = "VL_SET_W_" + frSvType + "(" + cvtToStr(portp->width()) + ",";
|
||||
return true;
|
||||
} else {
|
||||
frstmt = "VL_SET_" + string(portp->dtypep()->charIQWN()) + "_" + frSvType + "("
|
||||
+ frName + ")";
|
||||
const AstNodeDType* dtypep = portp->dtypep()->skipRefp();
|
||||
frstmt = "VL_SET_" + string(dtypep->charIQWN()) + "_" + frSvType + "(";
|
||||
if (VN_IS(dtypep, UnpackArrayDType)) frstmt += "&";
|
||||
frstmt += frName;
|
||||
ket = ")";
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
+2
-1
@@ -39,7 +39,8 @@ public:
|
||||
static V3TaskConnects taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp);
|
||||
static string assignInternalToDpi(AstVar* portp, bool isPtr, const string& frSuffix,
|
||||
const string& toSuffix, const string& frPrefix = "");
|
||||
static bool dpiToInternalFrStmt(AstVar* portp, const string& frName, string& frstmt);
|
||||
static bool dpiToInternalFrStmt(AstVar* portp, const string& frName, string& frstmt,
|
||||
string& ket);
|
||||
static const char* dpiTemporaryVarSuffix();
|
||||
};
|
||||
|
||||
|
||||
@@ -4238,6 +4238,46 @@ private:
|
||||
nodep->dtypeFrom(nodep->taskp());
|
||||
// if (debug()) nodep->dumpTree(cout, " FuncOut: ");
|
||||
}
|
||||
// Returns true if dtypep0 and dtypep1 have same dimensions
|
||||
static bool areSameSize(AstUnpackArrayDType* dtypep0, AstUnpackArrayDType* dtypep1) {
|
||||
const std::vector<AstUnpackArrayDType*> dims0 = dtypep0->unpackDimensions();
|
||||
const std::vector<AstUnpackArrayDType*> dims1 = dtypep1->unpackDimensions();
|
||||
if (dims0.size() != dims1.size()) return false;
|
||||
for (size_t i = 0; i < dims0.size(); ++i) {
|
||||
if (dims0[i]->elementsConst() != dims1[i]->elementsConst()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Makes sure that port and pin have same size and same datatype
|
||||
void checkUnpackedArrayArgs(AstVar* portp, AstNode* pinp) {
|
||||
if (AstUnpackArrayDType* portDtypep
|
||||
= VN_CAST(portp->dtypep()->skipRefp(), UnpackArrayDType)) {
|
||||
if (AstUnpackArrayDType* pinDtypep
|
||||
= VN_CAST(pinp->dtypep()->skipRefp(), UnpackArrayDType)) {
|
||||
if (!areSameSize(portDtypep, pinDtypep)) {
|
||||
pinp->v3warn(E_UNSUPPORTED,
|
||||
"Shape of the argument does not match the shape of the parameter "
|
||||
<< "(" << pinDtypep->prettyDTypeNameQ() << " v.s. "
|
||||
<< portDtypep->prettyDTypeNameQ() << ")");
|
||||
}
|
||||
if (portDtypep->basicp()->width() != pinDtypep->basicp()->width()
|
||||
|| (portDtypep->basicp()->keyword() != pinDtypep->basicp()->keyword()
|
||||
&& !(portDtypep->basicp()->keyword() == AstBasicDTypeKwd::LOGIC_IMPLICIT
|
||||
&& pinDtypep->basicp()->keyword() == AstBasicDTypeKwd::LOGIC)
|
||||
&& !(portDtypep->basicp()->keyword() == AstBasicDTypeKwd::LOGIC
|
||||
&& pinDtypep->basicp()->keyword()
|
||||
== AstBasicDTypeKwd::LOGIC_IMPLICIT))) {
|
||||
pinp->v3warn(E_UNSUPPORTED,
|
||||
"Shape of the argument does not match the shape of the parameter "
|
||||
<< "(" << pinDtypep->basicp()->prettyDTypeNameQ() << " v.s. "
|
||||
<< portDtypep->basicp()->prettyDTypeNameQ() << ")");
|
||||
}
|
||||
} else {
|
||||
pinp->v3warn(E_UNSUPPORTED, "Argument is not an unpacked array while parameter "
|
||||
<< portp->prettyNameQ() << " is");
|
||||
}
|
||||
}
|
||||
}
|
||||
void processFTaskRefArgs(AstNodeFTaskRef* nodep) {
|
||||
// For arguments, is assignment-like context; see IEEE rules in AstNodeAssign
|
||||
// Function hasn't been widthed, so make it so.
|
||||
@@ -4288,6 +4328,7 @@ private:
|
||||
else if (portp->basicp() && portp->basicp()->keyword() == AstBasicDTypeKwd::STRING
|
||||
&& !VN_IS(pinp, CvtPackString)
|
||||
&& !VN_IS(pinp, SFormatF) // Already generates a string
|
||||
&& !VN_IS(portp->dtypep(), UnpackArrayDType) // Unpacked array must match
|
||||
&& !(VN_IS(pinp, VarRef)
|
||||
&& VN_CAST(pinp, VarRef)->varp()->basicp()->keyword()
|
||||
== AstBasicDTypeKwd::STRING)) {
|
||||
@@ -4311,6 +4352,7 @@ private:
|
||||
AstNode* pinp = argp->exprp();
|
||||
if (!pinp) continue; // Argument error we'll find later
|
||||
// Change data types based on above accept completion
|
||||
if (nodep->taskp()->dpiImport()) checkUnpackedArrayArgs(portp, pinp);
|
||||
if (portp->isDouble()) VL_DO_DANGLING(spliceCvtD(pinp), pinp);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user