DPI: Support strings in DPI Imports
This commit is contained in:
parent
08b63b4f01
commit
788f69a8c9
|
|
@ -1843,6 +1843,11 @@ full nor unique.
|
||||||
|
|
||||||
All specify blocks and timing checks are ignored.
|
All specify blocks and timing checks are ignored.
|
||||||
|
|
||||||
|
=item string
|
||||||
|
|
||||||
|
String is supported only to the point that they can be passed to DPI
|
||||||
|
imports.
|
||||||
|
|
||||||
=item timeunit, timeprecision
|
=item timeunit, timeprecision
|
||||||
|
|
||||||
All timing control statements are ignored.
|
All timing control statements are ignored.
|
||||||
|
|
|
||||||
|
|
@ -616,6 +616,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
|
||||||
// File I/O
|
// File I/O
|
||||||
|
|
||||||
void _VL_VINT_TO_STRING(int obits, char* destoutp, WDataInP sourcep) {
|
void _VL_VINT_TO_STRING(int obits, char* destoutp, WDataInP sourcep) {
|
||||||
|
// See also VL_DATA_TO_STRING_NW
|
||||||
int lsb=obits-1;
|
int lsb=obits-1;
|
||||||
bool start=true;
|
bool start=true;
|
||||||
char* destp = destoutp;
|
char* destp = destoutp;
|
||||||
|
|
@ -901,6 +902,29 @@ IData VL_VALUEPLUSARGS_IW(int rbits, const char* prefixp, char fmt, WDataOutP rw
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
// Heavy functions
|
||||||
|
|
||||||
|
string VL_CVT_PACK_STR_NW(int lwords, WDataInP lwp) {
|
||||||
|
// See also _VL_VINT_TO_STRING
|
||||||
|
char destout[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1];
|
||||||
|
int obits = lwords * VL_WORDSIZE;
|
||||||
|
int lsb=obits-1;
|
||||||
|
bool start=true;
|
||||||
|
char* destp = destout;
|
||||||
|
int len = 0;
|
||||||
|
for (; lsb>=0; lsb--) {
|
||||||
|
lsb = (lsb / 8) * 8; // Next digit
|
||||||
|
IData charval = (lwp[VL_BITWORD_I(lsb)]>>VL_BITBIT_I(lsb)) & 0xff;
|
||||||
|
if (!start || charval) {
|
||||||
|
*destp++ = (charval==0)?' ':charval;
|
||||||
|
len++;
|
||||||
|
start = false; // Drop leading 0s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string(destout, len);
|
||||||
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
// Verilated:: Methods
|
// Verilated:: Methods
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
// <iostream> avoided to reduce compile time
|
// <iostream> avoided to reduce compile time
|
||||||
// <string> avoided to reduce compile time
|
// <string> avoided and instead in verilatedheavy.h to reduce compile time
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
// -*- C++ -*-
|
||||||
|
//*************************************************************************
|
||||||
|
//
|
||||||
|
// Copyright 2010-2010 by Wilson Snyder. This program is free software; you can
|
||||||
|
// redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
// Lesser General Public License Version 3 or the Perl Artistic License.
|
||||||
|
// Version 2.0.
|
||||||
|
//
|
||||||
|
// Verilator is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
///
|
||||||
|
/// \file
|
||||||
|
/// \brief Verilator: String include for all Verilated C files
|
||||||
|
///
|
||||||
|
/// This file is included automatically by Verilator at the top of
|
||||||
|
/// all C++ files it generates. It is used when strings or other
|
||||||
|
/// heavyweight types are required; these contents are not part of
|
||||||
|
/// verilated.h to save compile time when such types aren't used.
|
||||||
|
///
|
||||||
|
/// Code available from: http://www.veripool.org/verilator
|
||||||
|
///
|
||||||
|
//*************************************************************************
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _VERILATEDHEAVY_H_
|
||||||
|
#define _VERILATEDHEAVY_H_ 1 ///< Header Guard
|
||||||
|
|
||||||
|
#include "verilated.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
//======================================================================
|
||||||
|
|
||||||
|
extern string VL_CVT_PACK_STR_NW(int lwords, WDataInP lwp);
|
||||||
|
inline string VL_CVT_PACK_STR_NQ(QData lhs) {
|
||||||
|
IData lw[2]; VL_SET_WQ(lw, lhs);
|
||||||
|
return VL_CVT_PACK_STR_NW(2, lw);
|
||||||
|
}
|
||||||
|
inline string VL_CVT_PACK_STR_NI(IData lhs) {
|
||||||
|
IData lw[1]; lw[0] = lhs;
|
||||||
|
return VL_CVT_PACK_STR_NW(1, lw);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // Guard
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include "verilatedos.h"
|
#include "verilatedos.h"
|
||||||
#include "verilated.h"
|
#include "verilated.h"
|
||||||
|
#include "verilatedheavy.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
|
||||||
|
|
@ -272,6 +272,9 @@ public:
|
||||||
bool isDpiUnsupported() const {
|
bool isDpiUnsupported() const {
|
||||||
return (m_e==LOGIC || m_e==TIME || m_e==REALTIME);
|
return (m_e==LOGIC || m_e==TIME || m_e==REALTIME);
|
||||||
}
|
}
|
||||||
|
bool isOpaque() const { // IE not a simple number we can bit optimize
|
||||||
|
return (m_e==STRING || m_e==SCOPEPTR || m_e==CHARPTR);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
inline bool operator== (AstBasicDTypeKwd lhs, AstBasicDTypeKwd rhs) { return (lhs.m_e == rhs.m_e); }
|
inline bool operator== (AstBasicDTypeKwd lhs, AstBasicDTypeKwd rhs) { return (lhs.m_e == rhs.m_e); }
|
||||||
inline bool operator== (AstBasicDTypeKwd lhs, AstBasicDTypeKwd::en rhs) { return (lhs.m_e == rhs); }
|
inline bool operator== (AstBasicDTypeKwd lhs, AstBasicDTypeKwd::en rhs) { return (lhs.m_e == rhs); }
|
||||||
|
|
@ -918,6 +921,9 @@ struct AstNodeMath : public AstNode {
|
||||||
virtual string emitC() = 0;
|
virtual string emitC() = 0;
|
||||||
virtual string emitSimpleOperator() { return ""; }
|
virtual string emitSimpleOperator() { return ""; }
|
||||||
virtual bool cleanOut() = 0; // True if output has extra upper bits zero
|
virtual bool cleanOut() = 0; // True if output has extra upper bits zero
|
||||||
|
// Someday we will generically support data types on every math node
|
||||||
|
// Until then isOpaque indicates we shouldn't constant optimize this node type
|
||||||
|
bool isOpaque() { return castCvtPackString(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstNodeTermop : public AstNodeMath {
|
struct AstNodeTermop : public AstNodeMath {
|
||||||
|
|
|
||||||
|
|
@ -108,10 +108,14 @@ string AstVar::vlArgType(bool named, bool forReturn) const {
|
||||||
string arg;
|
string arg;
|
||||||
if (isWide() && isInOnly()) arg += "const ";
|
if (isWide() && isInOnly()) arg += "const ";
|
||||||
AstBasicDType* bdtypep = basicp();
|
AstBasicDType* bdtypep = basicp();
|
||||||
|
bool strtype = bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::STRING;
|
||||||
if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::CHARPTR) {
|
if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::CHARPTR) {
|
||||||
arg += "const char*";
|
arg += "const char*";
|
||||||
} else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::SCOPEPTR) {
|
} else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::SCOPEPTR) {
|
||||||
arg += "const VerilatedScope*";
|
arg += "const VerilatedScope*";
|
||||||
|
} else if (strtype) {
|
||||||
|
if (isInOnly()) arg += "const ";
|
||||||
|
arg += "string";
|
||||||
} else if (widthMin() <= 8) {
|
} else if (widthMin() <= 8) {
|
||||||
arg += "CData";
|
arg += "CData";
|
||||||
} else if (widthMin() <= 16) {
|
} else if (widthMin() <= 16) {
|
||||||
|
|
@ -123,11 +127,11 @@ string AstVar::vlArgType(bool named, bool forReturn) const {
|
||||||
} else if (isWide()) {
|
} else if (isWide()) {
|
||||||
arg += "WData"; // []'s added later
|
arg += "WData"; // []'s added later
|
||||||
}
|
}
|
||||||
if (isWide()) {
|
if (isWide() && !strtype) {
|
||||||
arg += " (& "+name();
|
arg += " (& "+name();
|
||||||
arg += ")["+cvtToStr(widthWords())+"]";
|
arg += ")["+cvtToStr(widthWords())+"]";
|
||||||
} else {
|
} else {
|
||||||
if (isOutput()) arg += "&";
|
if (isOutput() || (strtype && isInput())) arg += "&";
|
||||||
if (named) arg += " "+name();
|
if (named) arg += " "+name();
|
||||||
}
|
}
|
||||||
return arg;
|
return arg;
|
||||||
|
|
|
||||||
|
|
@ -228,7 +228,7 @@ private:
|
||||||
setSignedState(signst);
|
setSignedState(signst);
|
||||||
if (!rangep) { // Set based on keyword properties
|
if (!rangep) { // Set based on keyword properties
|
||||||
// V3Width will pull from this width
|
// V3Width will pull from this width
|
||||||
if (keyword().width() > 1) rangep = new AstRange(fileline(), keyword().width()-1, 0);
|
if (keyword().width() > 1 && !isOpaque()) rangep = new AstRange(fileline(), keyword().width()-1, 0);
|
||||||
width(keyword().width(), keyword().width());
|
width(keyword().width(), keyword().width());
|
||||||
} else {
|
} else {
|
||||||
widthFrom(rangep); // Maybe unknown if parameters underneath it
|
widthFrom(rangep); // Maybe unknown if parameters underneath it
|
||||||
|
|
@ -254,6 +254,7 @@ public:
|
||||||
virtual int widthTotalBytes() const; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
|
virtual int widthTotalBytes() const; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
|
||||||
AstBasicDTypeKwd keyword() const { return m_keyword; } // Avoid using - use isSomething accessors instead
|
AstBasicDTypeKwd keyword() const { return m_keyword; } // Avoid using - use isSomething accessors instead
|
||||||
bool isBitLogic() const { return keyword().isBitLogic(); }
|
bool isBitLogic() const { return keyword().isBitLogic(); }
|
||||||
|
bool isOpaque() const { return keyword().isOpaque(); }
|
||||||
bool isSloppy() const { return keyword().isSloppy(); }
|
bool isSloppy() const { return keyword().isSloppy(); }
|
||||||
bool isZeroInit() const { return keyword().isZeroInit(); }
|
bool isZeroInit() const { return keyword().isZeroInit(); }
|
||||||
int msb() const { if (!rangep()) return 0; return rangep()->msbConst(); }
|
int msb() const { if (!rangep()) return 0; return rangep()->msbConst(); }
|
||||||
|
|
@ -2420,6 +2421,20 @@ public:
|
||||||
int size() const { return m_size; }
|
int size() const { return m_size; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AstCvtPackString : public AstNodeUniop {
|
||||||
|
// Convert to Verilator Packed Pack (aka Pack)
|
||||||
|
AstCvtPackString(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||||
|
width(64,64); } // Really, width should be dtypep -> STRING
|
||||||
|
ASTNODE_NODE_FUNCS(CvtPackString, CVTPACKSTRING)
|
||||||
|
virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; }
|
||||||
|
virtual string emitVerilog() { return "%f$_CAST(%l)"; }
|
||||||
|
virtual string emitC() { return "VL_CVT_PACK_STR_N%lq(%lW, %li)"; }
|
||||||
|
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;}
|
||||||
|
virtual bool sizeMattersLhs() {return false;}
|
||||||
|
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||||
|
virtual bool same(AstNode* samep) const { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
struct AstFEof : public AstNodeUniop {
|
struct AstFEof : public AstNodeUniop {
|
||||||
AstFEof(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {}
|
AstFEof(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {}
|
||||||
ASTNODE_NODE_FUNCS(FEof, FEOF)
|
ASTNODE_NODE_FUNCS(FEof, FEOF)
|
||||||
|
|
|
||||||
|
|
@ -1090,6 +1090,11 @@ private:
|
||||||
nodep->v3error("Expecting expression to be constant, but variable isn't const: "<<nodep->itemp()->prettyName());
|
nodep->v3error("Expecting expression to be constant, but variable isn't const: "<<nodep->itemp()->prettyName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// virtual void visit(AstCvtPackString* nodep, AstNUser*) {
|
||||||
|
// Not constant propagated (for today) because AstMath::isOpaque is set
|
||||||
|
// Someday if lower is constant, convert to quoted "string".
|
||||||
|
|
||||||
virtual void visit(AstAttrOf* nodep, AstNUser*) {
|
virtual void visit(AstAttrOf* nodep, AstNUser*) {
|
||||||
// Don't iterate children, don't want to loose VarRef.
|
// Don't iterate children, don't want to loose VarRef.
|
||||||
if (nodep->attrType()==AstAttrType::BITS) {
|
if (nodep->attrType()==AstAttrType::BITS) {
|
||||||
|
|
@ -1504,7 +1509,7 @@ private:
|
||||||
TREEOP1("AstSel{warnSelect(nodep)}", "NEVER");
|
TREEOP1("AstSel{warnSelect(nodep)}", "NEVER");
|
||||||
// Generic constants on both side. Do this first to avoid other replacements
|
// Generic constants on both side. Do this first to avoid other replacements
|
||||||
TREEOP("AstNodeBiop {$lhsp.castConst, $rhsp.castConst}", "replaceConst(nodep)");
|
TREEOP("AstNodeBiop {$lhsp.castConst, $rhsp.castConst}", "replaceConst(nodep)");
|
||||||
TREEOP("AstNodeUniop{$lhsp.castConst}", "replaceConst(nodep)");
|
TREEOP("AstNodeUniop{$lhsp.castConst, !nodep->isOpaque()}", "replaceConst(nodep)");
|
||||||
// Zero on one side or the other
|
// Zero on one side or the other
|
||||||
TREEOP("AstAdd {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
|
TREEOP("AstAdd {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
|
||||||
TREEOP("AstAnd {$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
|
TREEOP("AstAnd {$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
|
||||||
|
|
|
||||||
|
|
@ -861,6 +861,14 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
|
||||||
+","+cvtToStr(basicp->widthWords()));
|
+","+cvtToStr(basicp->widthWords()));
|
||||||
puts(");\n");
|
puts(");\n");
|
||||||
}
|
}
|
||||||
|
} else if (basicp && basicp->isOpaque()) {
|
||||||
|
// strings and other fundamental c types
|
||||||
|
puts(nodep->vlArgType(true,false));
|
||||||
|
// This isn't very robust and may need cleanup for other data types
|
||||||
|
for (AstArrayDType* arrayp=nodep->dtypeSkipRefp()->castArrayDType(); arrayp; arrayp = arrayp->dtypeSkipRefp()->castArrayDType()) {
|
||||||
|
puts("["+cvtToStr(arrayp->elementsConst())+"]");
|
||||||
|
}
|
||||||
|
puts(";\n");
|
||||||
} else {
|
} else {
|
||||||
// Arrays need a small alignment, but may need different padding after.
|
// Arrays need a small alignment, but may need different padding after.
|
||||||
// For example three VL_SIG8's needs alignment 1 but size 3.
|
// For example three VL_SIG8's needs alignment 1 but size 3.
|
||||||
|
|
@ -1226,6 +1234,9 @@ void EmitCImp::emitVarResets(AstNodeModule* modp) {
|
||||||
if (varp->isIO() && modp->isTop() && optSystemC()) {
|
if (varp->isIO() && modp->isTop() && optSystemC()) {
|
||||||
// System C top I/O doesn't need loading, as the lower level subinst code does it.
|
// System C top I/O doesn't need loading, as the lower level subinst code does it.
|
||||||
}
|
}
|
||||||
|
else if (varp->basicp() && varp->basicp()->keyword() == AstBasicDTypeKwd::STRING) {
|
||||||
|
// Constructor deals with it
|
||||||
|
}
|
||||||
else if (varp->isParam()) {
|
else if (varp->isParam()) {
|
||||||
if (!varp->hasSimpleInit()) nodep->v3fatalSrc("No init for a param?");
|
if (!varp->hasSimpleInit()) nodep->v3fatalSrc("No init for a param?");
|
||||||
//puts("// parameter "+varp->name()+" = "+varp->initp()->name()+"\n");
|
//puts("// parameter "+varp->name()+" = "+varp->initp()->name()+"\n");
|
||||||
|
|
@ -1483,8 +1494,9 @@ void EmitCStmts::emitVarList(AstNode* firstp, EisWhich which, const string& pref
|
||||||
// But for now, Smallest->largest makes it more likely a small offset will allow access to the signal.
|
// But for now, Smallest->largest makes it more likely a small offset will allow access to the signal.
|
||||||
for (int isstatic=1; isstatic>=0; isstatic--) {
|
for (int isstatic=1; isstatic>=0; isstatic--) {
|
||||||
if (prefixIfImp!="" && !isstatic) continue;
|
if (prefixIfImp!="" && !isstatic) continue;
|
||||||
for (int size=0; size<8; size++) {
|
const int sortmax = 9;
|
||||||
if (size==3) continue;
|
for (int sort=0; sort<sortmax; sort++) {
|
||||||
|
if (sort==3) continue;
|
||||||
for (AstNode* nodep=firstp; nodep; nodep = nodep->nextp()) {
|
for (AstNode* nodep=firstp; nodep; nodep = nodep->nextp()) {
|
||||||
if (AstVar* varp = nodep->castVar()) {
|
if (AstVar* varp = nodep->castVar()) {
|
||||||
bool doit = true;
|
bool doit = true;
|
||||||
|
|
@ -1498,15 +1510,16 @@ void EmitCStmts::emitVarList(AstNode* firstp, EisWhich which, const string& pref
|
||||||
if (varp->isStatic() ? !isstatic : isstatic) doit=false;
|
if (varp->isStatic() ? !isstatic : isstatic) doit=false;
|
||||||
if (doit) {
|
if (doit) {
|
||||||
int sigbytes = varp->dtypeSkipRefp()->widthAlignBytes();
|
int sigbytes = varp->dtypeSkipRefp()->widthAlignBytes();
|
||||||
int sortbytes = 7;
|
int sortbytes = sortmax-1;
|
||||||
if (varp->isUsedClock() && varp->widthMin()==1) sortbytes = 0;
|
if (varp->isUsedClock() && varp->widthMin()==1) sortbytes = 0;
|
||||||
else if (varp->dtypeSkipRefp()->castArrayDType()) sortbytes=7;
|
else if (varp->dtypeSkipRefp()->castArrayDType()) sortbytes=8;
|
||||||
|
else if (varp->basicp() && varp->basicp()->isOpaque()) sortbytes=7;
|
||||||
else if (varp->isScBv()) sortbytes=6;
|
else if (varp->isScBv()) sortbytes=6;
|
||||||
else if (sigbytes==8) sortbytes=5;
|
else if (sigbytes==8) sortbytes=5;
|
||||||
else if (sigbytes==4) sortbytes=4;
|
else if (sigbytes==4) sortbytes=4;
|
||||||
else if (sigbytes==2) sortbytes=2;
|
else if (sigbytes==2) sortbytes=2;
|
||||||
else if (sigbytes==1) sortbytes=1;
|
else if (sigbytes==1) sortbytes=1;
|
||||||
if (size==sortbytes) {
|
if (sort==sortbytes) {
|
||||||
emitVarDecl(varp, prefixIfImp);
|
emitVarDecl(varp, prefixIfImp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1556,7 +1569,11 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ofp()->putsIntTopInclude();
|
ofp()->putsIntTopInclude();
|
||||||
puts("#include \"verilated.h\"\n");
|
if (v3Global.needHeavy()) {
|
||||||
|
puts("#include \"verilatedheavy.h\"\n");
|
||||||
|
} else {
|
||||||
|
puts("#include \"verilated.h\"\n");
|
||||||
|
}
|
||||||
if (v3Global.opt.coverage()) {
|
if (v3Global.opt.coverage()) {
|
||||||
puts("#include \"SpCoverage.h\"\n");
|
puts("#include \"SpCoverage.h\"\n");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ class EmitCInlines : EmitCBaseVisitor {
|
||||||
// VISITORS
|
// VISITORS
|
||||||
virtual void visit(AstVar* nodep, AstNUser*) {
|
virtual void visit(AstVar* nodep, AstNUser*) {
|
||||||
// All wide constants load into variables, so we can just hunt for them
|
// All wide constants load into variables, so we can just hunt for them
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
if (nodep->widthWords() >= EMITCINLINES_NUM_CONSTW ) {
|
if (nodep->widthWords() >= EMITCINLINES_NUM_CONSTW ) {
|
||||||
if (int(m_wordWidths.size()) <= nodep->widthWords()) {
|
if (int(m_wordWidths.size()) <= nodep->widthWords()) {
|
||||||
m_wordWidths.resize(nodep->widthWords()+5);
|
m_wordWidths.resize(nodep->widthWords()+5);
|
||||||
|
|
@ -55,6 +56,11 @@ class EmitCInlines : EmitCBaseVisitor {
|
||||||
v3Global.needHInlines(true);
|
v3Global.needHInlines(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstBasicDType* nodep, AstNUser*) {
|
||||||
|
if (nodep->keyword() == AstBasicDTypeKwd::STRING) {
|
||||||
|
v3Global.needHeavy(true); // #include <string> via verilatedheavy.h when we create symbol file
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NOPs
|
// NOPs
|
||||||
virtual void visit(AstNodeStmt*, AstNUser*) {}
|
virtual void visit(AstNodeStmt*, AstNUser*) {}
|
||||||
|
|
|
||||||
|
|
@ -181,6 +181,12 @@ void EmitCSyms::emitSymHdr() {
|
||||||
puts("#define _"+symClassName()+"_H_\n");
|
puts("#define _"+symClassName()+"_H_\n");
|
||||||
puts("\n");
|
puts("\n");
|
||||||
|
|
||||||
|
if (v3Global.needHeavy()) {
|
||||||
|
puts("#include \"verilatedheavy.h\"\n");
|
||||||
|
} else {
|
||||||
|
puts("#include \"verilated.h\"\n");
|
||||||
|
}
|
||||||
|
|
||||||
// for
|
// for
|
||||||
puts("\n// INCLUDE MODULE CLASSES\n");
|
puts("\n// INCLUDE MODULE CLASSES\n");
|
||||||
for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep; nodep=nodep->nextp()->castNodeModule()) {
|
for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep; nodep=nodep->nextp()->castNodeModule()) {
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ class V3Global {
|
||||||
int m_debugFileNumber; // Number to append to debug files created
|
int m_debugFileNumber; // Number to append to debug files created
|
||||||
bool m_assertWidthsSame; // Tree should have width()==widthMin()
|
bool m_assertWidthsSame; // Tree should have width()==widthMin()
|
||||||
bool m_needHInlines; // Need __Inlines file
|
bool m_needHInlines; // Need __Inlines file
|
||||||
|
bool m_needHeavy; // Need verilatedheavy.h include
|
||||||
bool m_dpi; // Need __Dpi include files
|
bool m_dpi; // Need __Dpi include files
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -57,6 +58,7 @@ public:
|
||||||
m_debugFileNumber = 0;
|
m_debugFileNumber = 0;
|
||||||
m_assertWidthsSame = false;
|
m_assertWidthsSame = false;
|
||||||
m_needHInlines = false;
|
m_needHInlines = false;
|
||||||
|
m_needHeavy = false;
|
||||||
m_dpi = false;
|
m_dpi = false;
|
||||||
}
|
}
|
||||||
void clear() {
|
void clear() {
|
||||||
|
|
@ -78,6 +80,8 @@ public:
|
||||||
}
|
}
|
||||||
bool needHInlines() const { return m_needHInlines; }
|
bool needHInlines() const { return m_needHInlines; }
|
||||||
void needHInlines(bool flag) { m_needHInlines=flag; }
|
void needHInlines(bool flag) { m_needHInlines=flag; }
|
||||||
|
bool needHeavy() const { return m_needHeavy; }
|
||||||
|
void needHeavy(bool flag) { m_needHeavy=flag; }
|
||||||
bool dpi() const { return m_dpi; }
|
bool dpi() const { return m_dpi; }
|
||||||
void dpi(bool flag) { m_dpi = flag; }
|
void dpi(bool flag) { m_dpi = flag; }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -503,15 +503,6 @@ private:
|
||||||
}
|
}
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
}
|
}
|
||||||
virtual void visit(AstBasicDType* nodep, AstNUser*) {
|
|
||||||
if (m_idState==ID_RESOLVE && nodep->keyword()==AstBasicDTypeKwd::STRING) {
|
|
||||||
if (!(m_ftaskp && m_ftaskp->dpiImport() && 0/*UNIMP*/)) {
|
|
||||||
nodep->v3error("Unsupported: SystemVerilog 'string' anywhere but DPI import __format");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nodep->iterateChildren(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void visit(AstCell* nodep, AstNUser*) {
|
virtual void visit(AstCell* nodep, AstNUser*) {
|
||||||
// Cell: Resolve its filename. If necessary, parse it.
|
// Cell: Resolve its filename. If necessary, parse it.
|
||||||
m_cellp = nodep;
|
m_cellp = nodep;
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,8 @@ private:
|
||||||
virtual void visit(AstNeq* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
virtual void visit(AstNeq* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||||
virtual void visit(AstNeqCase* nodep, AstNUser*){ signed_Ou_Ix(nodep); }
|
virtual void visit(AstNeqCase* nodep, AstNUser*){ signed_Ou_Ix(nodep); }
|
||||||
virtual void visit(AstNeqWild* nodep, AstNUser*){ signed_Ou_Ix(nodep); }
|
virtual void visit(AstNeqWild* nodep, AstNUser*){ signed_Ou_Ix(nodep); }
|
||||||
|
// ... Opaque returns, so arbitrary
|
||||||
|
virtual void visit(AstCvtPackString* nodep, AstNUser*){ signed_Ou_Ix(nodep); }
|
||||||
|
|
||||||
//========
|
//========
|
||||||
// Signed: Output signed
|
// Signed: Output signed
|
||||||
|
|
|
||||||
|
|
@ -592,6 +592,9 @@ private:
|
||||||
stmt += "(void*)";
|
stmt += "(void*)";
|
||||||
}
|
}
|
||||||
stmt += portp->name()+frSuffix;
|
stmt += portp->name()+frSuffix;
|
||||||
|
if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::STRING) {
|
||||||
|
stmt += ".c_str()";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
stmt += ";\n";
|
stmt += ";\n";
|
||||||
return new AstCStmt(portp->fileline(), stmt);
|
return new AstCStmt(portp->fileline(), stmt);
|
||||||
|
|
|
||||||
|
|
@ -481,6 +481,9 @@ private:
|
||||||
nodep->width(selwidth,selwidth);
|
nodep->width(selwidth,selwidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstCvtPackString* nodep, AstNUser* vup) {
|
||||||
|
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||||
|
}
|
||||||
virtual void visit(AstAttrOf* nodep, AstNUser*) {
|
virtual void visit(AstAttrOf* nodep, AstNUser*) {
|
||||||
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||||
nodep->width(32,1); // Approximation, unsized 32
|
nodep->width(32,1); // Approximation, unsized 32
|
||||||
|
|
@ -947,11 +950,22 @@ private:
|
||||||
if (accept_mode) {
|
if (accept_mode) {
|
||||||
// Prelim may cause the node to get replaced; we've lost our
|
// Prelim may cause the node to get replaced; we've lost our
|
||||||
// pointer, so need to iterate separately later
|
// pointer, so need to iterate separately later
|
||||||
|
if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::STRING
|
||||||
|
&& !pinp->castCvtPackString()
|
||||||
|
&& !(pinp->castVarRef() && pinp->castVarRef()->varp()->basicp()->keyword()==AstBasicDTypeKwd::STRING)) {
|
||||||
|
AstNRelinker handle;
|
||||||
|
pinp->unlinkFrBack(&handle); // No next, that's the next pin
|
||||||
|
AstNode* newp = new AstCvtPackString(pinp->fileline(), pinp);
|
||||||
|
handle.relink(newp);
|
||||||
|
pinp = newp;
|
||||||
|
}
|
||||||
pinp->accept(*this,WidthVP(portp->width(),portp->widthMin(),PRELIM).p()); pinp=NULL;
|
pinp->accept(*this,WidthVP(portp->width(),portp->widthMin(),PRELIM).p()); pinp=NULL;
|
||||||
} else {
|
} else {
|
||||||
// Do PRELIM again, because above accept may have exited early due to node replacement
|
// Do PRELIM again, because above accept may have exited early due to node replacement
|
||||||
pinp->accept(*this,WidthVP(portp->width(),portp->widthMin(),BOTH).p());
|
pinp->accept(*this,WidthVP(portp->width(),portp->widthMin(),BOTH).p());
|
||||||
widthCheck(nodep,"Function Argument",pinp,portp->width(),portp->widthMin());
|
if (portp->basicp() && !portp->basicp()->isOpaque()) {
|
||||||
|
widthCheck(nodep,"Function Argument",pinp,portp->width(),portp->widthMin());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,8 @@ module t ();
|
||||||
import "DPI-C" pure function shortint dpii_f_shortint (input shortint i);
|
import "DPI-C" pure function shortint dpii_f_shortint (input shortint i);
|
||||||
import "DPI-C" pure function longint dpii_f_longint (input longint i);
|
import "DPI-C" pure function longint dpii_f_longint (input longint i);
|
||||||
import "DPI-C" pure function chandle dpii_f_chandle (input chandle i);
|
import "DPI-C" pure function chandle dpii_f_chandle (input chandle i);
|
||||||
`ifndef VERILATOR
|
|
||||||
import "DPI-C" pure function string dpii_f_string (input string i);
|
import "DPI-C" pure function string dpii_f_string (input string i);
|
||||||
|
`ifndef VERILATOR
|
||||||
import "DPI-C" pure function real dpii_f_real (input real i);
|
import "DPI-C" pure function real dpii_f_real (input real i);
|
||||||
`endif
|
`endif
|
||||||
`ifndef NO_SHORTREAL
|
`ifndef NO_SHORTREAL
|
||||||
|
|
@ -52,14 +52,16 @@ module t ();
|
||||||
import "DPI-C" pure function void dpii_v_shortint (input shortint i, output shortint o);
|
import "DPI-C" pure function void dpii_v_shortint (input shortint i, output shortint o);
|
||||||
import "DPI-C" pure function void dpii_v_longint (input longint i, output longint o);
|
import "DPI-C" pure function void dpii_v_longint (input longint i, output longint o);
|
||||||
import "DPI-C" pure function void dpii_v_chandle (input chandle i, output chandle o);
|
import "DPI-C" pure function void dpii_v_chandle (input chandle i, output chandle o);
|
||||||
`ifndef VERILATOR
|
|
||||||
import "DPI-C" pure function void dpii_v_string (input string i, output string o);
|
import "DPI-C" pure function void dpii_v_string (input string i, output string o);
|
||||||
|
`ifndef VERILATOR
|
||||||
import "DPI-C" pure function void dpii_v_real (input real i, output real o);
|
import "DPI-C" pure function void dpii_v_real (input real i, output real o);
|
||||||
`endif
|
`endif
|
||||||
`ifndef NO_SHORTREAL
|
`ifndef NO_SHORTREAL
|
||||||
import "DPI-C" pure function void dpii_v_shortreal(input shortreal i, output shortreal o);
|
import "DPI-C" pure function void dpii_v_shortreal(input shortreal i, output shortreal o);
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
|
import "DPI-C" pure function int dpii_f_strlen (input string i);
|
||||||
|
|
||||||
import "DPI-C" function void dpii_f_void ();
|
import "DPI-C" function void dpii_f_void ();
|
||||||
|
|
||||||
// Try a task
|
// Try a task
|
||||||
|
|
@ -86,8 +88,8 @@ module t ();
|
||||||
shortint i_s, o_s;
|
shortint i_s, o_s;
|
||||||
longint i_l, o_l;
|
longint i_l, o_l;
|
||||||
chandle i_c, o_c;
|
chandle i_c, o_c;
|
||||||
`ifndef VERILATOR
|
|
||||||
string i_n, o_n;
|
string i_n, o_n;
|
||||||
|
`ifndef VERILATOR
|
||||||
real i_d, o_d;
|
real i_d, o_d;
|
||||||
`endif
|
`endif
|
||||||
`ifndef NO_SHORTREAL
|
`ifndef NO_SHORTREAL
|
||||||
|
|
@ -134,8 +136,8 @@ module t ();
|
||||||
if (dpii_f_shortint (i_s) !== ~i_s) $stop;
|
if (dpii_f_shortint (i_s) !== ~i_s) $stop;
|
||||||
if (dpii_f_longint (i_l) !== ~i_l) $stop;
|
if (dpii_f_longint (i_l) !== ~i_l) $stop;
|
||||||
if (dpii_f_chandle (i_c) !== i_c) $stop;
|
if (dpii_f_chandle (i_c) !== i_c) $stop;
|
||||||
`ifndef VERILATOR
|
|
||||||
if (dpii_f_string (i_n) != i_n) $stop;
|
if (dpii_f_string (i_n) != i_n) $stop;
|
||||||
|
`ifndef VERILATOR
|
||||||
if (dpii_f_real (i_d) != i_d+1.5) $stop;
|
if (dpii_f_real (i_d) != i_d+1.5) $stop;
|
||||||
`endif
|
`endif
|
||||||
`ifndef NO_SHORTREAL
|
`ifndef NO_SHORTREAL
|
||||||
|
|
@ -148,16 +150,22 @@ module t ();
|
||||||
dpii_v_shortint (i_s,o_s); if (o_s !== ~i_s) $stop;
|
dpii_v_shortint (i_s,o_s); if (o_s !== ~i_s) $stop;
|
||||||
dpii_v_longint (i_l,o_l); if (o_l !== ~i_l) $stop;
|
dpii_v_longint (i_l,o_l); if (o_l !== ~i_l) $stop;
|
||||||
dpii_v_chandle (i_c,o_c); if (o_c !== i_c) $stop;
|
dpii_v_chandle (i_c,o_c); if (o_c !== i_c) $stop;
|
||||||
`ifndef VERILATOR
|
|
||||||
`ifndef VCS // Strange link error
|
|
||||||
dpii_v_string (i_n,o_n); if (o_n != i_n) $stop;
|
dpii_v_string (i_n,o_n); if (o_n != i_n) $stop;
|
||||||
`endif
|
`ifndef VERILATOR
|
||||||
dpii_v_real (i_d,o_d); if (o_d != i_d+1.5) $stop;
|
dpii_v_real (i_d,o_d); if (o_d != i_d+1.5) $stop;
|
||||||
`endif
|
`endif
|
||||||
`ifndef NO_SHORTREAL
|
`ifndef NO_SHORTREAL
|
||||||
dpii_v_shortreal(i_f,o_f); if (o_f != i_f+1.5) $stop;
|
dpii_v_shortreal(i_f,o_f); if (o_f != i_f+1.5) $stop;
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
|
if (dpii_f_strlen ("")!=0) $stop;
|
||||||
|
if (dpii_f_strlen ("s")!=1) $stop;
|
||||||
|
if (dpii_f_strlen ("st")!=2) $stop;
|
||||||
|
if (dpii_f_strlen ("str")!=3) $stop;
|
||||||
|
if (dpii_f_strlen ("stri")!=4) $stop;
|
||||||
|
if (dpii_f_strlen ("string_l")!=8) $stop;
|
||||||
|
if (dpii_f_strlen ("string_len")!=10) $stop;
|
||||||
|
|
||||||
dpii_f_void();
|
dpii_f_void();
|
||||||
dpii_t_void();
|
dpii_t_void();
|
||||||
dpii_t_void_context();
|
dpii_t_void_context();
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <svdpi.h>
|
#include <svdpi.h>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
|
|
@ -63,6 +64,8 @@ extern "C" {
|
||||||
extern int dpii_t_void_context ();
|
extern int dpii_t_void_context ();
|
||||||
extern int dpii_t_int (int i, int *o);
|
extern int dpii_t_int (int i, int *o);
|
||||||
|
|
||||||
|
extern int dpii_f_strlen (const char* i);
|
||||||
|
|
||||||
extern int dpii_fa_bit(int i);
|
extern int dpii_fa_bit(int i);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -97,6 +100,8 @@ void dpii_v_string (const char* i, const char** o) { *o = i; }
|
||||||
void dpii_v_real (double i, double* o) { *o = i + 1.5; }
|
void dpii_v_real (double i, double* o) { *o = i + 1.5; }
|
||||||
void dpii_v_shortreal(float i, float* o) { *o = i + 1.5; }
|
void dpii_v_shortreal(float i, float* o) { *o = i + 1.5; }
|
||||||
|
|
||||||
|
int dpii_f_strlen (const char* i) { return strlen(i); }
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
void dpii_f_void () {}
|
void dpii_f_void () {}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue