From d1b8f53711be32ba5a18b6d9b2f75ed7b0356823 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 9 Dec 2017 20:17:37 -0500 Subject: [PATCH] Support DPI time and svLogicVal. Note older version incorrectly assumed svBitVal even for logicals. --- Changes | 3 ++ include/verilated_dpi.cpp | 43 ++++++++++------ include/verilated_dpi.h | 26 ++++++++-- src/V3Ast.h | 23 +++++++-- src/V3AstNodes.cpp | 16 +++++- src/V3AstNodes.h | 1 + src/V3Task.cpp | 86 +++++++++++++++++++++---------- src/V3Width.cpp | 6 ++- test_regress/t/t_dpi_exp_bad.pl | 2 +- test_regress/t/t_dpi_export.v | 42 +++++++++++---- test_regress/t/t_dpi_export_c.cpp | 51 ++++++++++++++++++ test_regress/t/t_dpi_import.v | 30 +++++++++++ test_regress/t/t_dpi_import_c.cpp | 52 +++++++++++++++---- test_regress/t/t_dpi_logic_bad.pl | 11 ++-- test_regress/t/t_dpi_logic_bad.v | 2 +- 15 files changed, 309 insertions(+), 85 deletions(-) diff --git a/Changes b/Changes index 4f981c9f2..2af47256f 100644 --- a/Changes +++ b/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] diff --git a/include/verilated_dpi.cpp b/include/verilated_dpi.cpp index 666d391ae..fa619e7b1 100644 --- a/include/verilated_dpi.cpp +++ b/include/verilated_dpi.cpp @@ -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 diff --git a/include/verilated_dpi.h b/include/verilated_dpi.h index 3b00443e4..590f18b7c 100644 --- a/include/verilated_dpi.h +++ b/include/verilated_dpi.h @@ -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 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(); } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 083ff714a..1803ad3be 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -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); diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index e014ccfce..dcd55feab 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -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(); } diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 00d7cacec..3fd0c67fb 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -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: "<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: "<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 "<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 "<basicp()->prettyTypeName()<warnMore()<<"... For best portability, use bit, byte, int, or longint"); // We don't warn on logic either, although the 4-stateness is lost. diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 005cc2aee..6601f8575 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -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()) { diff --git a/test_regress/t/t_dpi_exp_bad.pl b/test_regress/t/t_dpi_exp_bad.pl index 99494afb2..eb555643e 100755 --- a/test_regress/t/t_dpi_exp_bad.pl +++ b/test_regress/t/t_dpi_exp_bad.pl @@ -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 .*' ); diff --git a/test_regress/t/t_dpi_export.v b/test_regress/t/t_dpi_export.v index bb441d3df..a7eed5427 100644 --- a/test_regress/t/t_dpi_export.v +++ b/test_regress/t/t_dpi_export.v @@ -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 diff --git a/test_regress/t/t_dpi_export_c.cpp b/test_regress/t/t_dpi_export_c.cpp index ebf1cca15..94ce61329 100644 --- a/test_regress/t/t_dpi_export_c.cpp +++ b/test_regress/t/t_dpi_export_c.cpp @@ -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; diff --git a/test_regress/t/t_dpi_import.v b/test_regress/t/t_dpi_import.v index 5e45da2bd..e78cb284a 100644 --- a/test_regress/t/t_dpi_import.v +++ b/test_regress/t/t_dpi_import.v @@ -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; diff --git a/test_regress/t/t_dpi_import_c.cpp b/test_regress/t/t_dpi_import_c.cpp index f712742f7..2ceb0ef3b 100644 --- a/test_regress/t/t_dpi_import_c.cpp +++ b/test_regress/t/t_dpi_import_c.cpp @@ -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]; diff --git a/test_regress/t/t_dpi_logic_bad.pl b/test_regress/t/t_dpi_logic_bad.pl index e23755ee4..29ff03c2d 100755 --- a/test_regress/t/t_dpi_logic_bad.pl +++ b/test_regress/t/t_dpi_logic_bad.pl @@ -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; diff --git a/test_regress/t/t_dpi_logic_bad.v b/test_regress/t/t_dpi_logic_bad.v index fb4cfa8af..44f86489d 100644 --- a/test_regress/t/t_dpi_logic_bad.v +++ b/test_regress/t/t_dpi_logic_bad.v @@ -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;