mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
Support DPI time and svLogicVal.
Note older version incorrectly assumed svBitVal even for logicals.
This commit is contained in:
parent
27b5bfe9b1
commit
d1b8f53711
3
Changes
3
Changes
@ -8,6 +8,9 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
**** Support > 64 bit decimal $display.
|
||||
|
||||
**** Support DPI time and svLogicVal. [Victor Besyakov]
|
||||
Note older version incorrectly assumed svBitVal even for logicals.
|
||||
|
||||
**** Support string len() method. [Victor Besyakov]
|
||||
|
||||
**** Fix modport outputs being treated as inputs, bug1246. [Jeff Bush]
|
||||
|
@ -48,6 +48,12 @@
|
||||
#define _VL_SVDPI_CONTEXT_WARN() \
|
||||
VL_PRINTF_MT("%%Warning: DPI C Function called by Verilog DPI import with missing 'context' keyword.\n");
|
||||
|
||||
// Function requires svOpenArrayHandle dimensionality
|
||||
#define _VL_SVDPI_DIMENSION_CHECK(d, dimensions) \
|
||||
do { if (VL_UNLIKELY(svDimensions(d) != (dimensions))) { \
|
||||
VL_PRINTF_MT("%%Warning: %s called on array that is not %d dimensional.\n", __FUNCTION__, dimensions); \
|
||||
} } while(0)
|
||||
|
||||
//======================================================================
|
||||
//======================================================================
|
||||
//======================================================================
|
||||
@ -371,26 +377,18 @@ svLogic svGetLogicArrElem(const svOpenArrayHandle s, int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP(); return sv_x;
|
||||
}
|
||||
svLogic svGetLogicArrElem1(const svOpenArrayHandle s, int indx1) {
|
||||
_VL_SVDPI_UNIMP(); return sv_x;
|
||||
// Verilator doesn't support X/Z so can just call Bit version
|
||||
return svGetBitArrElem1(s, indx1);
|
||||
}
|
||||
svLogic svGetLogicArrElem2(const svOpenArrayHandle s, int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP(); return sv_x;
|
||||
// Verilator doesn't support X/Z so can just call Bit version
|
||||
return svGetBitArrElem2(s, indx1, indx2);
|
||||
}
|
||||
svLogic svGetLogicArrElem3(const svOpenArrayHandle s, int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP(); return sv_x;
|
||||
}
|
||||
void svPutLogicArrElem(const svOpenArrayHandle d, svLogic value, int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElem1(const svOpenArrayHandle d, svLogic value, int indx1) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElem2(const svOpenArrayHandle d, svLogic value, int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value, int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
// Verilator doesn't support X/Z so can just call Bit version
|
||||
return svGetBitArrElem3(s, indx1, indx2, indx3);
|
||||
}
|
||||
|
||||
void svPutBitArrElem(const svOpenArrayHandle d, svBit value, int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
@ -403,6 +401,21 @@ void svPutBitArrElem2(const svOpenArrayHandle d, svBit value, int indx1, int ind
|
||||
void svPutBitArrElem3(const svOpenArrayHandle d, svBit value, int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElem(const svOpenArrayHandle d, svLogic value, int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElem1(const svOpenArrayHandle d, svLogic value, int indx1) {
|
||||
// Verilator doesn't support X/Z so can just call Bit version
|
||||
svPutBitArrElem1(d, value, indx1);
|
||||
}
|
||||
void svPutLogicArrElem2(const svOpenArrayHandle d, svLogic value, int indx1, int indx2) {
|
||||
// Verilator doesn't support X/Z so can just call Bit version
|
||||
svPutBitArrElem2(d, value, indx1, indx2);
|
||||
}
|
||||
void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value, int indx1, int indx2, int indx3) {
|
||||
// Verilator doesn't support X/Z so can just call Bit version
|
||||
svPutBitArrElem3(d, value, indx1, indx2, indx3);
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Functions for working with DPI context
|
||||
|
@ -34,30 +34,46 @@
|
||||
//===================================================================
|
||||
// SETTING OPERATORS
|
||||
|
||||
/// Return svBitVecVal from WData
|
||||
static inline void VL_SET_W_SVBV(int obits, WDataOutP owp, svBitVecVal* lwp) VL_MT_SAFE {
|
||||
/// Return WData from svBitVecVal
|
||||
static inline void VL_SET_W_SVBV(int obits, WDataOutP owp, const svBitVecVal* lwp) VL_MT_SAFE {
|
||||
int words = VL_WORDS_I(obits);
|
||||
for (int i=0; i<words-1; ++i) owp[i]=lwp[i];
|
||||
owp[words-1] = lwp[words-1] & VL_MASK_I(obits);
|
||||
}
|
||||
/// Return svBitVecVal from WData
|
||||
static inline void VL_SET_SVBV_W(int obits, svBitVecVal* owp, WDataInP lwp) VL_MT_SAFE {
|
||||
int words = VL_WORDS_I(obits);
|
||||
for (int i=0; i<words-1; ++i) owp[i]=lwp[i];
|
||||
owp[words-1] = lwp[words-1] & VL_MASK_I(obits);
|
||||
}
|
||||
static inline void VL_SET_W_SVLV(int obits, WDataOutP owp, svLogicVecVal* lwp) VL_MT_SAFE {
|
||||
// Note we ignore X/Z in svLogicVecVal
|
||||
|
||||
/// Convert svLogicVecVal to/from WData
|
||||
/// Note these functions ignore X/Z in svLogicVecVal
|
||||
static inline void VL_SET_W_SVLV(int obits, WDataOutP owp, const svLogicVecVal* lwp) VL_MT_SAFE {
|
||||
int words = VL_WORDS_I(obits);
|
||||
for (int i=0; i<words-1; ++i) owp[i]=lwp[i].aval;
|
||||
owp[words-1] = lwp[words-1].aval & VL_MASK_I(obits);
|
||||
}
|
||||
static inline QData VL_SET_Q_SVLV(const svLogicVecVal* lwp) VL_MT_SAFE {
|
||||
return _VL_SET_QII(lwp[1].aval, lwp[0].aval);
|
||||
}
|
||||
static inline IData VL_SET_I_SVLV(const svLogicVecVal* lwp) VL_MT_SAFE {
|
||||
return lwp[0].aval;
|
||||
}
|
||||
static inline void VL_SET_SVLV_W(int obits, svLogicVecVal* owp, WDataInP lwp) VL_MT_SAFE {
|
||||
// Note we don't create X/Z in svLogicVecVal
|
||||
int words = VL_WORDS_I(obits);
|
||||
for (int i=0; i<words; ++i) owp[i].bval=0;
|
||||
for (int i=0; i<words-1; ++i) owp[i].aval=lwp[i];
|
||||
owp[words-1].aval = lwp[words-1] & VL_MASK_I(obits);
|
||||
}
|
||||
static inline void VL_SET_SVLV_I(int obits, svLogicVecVal* owp, IData ld) VL_MT_SAFE {
|
||||
owp[0].aval=ld; owp[0].bval=0;
|
||||
}
|
||||
static inline void VL_SET_SVLV_Q(int obits, svLogicVecVal* owp, QData ld) VL_MT_SAFE {
|
||||
WData lwp[2]; VL_SET_WQ(lwp,ld);
|
||||
owp[0].aval=lwp[0]; owp[0].bval=0;
|
||||
owp[1].aval=lwp[1]; owp[1].bval=0;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
||||
|
23
src/V3Ast.h
23
src/V3Ast.h
@ -418,11 +418,17 @@ public:
|
||||
bool isBitLogic() const { // Bit/logic vector types; can form a packed array
|
||||
return (m_e==LOGIC || m_e==BIT);
|
||||
}
|
||||
bool isDpiUnsupported() const {
|
||||
return (m_e==TIME);
|
||||
bool isDpiBitVal() const { // DPI uses svBitVecVal
|
||||
return m_e==BIT;
|
||||
}
|
||||
bool isDpiLogicVal() const { // DPI uses svLogicVecVal
|
||||
return m_e==INTEGER || m_e==LOGIC || m_e==LOGIC_IMPLICIT || m_e==TIME;
|
||||
}
|
||||
bool isDpiUnreturnable() const { // Not legal as DPI function return
|
||||
return isDpiLogicVal();
|
||||
}
|
||||
bool isDpiUnsignable() const { // Can add "unsigned" to DPI
|
||||
return (m_e==BYTE || m_e==SHORTINT || m_e==INT || m_e==LONGINT || m_e==INTEGER);
|
||||
return (m_e==BYTE || m_e==SHORTINT || m_e==INT || m_e==LONGINT || m_e==INTEGER);
|
||||
}
|
||||
bool isOpaque() const { // IE not a simple number we can bit optimize
|
||||
return (m_e==STRING || m_e==SCOPEPTR || m_e==CHARPTR || m_e==DOUBLE || m_e==FLOAT);
|
||||
@ -1717,6 +1723,7 @@ public:
|
||||
virtual void virtRefDTypep(AstNodeDType* nodep) { } // Iff has refDTypep(), set as generic node function
|
||||
virtual bool similarDType(AstNodeDType* samep) const = 0; // Assignable equivalence. Call skipRefp() on this and samep before calling
|
||||
virtual AstNodeDType* subDTypep() const { return NULL; } // Iff has a non-null subDTypep(), as generic node function
|
||||
virtual bool isFourstate() const;
|
||||
//
|
||||
// Changing the width may confuse the data type resolution, so must clear TypeTable cache after use.
|
||||
void widthForce(int width, int sized) { m_width=width; m_widthMin=sized; }
|
||||
@ -1748,19 +1755,23 @@ private:
|
||||
typedef map<string,AstMemberDType*> MemberNameMap;
|
||||
// MEMBERS
|
||||
bool m_packed;
|
||||
bool m_isFourstate;
|
||||
MemberNameMap m_members;
|
||||
public:
|
||||
AstNodeClassDType(FileLine* fl, AstNumeric numericUnpack)
|
||||
: AstNodeDType(fl) {
|
||||
// AstNumeric::NOSIGN overloaded to indicate not packed
|
||||
m_packed = (numericUnpack != AstNumeric::NOSIGN);
|
||||
m_isFourstate = false; // V3Width computes
|
||||
numeric(numericUnpack.isSigned() ? AstNumeric::SIGNED : AstNumeric::UNSIGNED);
|
||||
}
|
||||
ASTNODE_BASE_FUNCS(NodeClassDType)
|
||||
virtual const char* broken() const;
|
||||
virtual void dump(ostream& str);
|
||||
// For basicp() we reuse the size to indicate a "fake" basic type of same size
|
||||
virtual AstBasicDType* basicp() const { return findLogicDType(width(),width(),numeric())->castBasicDType(); }
|
||||
virtual AstBasicDType* basicp() const {
|
||||
return (isFourstate() ? findLogicDType(width(),width(),numeric())->castBasicDType()
|
||||
: findBitDType(width(),width(),numeric())->castBasicDType()); }
|
||||
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
|
||||
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
|
||||
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
|
||||
@ -1774,6 +1785,8 @@ public:
|
||||
void addMembersp(AstNode* nodep) { addNOp1p(nodep); }
|
||||
bool packed() const { return m_packed; }
|
||||
bool packedUnsup() const { return true; } // packed() but as don't support unpacked, presently all structs
|
||||
void isFourstate(bool flag) { m_isFourstate = flag; }
|
||||
virtual bool isFourstate() const { return m_isFourstate; }
|
||||
void clearCache() { m_members.clear(); }
|
||||
void repairMemberCache();
|
||||
AstMemberDType* findMember(const string& name) const {
|
||||
@ -2061,6 +2074,8 @@ inline bool AstNode::sameGateTree(AstNode* node2p) { return sameTreeIter(this, n
|
||||
|
||||
inline void AstNodeVarRef::init() { if (m_varp) dtypep(m_varp->dtypep()); }
|
||||
|
||||
inline bool AstNodeDType::isFourstate() const { return basicp()->isFourstate(); }
|
||||
|
||||
inline void AstNodeArrayDType::rangep(AstRange* nodep) { setOp2p(nodep); }
|
||||
inline int AstNodeArrayDType::msb() const { return rangep()->msbConst(); }
|
||||
inline int AstNodeArrayDType::lsb() const { return rangep()->lsbConst(); }
|
||||
|
@ -314,7 +314,7 @@ string AstVar::dpiArgType(bool named, bool forReturn) const {
|
||||
if (forReturn) named=false;
|
||||
string arg;
|
||||
if (!basicp()) arg = "UNKNOWN";
|
||||
if (basicp()->isBitLogic()) {
|
||||
else if (basicp()->keyword().isDpiBitVal()) {
|
||||
if (widthMin() == 1) {
|
||||
arg = "unsigned char";
|
||||
if (!forReturn && isOutput()) arg += "*";
|
||||
@ -327,6 +327,19 @@ string AstVar::dpiArgType(bool named, bool forReturn) const {
|
||||
arg = "svBitVecVal*";
|
||||
}
|
||||
}
|
||||
} else if (basicp()->keyword().isDpiLogicVal()) {
|
||||
if (widthMin() == 1) {
|
||||
arg = "unsigned char";
|
||||
if (!forReturn && isOutput()) arg += "*";
|
||||
} else {
|
||||
if (forReturn) {
|
||||
arg = "svLogicVecVal";
|
||||
} else if (isInOnly()) {
|
||||
arg = "const svLogicVecVal*";
|
||||
} else {
|
||||
arg = "svLogicVecVal*";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
arg = basicp()->keyword().dpiType();
|
||||
if (basicp()->keyword().isDpiUnsignable() && !basicp()->isSigned()) {
|
||||
@ -851,6 +864,7 @@ void AstRefDType::dump(ostream& str) {
|
||||
void AstNodeClassDType::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (packed()) str<<" [PACKED]";
|
||||
if (isFourstate()) str<<" [4STATE]";
|
||||
}
|
||||
void AstNodeDType::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
|
@ -426,6 +426,7 @@ public:
|
||||
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
|
||||
virtual int widthAlignBytes() const; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
|
||||
virtual int widthTotalBytes() const; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
|
||||
virtual bool isFourstate() const { return keyword().isFourstate(); }
|
||||
AstBasicDTypeKwd keyword() const { return m.m_keyword; } // Avoid using - use isSomething accessors instead
|
||||
bool isBitLogic() const { return keyword().isBitLogic(); }
|
||||
bool isDouble() const { return keyword().isDouble(); }
|
||||
|
@ -578,12 +578,16 @@ private:
|
||||
}
|
||||
|
||||
AstNode* createDpiTemp(AstVar* portp, const string& suffix) {
|
||||
bool bitvec = (portp->basicp()->isBitLogic() && portp->width() > 32);
|
||||
bool bitvec = (portp->basicp()->keyword().isDpiBitVal() && portp->width() > 32);
|
||||
bool logicvec = (portp->basicp()->keyword().isDpiLogicVal() && portp->width() > 1);
|
||||
string stmt;
|
||||
if (bitvec) {
|
||||
stmt += "svBitVecVal "+portp->name()+suffix;
|
||||
stmt += " ["+cvtToStr(portp->widthWords())+"]";
|
||||
} else {
|
||||
} else if (logicvec) {
|
||||
stmt += "svLogicVecVal "+portp->name()+suffix;
|
||||
stmt += " ["+cvtToStr(portp->widthWords())+"]";
|
||||
} else {
|
||||
stmt += portp->dpiArgType(true,true);
|
||||
stmt += " "+portp->name()+suffix;
|
||||
}
|
||||
@ -594,11 +598,12 @@ private:
|
||||
AstNode* createAssignInternalToDpi(AstVar* portp, bool isRtn, bool isPtr,
|
||||
const string& frSuffix, const string& toSuffix) {
|
||||
// Create assignment from internal format into DPI temporary
|
||||
bool bitvec = (portp->basicp()->isBitLogic() && portp->width() > 32);
|
||||
if (isRtn && bitvec) {
|
||||
portp->v3error("DPI functions cannot return > 32 bits; use a two-state type or task instead: "<<portp->prettyName());
|
||||
// Code below works, but won't compile right, and IEEE illegal
|
||||
}
|
||||
bool bitvec = (portp->basicp()->keyword().isDpiBitVal() && portp->width() > 32);
|
||||
bool logicvec = (portp->basicp()->keyword().isDpiLogicVal() && portp->width() > 1);
|
||||
if (isRtn && (bitvec || logicvec)) {
|
||||
portp->v3error("DPI functions cannot return > 32 bits or four-state; use a two-state type or task instead: "<<portp->prettyName());
|
||||
// Code below works, but won't compile right, and IEEE illegal
|
||||
}
|
||||
string stmt;
|
||||
string ket;
|
||||
// Someday we'll have better type support, and this can make variables and casts.
|
||||
@ -610,6 +615,10 @@ private:
|
||||
} else {
|
||||
stmt += "VL_SET_WQ("+portp->name()+toSuffix+", "+portp->name()+frSuffix+")";
|
||||
}
|
||||
} else if (logicvec) {
|
||||
stmt += ("VL_SET_SVLV_" + string(portp->dtypep()->charIQWN()) + "("
|
||||
+ cvtToStr(portp->width())
|
||||
+ ", "+portp->name()+toSuffix+", "+portp->name()+frSuffix+")");
|
||||
} else {
|
||||
if (isPtr) stmt += "*"; // DPI outputs are pointers
|
||||
stmt += portp->name()+toSuffix+" = ";
|
||||
@ -629,29 +638,41 @@ private:
|
||||
AstNode* createAssignDpiToInternal(AstVarScope* portvscp, const string& frName, bool cvt) {
|
||||
// Create assignment from DPI temporary into internal format
|
||||
AstVar* portp = portvscp->varp();
|
||||
string stmt;
|
||||
string ket;
|
||||
if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::CHANDLE) {
|
||||
stmt += "VL_CVT_VP_Q(";
|
||||
ket += ")";
|
||||
string frstmt;
|
||||
if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::CHANDLE) {
|
||||
frstmt = "VL_CVT_VP_Q("+frName+")";
|
||||
}
|
||||
else if (portp->basicp() && portp->basicp()->keyword().isDpiBitVal() && portp->width() != 1 && portp->isQuad()) {
|
||||
// SV is vector, Verilator isn't
|
||||
frstmt = "VL_SET_QW("+frName+")";
|
||||
}
|
||||
else if (portp->basicp() && portp->basicp()->keyword().isDpiLogicVal() && portp->width() != 1 && portp->isQuad()) {
|
||||
frstmt = "VL_SET_Q_SVLV("+frName+")";
|
||||
}
|
||||
else if (portp->basicp() && portp->basicp()->keyword().isDpiLogicVal() && portp->width() != 1 && !portp->isWide()) {
|
||||
frstmt = "VL_SET_I_SVLV("+frName+")";
|
||||
}
|
||||
else if (!cvt
|
||||
&& portp->basicp() && portp->basicp()->keyword().isDpiBitVal() && portp->width() != 1 && !portp->isWide()) {
|
||||
frstmt = "*"+frName; // it's a svBitVecVal, which other code won't think is arrayed (as WData aren't), but really is
|
||||
}
|
||||
else if (portp->basicp() && portp->basicp()->keyword().isDpiLogicVal() && portp->width() != 1 && portp->isWide()) {
|
||||
// Need to convert to wide, using special function
|
||||
AstNode* linesp = new AstText(portp->fileline(), "VL_SET_W_SVLV("+cvtToStr(portp->width()) + ",");
|
||||
linesp->addNext(new AstVarRef(portp->fileline(), portvscp, true));
|
||||
linesp->addNext(new AstText(portp->fileline(), ","+frName+");"));
|
||||
return new AstCStmt(portp->fileline(), linesp);
|
||||
}
|
||||
else {
|
||||
frstmt = frName;
|
||||
}
|
||||
else if (portp->basicp() && portp->basicp()->isBitLogic() && portp->width() != 1 && portp->isQuad()) {
|
||||
// SV is vector, Verilator isn't
|
||||
stmt += "VL_SET_QW(";
|
||||
ket += ")";
|
||||
}
|
||||
if (!cvt
|
||||
&& portp->basicp() && portp->basicp()->isBitLogic() && portp->width() != 1 && !portp->isWide() && !portp->isQuad())
|
||||
stmt += "*"; // it's a svBitVecVal, which other code won't think is arrayed (as WData aren't), but really is
|
||||
stmt += frName;
|
||||
stmt += ket;
|
||||
// Use a AstCMath, as we want V3Clean to mask off bits that don't make sense.
|
||||
int cwidth = VL_WORDSIZE; if (portp->basicp()) cwidth = portp->basicp()->keyword().width();
|
||||
if (portp->basicp() && portp->basicp()->isBitLogic()) cwidth = VL_WORDSIZE*portp->widthWords();
|
||||
if (portp->basicp() && portp->basicp()->keyword().isBitLogic()) cwidth = VL_WORDSIZE*portp->widthWords();
|
||||
AstNode* newp = new AstAssign(portp->fileline(),
|
||||
new AstVarRef(portp->fileline(), portvscp, true),
|
||||
new AstSel(portp->fileline(),
|
||||
new AstCMath(portp->fileline(), stmt, cwidth, false),
|
||||
new AstCMath(portp->fileline(), frstmt, cwidth, false),
|
||||
0, portp->width()));
|
||||
return newp;
|
||||
}
|
||||
@ -785,12 +806,15 @@ private:
|
||||
&& portp->name() != "__Vscopep" // Passed to dpiContext, not callee
|
||||
&& portp->name() != "__Vfilenamep"
|
||||
&& portp->name() != "__Vlineno") {
|
||||
bool bitvec = (portp->basicp()->isBitLogic() && portp->width() > 32);
|
||||
bool bitvec = (portp->basicp()->keyword().isDpiBitVal() && portp->width() > 32);
|
||||
bool logicvec = (portp->basicp()->keyword().isDpiLogicVal() && portp->width() > 1);
|
||||
|
||||
if (args != "") { args+= ", "; }
|
||||
if (bitvec) {}
|
||||
else if (portp->isOutput()) args += "&";
|
||||
else if (portp->basicp() && portp->basicp()->isBitLogic() && portp->width() != 1) args += "&"; // it's a svBitVecVal
|
||||
else if (logicvec) {}
|
||||
else if (portp->isOutput()) args += "&";
|
||||
else if (portp->basicp() && portp->basicp()->keyword().isDpiBitVal()
|
||||
&& portp->width() != 1) args += "&"; // it's a svBitVecVal (2-32 bits wide)
|
||||
|
||||
args += portp->name()+"__Vcvt";
|
||||
|
||||
@ -841,6 +865,12 @@ private:
|
||||
if (!portp->isFuncReturn()) nodep->v3error("Not marked as function return var");
|
||||
if (portp->isWide()) nodep->v3error("Unsupported: Public functions with return > 64 bits wide. (Make it a output instead.)");
|
||||
if (ftaskNoInline || nodep->dpiExport()) portp->funcReturn(false); // Converting return to 'outputs'
|
||||
if ((nodep->dpiImport() || nodep->dpiExport())
|
||||
&& portp->dtypep()->basicp()
|
||||
&& portp->dtypep()->basicp()->keyword().isDpiUnreturnable()) {
|
||||
portp->v3error("DPI function may not return type "<<portp->basicp()->prettyTypeName()
|
||||
<<" (IEEE 2012 35.5.5)");
|
||||
}
|
||||
portp->unlinkFrBack();
|
||||
rtnvarp = portp;
|
||||
rtnvarp->funcLocal(true);
|
||||
@ -942,7 +972,7 @@ private:
|
||||
cfuncp->addArgsp(portp);
|
||||
if (dpip) {
|
||||
dpip->addArgsp(portp->cloneTree(false));
|
||||
if (!portp->basicp() || portp->basicp()->keyword().isDpiUnsupported()) {
|
||||
if (!portp->basicp()) {
|
||||
portp->v3error("Unsupported: DPI argument of type "<<portp->basicp()->prettyTypeName()<<endl
|
||||
<<portp->warnMore()<<"... For best portability, use bit, byte, int, or longint");
|
||||
// We don't warn on logic either, although the 4-stateness is lost.
|
||||
|
@ -1105,7 +1105,7 @@ private:
|
||||
// So two steps, first do the calculation's width (max of the two widths)
|
||||
{
|
||||
int calcWidth = max(width, underDtp->width());
|
||||
AstNodeDType* calcDtp = (underDtp->keyword().isFourstate()
|
||||
AstNodeDType* calcDtp = (underDtp->isFourstate()
|
||||
? nodep->findLogicDType(calcWidth, calcWidth, underDtp->numeric())
|
||||
: nodep->findBitDType(calcWidth, calcWidth, underDtp->numeric()));
|
||||
nodep->dtypep(calcDtp);
|
||||
@ -1115,7 +1115,7 @@ private:
|
||||
if (debug()) nodep->dumpTree(cout," CastSizeClc: ");
|
||||
// Next step, make the proper output width
|
||||
{
|
||||
AstNodeDType* outDtp = (underDtp->keyword().isFourstate()
|
||||
AstNodeDType* outDtp = (underDtp->isFourstate()
|
||||
? nodep->findLogicDType(width, width, underDtp->numeric())
|
||||
: nodep->findBitDType(width, width, underDtp->numeric()));
|
||||
nodep->dtypep(outDtp);
|
||||
@ -1413,10 +1413,12 @@ private:
|
||||
nodep->dtypep(nodep);
|
||||
int lsb = 0;
|
||||
int width = 0;
|
||||
nodep->isFourstate(false);
|
||||
// MSB is first, so go backwards
|
||||
AstMemberDType* itemp;
|
||||
for (itemp = nodep->membersp(); itemp && itemp->nextp(); itemp=itemp->nextp()->castMemberDType()) ;
|
||||
for (AstMemberDType* backip; itemp; itemp=backip) {
|
||||
if (nodep->isFourstate()) nodep->isFourstate(true);
|
||||
backip = itemp->backp()->castMemberDType();
|
||||
itemp->lsb(lsb);
|
||||
if (nodep->castUnionDType()) {
|
||||
|
@ -11,7 +11,7 @@ compile (
|
||||
v_flags2 => ["--lint-only"],
|
||||
fails=>$Self->{v3},
|
||||
expect=>
|
||||
'%Error: t/t_dpi_exp_bad.v:\d+: DPI functions cannot return > 32 bits; use a two-state type or task instead: dpix_f_bit48__Vfuncrtn
|
||||
'%Error: t/t_dpi_exp_bad.v:\d+: DPI functions cannot return > 32 bits or four-state; use a two-state type or task instead: dpix_f_bit48__Vfuncrtn
|
||||
%Error: Exiting due to .*'
|
||||
);
|
||||
|
||||
|
@ -5,6 +5,13 @@
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
|
||||
`ifdef VCS
|
||||
`define NO_TIME
|
||||
`endif
|
||||
`ifdef NC
|
||||
`define NO_TIME
|
||||
`endif
|
||||
|
||||
module t;
|
||||
|
||||
sub a (.inst(1));
|
||||
@ -20,7 +27,7 @@ module t;
|
||||
task dpix_t_ren(input int i, output int o); o = i+2; endtask
|
||||
|
||||
export "DPI-C" function dpix_int123;
|
||||
function int dpix_int123(); dpix_int123 = 32'h123; endfunction
|
||||
function int dpix_int123(); dpix_int123 = 32'h123; endfunction
|
||||
|
||||
export "DPI-C" function dpix_f_bit;
|
||||
export "DPI-C" function dpix_f_bit15;
|
||||
@ -30,13 +37,13 @@ module t;
|
||||
export "DPI-C" function dpix_f_longint;
|
||||
export "DPI-C" function dpix_f_chandle;
|
||||
|
||||
function bit dpix_f_bit (bit i); dpix_f_bit = ~i; endfunction
|
||||
function bit [14:0] dpix_f_bit15 (bit [14:0] i); dpix_f_bit15 = ~i; endfunction
|
||||
function int dpix_f_int (int i); dpix_f_int = ~i; endfunction
|
||||
function byte dpix_f_byte (byte i); dpix_f_byte = ~i; endfunction
|
||||
function shortint dpix_f_shortint(shortint i); dpix_f_shortint = ~i; endfunction
|
||||
function longint dpix_f_longint (longint i); dpix_f_longint = ~i; endfunction
|
||||
function chandle dpix_f_chandle (chandle i); dpix_f_chandle = i; endfunction
|
||||
function bit dpix_f_bit (bit i); dpix_f_bit = ~i; endfunction
|
||||
function bit [14:0] dpix_f_bit15 (bit [14:0] i); dpix_f_bit15 = ~i; endfunction
|
||||
function int dpix_f_int (int i); dpix_f_int = ~i; endfunction
|
||||
function byte dpix_f_byte (byte i); dpix_f_byte = ~i; endfunction
|
||||
function shortint dpix_f_shortint(shortint i); dpix_f_shortint = ~i; endfunction
|
||||
function longint dpix_f_longint (longint i); dpix_f_longint = ~i; endfunction
|
||||
function chandle dpix_f_chandle (chandle i); dpix_f_chandle = i; endfunction
|
||||
|
||||
export "DPI-C" task dpix_t_bit48;
|
||||
task dpix_t_bit48(input bit [47:0] i, output bit [47:0] o); o = ~i; endtask
|
||||
@ -45,13 +52,26 @@ module t;
|
||||
export "DPI-C" task dpix_t_bit96;
|
||||
task dpix_t_bit96(input bit [95:0] i, output bit [95:0] o); o = ~i; endtask
|
||||
|
||||
export "DPI-C" task dpix_t_reg;
|
||||
task dpix_t_reg(input reg i, output reg o); o = ~i; endtask
|
||||
export "DPI-C" task dpix_t_reg15;
|
||||
task dpix_t_reg15(input reg [14:0] i, output reg [14:0] o); o = ~i; endtask
|
||||
export "DPI-C" task dpix_t_reg95;
|
||||
task dpix_t_reg95(input reg [94:0] i, output reg [94:0] o); o = ~i; endtask
|
||||
export "DPI-C" task dpix_t_integer;
|
||||
task dpix_t_integer(input integer i, output integer o); o = ~i; endtask
|
||||
`ifndef NO_TIME
|
||||
export "DPI-C" task dpix_t_time;
|
||||
`endif
|
||||
task dpix_t_time(input time i, output time o); o = ~i; endtask
|
||||
|
||||
int lineno;
|
||||
|
||||
initial begin
|
||||
lineno = dpix_run_tests();
|
||||
if (lineno != -1) begin
|
||||
$display("[%0t] %%Error: t_dpix_ort_c.c:%0d: dpix_run_tests returned an error", $time, lineno);
|
||||
$stop;
|
||||
$display("[%0t] %%Error: t_dpix_ort_c.c:%0d: dpix_run_tests returned an error", $time, lineno);
|
||||
$stop;
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
@ -64,6 +84,6 @@ module sub (input int inst);
|
||||
|
||||
export "DPI-C" function dpix_sub_inst;
|
||||
|
||||
function int dpix_sub_inst (int i); dpix_sub_inst = inst + i; endfunction
|
||||
function int dpix_sub_inst (int i); dpix_sub_inst = inst + i; endfunction
|
||||
|
||||
endmodule
|
||||
|
@ -55,6 +55,12 @@ extern "C" {
|
||||
extern void* dpix_f_chandle(void* i);
|
||||
|
||||
extern int dpix_sub_inst (int i);
|
||||
|
||||
extern void dpix_t_reg(svLogic i, svLogic* o);
|
||||
extern void dpix_t_reg15(const svLogicVecVal* i, svLogicVecVal* o);
|
||||
extern void dpix_t_reg95(const svLogicVecVal* i, svLogicVecVal* o);
|
||||
extern void dpix_t_integer(const svLogicVecVal* i, svLogicVecVal* o);
|
||||
extern void dpix_t_time(const svLogicVecVal* i, svLogicVecVal* o);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -166,6 +172,51 @@ int dpix_run_tests() {
|
||||
CHECK_RESULT(int, o_vec96[2], ~i_vec96[2]);
|
||||
}
|
||||
|
||||
extern void dpix_t_reg(svLogic i, svLogic* o);
|
||||
{
|
||||
svLogic i = 0;
|
||||
svLogic o;
|
||||
dpix_t_reg(i, &o);
|
||||
CHECK_RESULT(svLogic, o, 1);
|
||||
i = 1;
|
||||
dpix_t_reg(i, &o);
|
||||
CHECK_RESULT(svLogic, o, 0);
|
||||
}
|
||||
{
|
||||
svLogicVecVal i[1]; i[0].aval = 0x12; i[0].bval = 0;
|
||||
svLogicVecVal o[1];
|
||||
dpix_t_reg15(i, o);
|
||||
CHECK_RESULT(int, o[0].aval, (~i[0].aval) & 0x7fff);
|
||||
CHECK_RESULT(int, o[0].bval, 0);
|
||||
}
|
||||
{
|
||||
svLogicVecVal i[3];
|
||||
i[0].aval = 0x72912312; i[0].bval = 0;
|
||||
i[1].aval = 0xab782a12; i[1].bval = 0;
|
||||
i[2].aval = 0x8a413bd9; i[2].bval = 0;
|
||||
svLogicVecVal o[3];
|
||||
dpix_t_reg95(i, o);
|
||||
CHECK_RESULT(int, o[0].aval, ~i[0].aval);
|
||||
CHECK_RESULT(int, o[1].aval, ~i[1].aval);
|
||||
CHECK_RESULT(int, o[2].aval, (~i[2].aval)&0x7fffffffUL);
|
||||
CHECK_RESULT(int, o[0].bval, 0);
|
||||
CHECK_RESULT(int, o[1].bval, 0);
|
||||
CHECK_RESULT(int, o[2].bval, 0);
|
||||
}
|
||||
#if !defined(VCS) && !defined(CADENCE)
|
||||
{
|
||||
svLogicVecVal i[2];
|
||||
i[0].aval = 0x72912312; i[0].bval = 0;
|
||||
i[1].aval = 0xab782a12; i[1].bval = 0;
|
||||
svLogicVecVal o[2];
|
||||
dpix_t_time(i, o);
|
||||
CHECK_RESULT(int, o[0].aval, ~i[0].aval);
|
||||
CHECK_RESULT(int, o[1].aval, ~i[1].aval);
|
||||
CHECK_RESULT(int, o[0].bval, 0);
|
||||
CHECK_RESULT(int, o[1].bval, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (int bad=check_sub("top.t.a",1)) return bad;
|
||||
if (int bad=check_sub("top.t.b",2)) return bad;
|
||||
|
||||
|
@ -7,9 +7,11 @@
|
||||
|
||||
`ifdef VCS
|
||||
`define NO_SHORTREAL
|
||||
`define NO_TIME
|
||||
`endif
|
||||
`ifdef NC
|
||||
`define NO_SHORTREAL
|
||||
`define NO_TIME
|
||||
`endif
|
||||
`ifdef VERILATOR // Unsupported
|
||||
`define NO_SHORTREAL
|
||||
@ -72,6 +74,14 @@ module t (/*AUTOARG*/
|
||||
import "DPI-C" pure function void dpii_v_bit95 (input bit [95-1:0] i, output bit [95-1:0] o);
|
||||
import "DPI-C" pure function void dpii_v_bit96 (input bit [96-1:0] i, output bit [96-1:0] o);
|
||||
|
||||
import "DPI-C" pure function void dpii_v_reg (input reg i, output reg o);
|
||||
import "DPI-C" pure function void dpii_v_reg15 (input reg [14:0] i, output reg [14:0] o);
|
||||
import "DPI-C" pure function void dpii_v_reg95 (input reg [94:0] i, output reg [94:0] o);
|
||||
import "DPI-C" pure function void dpii_v_integer (input integer i, output integer o);
|
||||
`ifndef NO_TIME
|
||||
import "DPI-C" pure function void dpii_v_time (input time i, output time o);
|
||||
`endif
|
||||
|
||||
import "DPI-C" pure function int dpii_f_strlen (input string i);
|
||||
|
||||
import "DPI-C" function void dpii_f_void ();
|
||||
@ -116,6 +126,12 @@ module t (/*AUTOARG*/
|
||||
shortreal i_f, o_f;
|
||||
`endif
|
||||
|
||||
reg i_r, o_r;
|
||||
reg [14:0] i_r15, o_r15;
|
||||
reg [94:0] i_r95, o_r95;
|
||||
integer i_in, o_in;
|
||||
time i_tm, o_tm;
|
||||
|
||||
bit [94:0] wide;
|
||||
|
||||
bit [6*8:1] string6;
|
||||
@ -151,6 +167,12 @@ module t (/*AUTOARG*/
|
||||
i_f = 30.2;
|
||||
`endif
|
||||
|
||||
i_r = '0;
|
||||
i_r15 = wide[14:0];
|
||||
i_r95 = wide[94:0];
|
||||
i_in = -1234;
|
||||
i_tm = 62;
|
||||
|
||||
if (dpii_f_bit (i_b) !== ~i_b) $stop;
|
||||
if (dpii_f_bit8 (i_b8) !== ~i_b8) $stop;
|
||||
if (dpii_f_bit9 (i_b9) !== ~i_b9) $stop;
|
||||
@ -198,6 +220,14 @@ module t (/*AUTOARG*/
|
||||
dpii_v_bit95 (i_b95,o_b95); if (o_b95 !== ~i_b95) $stop;
|
||||
dpii_v_bit96 (i_b96,o_b96); if (o_b96 !== ~i_b96) $stop;
|
||||
|
||||
dpii_v_reg (i_r,o_r); if (o_r !== ~i_r) $stop;
|
||||
dpii_v_reg15 (i_r15,o_r15); if (o_r15 !== ~i_r15) $stop;
|
||||
dpii_v_reg95 (i_r95,o_r95); if (o_r95 !== ~i_r95) $stop;
|
||||
dpii_v_integer (i_in,o_in); if (o_in != ~i_in) $stop;
|
||||
`ifndef NO_TIME
|
||||
dpii_v_time (i_tm,o_tm); if (o_tm != ~i_tm) $stop;
|
||||
`endif
|
||||
|
||||
if (dpii_f_strlen ("")!=0) $stop;
|
||||
if (dpii_f_strlen ("s")!=1) $stop;
|
||||
if (dpii_f_strlen ("st")!=2) $stop;
|
||||
|
@ -75,6 +75,12 @@ extern "C" {
|
||||
extern void dpii_v_bit95(const svBitVecVal* i, svBitVecVal* o);
|
||||
extern void dpii_v_bit96(const svBitVecVal* i, svBitVecVal* o);
|
||||
|
||||
extern void dpii_v_reg(unsigned char i, unsigned char* o);
|
||||
extern void dpii_v_reg15(const svLogicVecVal* i, svLogicVecVal* o);
|
||||
extern void dpii_v_reg95(const svLogicVecVal* i, svLogicVecVal* o);
|
||||
extern void dpii_v_integer(const svLogicVecVal* i, svLogicVecVal* o);
|
||||
extern void dpii_v_time(const svLogicVecVal* i, svLogicVecVal* o);
|
||||
|
||||
extern int dpii_f_strlen (const char* i);
|
||||
|
||||
extern void dpii_f_void ();
|
||||
@ -88,12 +94,12 @@ extern "C" {
|
||||
|
||||
//======================================================================
|
||||
|
||||
unsigned char dpii_f_bit (unsigned char i) { return VL_MASK_I(1) & ~i; }
|
||||
svBitVecVal dpii_f_bit8 (const svBitVecVal *i) { return VL_MASK_I(8) & ~*i; }
|
||||
svBitVecVal dpii_f_bit9 (const svBitVecVal *i) { return VL_MASK_I(9) & ~*i; }
|
||||
svBitVecVal dpii_f_bit16(const svBitVecVal *i) { return VL_MASK_I(16) & ~*i; }
|
||||
svBitVecVal dpii_f_bit17(const svBitVecVal *i) { return VL_MASK_I(17) & ~*i; }
|
||||
svBitVecVal dpii_f_bit32(const svBitVecVal *i) { return ~*i; }
|
||||
unsigned char dpii_f_bit (unsigned char i) { return 0x1 & ~i; }
|
||||
svBitVecVal dpii_f_bit8 (const svBitVecVal *i) { return 0xffUL & ~*i; }
|
||||
svBitVecVal dpii_f_bit9 (const svBitVecVal *i) { return 0x1ffUL & ~*i; }
|
||||
svBitVecVal dpii_f_bit16(const svBitVecVal *i) { return 0xffffUL & ~*i; }
|
||||
svBitVecVal dpii_f_bit17(const svBitVecVal *i) { return 0x1ffffUL & ~*i; }
|
||||
svBitVecVal dpii_f_bit32(const svBitVecVal *i) { return ~*i; }
|
||||
long long dpii_f_bit33(const svBitVecVal *i) { return ((1ULL<<33)-1) & ~((long long)(i[1])<<32ULL | i[0]); }
|
||||
long long dpii_f_bit64(const svBitVecVal *i) { return ~((long long)(i[1])<<32ULL | i[0]); }
|
||||
|
||||
@ -106,7 +112,7 @@ const char* dpii_f_string (const char* i) { return i; }
|
||||
double dpii_f_real (double i) { return i+1.5; }
|
||||
float dpii_f_shortreal(float i) { return i+1.5f; }
|
||||
|
||||
void dpii_v_bit (unsigned char i, unsigned char *o) { *o = VL_MASK_I(1) & ~i; }
|
||||
void dpii_v_bit (unsigned char i, unsigned char *o) { *o = 1 & ~i; }
|
||||
void dpii_v_int (int i, int *o) { *o = ~i; }
|
||||
void dpii_v_uint (unsigned int i, unsigned int *o) { *o = ~i; }
|
||||
void dpii_v_byte (char i, char *o) { *o = ~i; }
|
||||
@ -115,10 +121,34 @@ void dpii_v_ushort (unsigned short i, unsigned short *o) { *o = ~i; }
|
||||
void dpii_v_longint (long long i, long long *o) { *o = ~i; }
|
||||
void dpii_v_ulong (unsigned long long i, unsigned long long *o) { *o = ~i; }
|
||||
void dpii_v_chandle (void* i, void* *o) { *o = i; }
|
||||
void dpii_v_string (const char* i, const char** o) { *o = i; }
|
||||
void dpii_v_string (const char* i, const char** o) { *o = strdup(i); } // Leaks
|
||||
void dpii_v_real (double i, double* o) { *o = i + 1.5; }
|
||||
void dpii_v_shortreal(float i, float* o) { *o = i + 1.5f; }
|
||||
|
||||
void dpii_v_reg(unsigned char i, unsigned char* o) { *o = (~i)&1; }
|
||||
void dpii_v_reg15(const svLogicVecVal* i, svLogicVecVal* o) {
|
||||
o[0].aval = (~i[0].aval) & 0x7fffUL;
|
||||
o[0].bval = 0;
|
||||
}
|
||||
void dpii_v_reg95(const svLogicVecVal* i, svLogicVecVal* o) {
|
||||
o[0].aval = (~i[0].aval);
|
||||
o[1].aval = (~i[1].aval);
|
||||
o[2].aval = (~i[2].aval) & 0x7fffffffUL;
|
||||
o[0].bval = 0;
|
||||
o[1].bval = 0;
|
||||
o[2].bval = 0;
|
||||
}
|
||||
void dpii_v_integer(const svLogicVecVal* i, svLogicVecVal* o) {
|
||||
o[0].aval = (~i[0].aval);
|
||||
o[0].bval = 0;
|
||||
}
|
||||
void dpii_v_time(const svLogicVecVal* i, svLogicVecVal* o) {
|
||||
o[0].aval = (~i[0].aval);
|
||||
o[1].aval = (~i[1].aval);
|
||||
o[0].bval = 0;
|
||||
o[1].bval = 0;
|
||||
}
|
||||
|
||||
void dpii_v_struct (const svBitVecVal* i, svBitVecVal* o) {
|
||||
o[0] = ~i[0];
|
||||
o[1] = ~i[1];
|
||||
@ -135,9 +165,9 @@ void dpii_v_bit64(const svBitVecVal* i, svBitVecVal* o) {
|
||||
o[1] = ~i[1];
|
||||
}
|
||||
void dpii_v_bit95(const svBitVecVal* i, svBitVecVal* o) {
|
||||
o[0] = ~i[0];
|
||||
o[1] = ~i[1];
|
||||
o[2] = VL_MASK_I(95-64) & ~i[2];
|
||||
o[0] = (~i[0]);
|
||||
o[1] = (~i[1]);
|
||||
o[2] = (~i[2]) & 0x7fffffffUL;
|
||||
}
|
||||
void dpii_v_bit96(const svBitVecVal* i, svBitVecVal* o) {
|
||||
o[0] = ~i[0];
|
||||
|
@ -8,13 +8,12 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
v_flags2 => ["--lint-only"],
|
||||
fails=>$Self->{v3},
|
||||
expect=>
|
||||
'%Error: t/t_dpi_logic_bad.v:\d+: Unsupported: DPI argument of type .*
|
||||
%Error: t/t_dpi_logic_bad.v:\d+: ... For best portability, use bit, byte, int, or longint
|
||||
v_flags2 => ["--lint-only"],
|
||||
fails=>$Self->{v3},
|
||||
expect=>
|
||||
'%Error: t/t_dpi_logic_bad.v:\d+: DPI function may not return type BASICDTYPE \'logic\' \(IEEE 2012 35.5.5\)
|
||||
%Error: Exiting due to .*'
|
||||
);
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
@ -8,7 +8,7 @@
|
||||
module t ();
|
||||
|
||||
// Can't handle time (yet?)
|
||||
import "DPI-C" dpii_fa_bit = function int oth_f_int1(input time i);
|
||||
import "DPI-C" dpii_fa_bit = function logic [2:0] oth_f_int1(input time i);
|
||||
|
||||
initial begin
|
||||
$stop;
|
||||
|
Loading…
Reference in New Issue
Block a user