Support DPI time and svLogicVal.

Note older version incorrectly assumed svBitVal even for logicals.
This commit is contained in:
Wilson Snyder 2017-12-09 20:17:37 -05:00
parent 27b5bfe9b1
commit d1b8f53711
15 changed files with 309 additions and 85 deletions

View File

@ -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]

View File

@ -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

View File

@ -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;
}
//======================================================================

View File

@ -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(); }

View File

@ -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);

View File

@ -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(); }

View File

@ -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.

View File

@ -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()) {

View File

@ -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 .*'
);

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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];

View File

@ -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;

View File

@ -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;