DPI $display like sformat metacomment and $sformatf

This commit is contained in:
Wilson Snyder 2010-01-17 19:13:44 -05:00
parent 0d1de96dbc
commit 72b596efb3
18 changed files with 244 additions and 31 deletions

View File

@ -1227,6 +1227,15 @@ DPI compatible but is easier to read and better supports multiple designs.
Vour::publicSetBool(value); Vour::publicSetBool(value);
// or top->publicSetBool(value); // or top->publicSetBool(value);
Verilator also allows writing $display like functions using this syntax:
import "DPI-C" function void
\$my_display (input string formatted /*verilator sformat*/ );
The /*verilator sformat*/ indicates that this function accepts a $display
like format specifier followed by any number of arguments to satisfy the
format.
Instead of DPI exporting, there's also Verilator public functions, which Instead of DPI exporting, there's also Verilator public functions, which
are slightly faster, but less compatible. are slightly faster, but less compatible.
@ -1621,10 +1630,17 @@ using the --public switch.
=item /*verilator sc_clock*/ =item /*verilator sc_clock*/
Used after a input declaration to indicate the signal should be declared in Rarely needed. Used after a input declaration to indicate the signal
SystemC as a sc_clock instead of a bool. This was needed in SystemC 1.1 should be declared in SystemC as a sc_clock instead of a bool. This was
and 1.2 only; versions 2.0 and later do not require clock pins to be needed in SystemC 1.1 and 1.2 only; versions 2.0 and later do not require
sc_clocks and this is no longer needed. clock pins to be sc_clocks and this is no longer needed.
=item /*verilator sformat*/
Attached to the final input of a function or task "input string" to
indicate the function or task should pass all remaining arguments through
$sformatf. This allows creation of DPI functions with $display like
behavior. See the test_regress/t/t_dpi_display.v file for an example.
=item /*verilator tracing_off*/ =item /*verilator tracing_off*/

View File

@ -692,6 +692,16 @@ void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) {
_VL_STRING_TO_VINT(obits, destp, output.length(), output.c_str()); _VL_STRING_TO_VINT(obits, destp, output.length(), output.c_str());
} }
string VL_SFORMATF_NX(const char* formatp, ...) {
va_list ap;
va_start(ap,formatp);
string output;
_vl_vsformat(output, formatp, ap);
va_end(ap);
return output;
}
void VL_WRITEF(const char* formatp, ...) { void VL_WRITEF(const char* formatp, ...) {
va_list ap; va_list ap;
va_start(ap,formatp); va_start(ap,formatp);

View File

@ -34,6 +34,7 @@
#include <string> #include <string>
//====================================================================== //======================================================================
// Conversion functions
extern string VL_CVT_PACK_STR_NW(int lwords, WDataInP lwp); extern string VL_CVT_PACK_STR_NW(int lwords, WDataInP lwp);
inline string VL_CVT_PACK_STR_NQ(QData lhs) { inline string VL_CVT_PACK_STR_NQ(QData lhs) {
@ -45,4 +46,6 @@ inline string VL_CVT_PACK_STR_NI(IData lhs) {
return VL_CVT_PACK_STR_NW(1, lw); return VL_CVT_PACK_STR_NW(1, lw);
} }
extern string VL_SFORMATF_NX(const char* formatp, ...);
#endif // Guard #endif // Guard

View File

@ -179,14 +179,15 @@ public:
VAR_CLOCK_ENABLE, // V3LinkParse moves to AstVar::attrClockEn VAR_CLOCK_ENABLE, // V3LinkParse moves to AstVar::attrClockEn
VAR_PUBLIC, // V3LinkParse moves to AstVar::sigPublic VAR_PUBLIC, // V3LinkParse moves to AstVar::sigPublic
VAR_PUBLIC_FLAT, // V3LinkParse moves to AstVar::sigPublic VAR_PUBLIC_FLAT, // V3LinkParse moves to AstVar::sigPublic
VAR_ISOLATE_ASSIGNMENTS // V3LinkParse moves to AstVar::attrIsolateAssign VAR_ISOLATE_ASSIGNMENTS, // V3LinkParse moves to AstVar::attrIsolateAssign
VAR_SFORMAT // V3LinkParse moves to AstVar::attrSFormat
}; };
enum en m_e; enum en m_e;
const char* ascii() const { const char* ascii() const {
static const char* names[] = { static const char* names[] = {
"BITS", "VAR_BASE", "BITS", "VAR_BASE",
"VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC", "VAR_PUBLIC_FLAT", "VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC", "VAR_PUBLIC_FLAT",
"VAR_ISOLATE_ASSIGNMENTS" "VAR_ISOLATE_ASSIGNMENTS", "VAR_SFORMAT"
}; };
return names[m_e]; return names[m_e];
}; };

View File

@ -513,6 +513,7 @@ private:
bool m_funcReturn:1; // Return variable for a function bool m_funcReturn:1; // Return variable for a function
bool m_attrClockEn:1;// User clock enable attribute bool m_attrClockEn:1;// User clock enable attribute
bool m_attrIsolateAssign:1;// User isolate_assignments attribute bool m_attrIsolateAssign:1;// User isolate_assignments attribute
bool m_attrSFormat:1;// User sformat attribute
bool m_fileDescr:1; // File descriptor bool m_fileDescr:1; // File descriptor
bool m_isConst:1; // Table contains constant data bool m_isConst:1; // Table contains constant data
bool m_isStatic:1; // Static variable bool m_isStatic:1; // Static variable
@ -525,7 +526,7 @@ private:
m_usedClock=false; m_usedParam=false; m_usedClock=false; m_usedParam=false;
m_sigPublic=false; m_sigModPublic=false; m_sigPublic=false; m_sigModPublic=false;
m_funcLocal=false; m_funcReturn=false; m_funcLocal=false; m_funcReturn=false;
m_attrClockEn=false; m_attrIsolateAssign=false; m_attrClockEn=false; m_attrIsolateAssign=false; m_attrSFormat=false;
m_fileDescr=false; m_isConst=false; m_isStatic=false; m_fileDescr=false; m_isConst=false; m_isStatic=false;
m_trace=false; m_trace=false;
} }
@ -584,6 +585,7 @@ public:
void attrFileDescr(bool flag) { m_fileDescr = flag; } void attrFileDescr(bool flag) { m_fileDescr = flag; }
void attrScClocked(bool flag) { m_scClocked = flag; } void attrScClocked(bool flag) { m_scClocked = flag; }
void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; } void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; }
void attrSFormat(bool flag) { m_attrSFormat = flag; }
void usedClock(bool flag) { m_usedClock = flag; } void usedClock(bool flag) { m_usedClock = flag; }
void usedParam(bool flag) { m_usedParam = flag; } void usedParam(bool flag) { m_usedParam = flag; }
void sigPublic(bool flag) { m_sigPublic = flag; } void sigPublic(bool flag) { m_sigPublic = flag; }
@ -638,6 +640,7 @@ public:
bool attrClockEn() const { return m_attrClockEn; } bool attrClockEn() const { return m_attrClockEn; }
bool attrFileDescr() const { return m_fileDescr; } bool attrFileDescr() const { return m_fileDescr; }
bool attrScClocked() const { return m_scClocked; } bool attrScClocked() const { return m_scClocked; }
bool attrSFormat() const { return m_attrSFormat; }
bool attrIsolateAssign() const { return m_attrIsolateAssign; } bool attrIsolateAssign() const { return m_attrIsolateAssign; }
uint32_t arrayElements() const; // 1, or total multiplication of all dimensions uint32_t arrayElements() const; // 1, or total multiplication of all dimensions
virtual string verilogKwd() const; virtual string verilogKwd() const;
@ -1518,6 +1521,7 @@ public:
virtual int instrCount() const { return instrCountPli(); } virtual int instrCount() const { return instrCountPli(); }
virtual V3Hash sameHash() const { return V3Hash(text()); } virtual V3Hash sameHash() const { return V3Hash(text()); }
virtual bool same(AstNode* samep) const { return text()==samep->castSFormatF()->text(); } virtual bool same(AstNode* samep) const { return text()==samep->castSFormatF()->text(); }
virtual string verilogKwd() const { return "$sformatf"; }
void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output
AstNode* exprsp() const { return op1p()->castNode(); } // op1 = Expressions to output AstNode* exprsp() const { return op1p()->castNode(); } // op1 = Expressions to output
string text() const { return m_text; } // * = Text to display string text() const { return m_text; } // * = Text to display
@ -1543,6 +1547,7 @@ public:
} }
ASTNODE_NODE_FUNCS(Display, DISPLAY) ASTNODE_NODE_FUNCS(Display, DISPLAY)
virtual void dump(ostream& str); virtual void dump(ostream& str);
virtual bool broken() const { return !fmtp(); }
virtual string verilogKwd() const { return (filep() ? (string)"$f"+(string)displayType().ascii() virtual string verilogKwd() const { return (filep() ? (string)"$f"+(string)displayType().ascii()
: (string)"$"+(string)displayType().ascii()); } : (string)"$"+(string)displayType().ascii()); }
virtual bool isGateOptimizable() const { return false; } virtual bool isGateOptimizable() const { return false; }
@ -1572,6 +1577,7 @@ struct AstSFormat : public AstNode {
setOp3p(lhsp); setOp3p(lhsp);
} }
ASTNODE_NODE_FUNCS(SFormat, SFORMAT) ASTNODE_NODE_FUNCS(SFormat, SFORMAT)
virtual bool broken() const { return !fmtp(); }
virtual string verilogKwd() const { return "$sformat"; } virtual string verilogKwd() const { return "$sformat"; }
virtual string emitVerilog() { V3ERROR_NA; return ""; } virtual string emitVerilog() { V3ERROR_NA; return ""; }
virtual string emitC() { V3ERROR_NA; return ""; } virtual string emitC() { V3ERROR_NA; return ""; }

View File

@ -95,7 +95,7 @@ private:
CleanState clstate = getCleanState(nodep); CleanState clstate = getCleanState(nodep);
if (clstate==CLEAN) return true; if (clstate==CLEAN) return true;
if (clstate==DIRTY) return false; if (clstate==DIRTY) return false;
nodep->v3fatalSrc("Unknown clean state on node."); nodep->v3fatalSrc("Unknown clean state on node: "+nodep->prettyTypeName());
return false; return false;
} }
void setClean(AstNode* nodep, bool isClean) { void setClean(AstNode* nodep, bool isClean) {
@ -243,6 +243,7 @@ private:
virtual void visit(AstSFormatF* nodep, AstNUser*) { virtual void visit(AstSFormatF* nodep, AstNUser*) {
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
insureCleanAndNext (nodep->exprsp()); insureCleanAndNext (nodep->exprsp());
setClean(nodep, true); // generates a string, so not relevant
} }
virtual void visit(AstUCStmt* nodep, AstNUser*) { virtual void visit(AstUCStmt* nodep, AstNUser*) {
nodep->iterateChildren(*this); nodep->iterateChildren(*this);

View File

@ -217,6 +217,9 @@ public:
virtual void visit(AstSFormat* nodep, AstNUser*) { virtual void visit(AstSFormat* nodep, AstNUser*) {
displayNode(nodep, nodep->fmtp()->scopeNamep(), nodep->fmtp()->text(), nodep->fmtp()->exprsp(), false); displayNode(nodep, nodep->fmtp()->scopeNamep(), nodep->fmtp()->text(), nodep->fmtp()->exprsp(), false);
} }
virtual void visit(AstSFormatF* nodep, AstNUser*) {
displayNode(nodep, nodep->scopeNamep(), nodep->text(), nodep->exprsp(), false);
}
virtual void visit(AstFScanF* nodep, AstNUser*) { virtual void visit(AstFScanF* nodep, AstNUser*) {
displayNode(nodep, NULL, nodep->text(), nodep->exprsp(), true); displayNode(nodep, NULL, nodep->text(), nodep->exprsp(), true);
} }
@ -1079,6 +1082,9 @@ void EmitCStmts::displayEmit(AstNode* nodep, bool isScan) {
putbs(","); putbs(",");
dispp->lhsp()->iterate(*this); dispp->lhsp()->iterate(*this);
putbs(","); putbs(",");
} else if (AstSFormatF* dispp = nodep->castSFormatF()) {
if (dispp) {}
puts("VL_SFORMATF_NX(");
} else { } else {
isStmt = true; isStmt = true;
nodep->v3fatalSrc("Unknown displayEmit node type"); nodep->v3fatalSrc("Unknown displayEmit node type");

View File

@ -207,6 +207,9 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
virtual void visit(AstSFormat* nodep, AstNUser*) { virtual void visit(AstSFormat* nodep, AstNUser*) {
visitNodeDisplay(nodep, nodep->lhsp(), nodep->fmtp()->text(), nodep->fmtp()->exprsp()); visitNodeDisplay(nodep, nodep->lhsp(), nodep->fmtp()->text(), nodep->fmtp()->exprsp());
} }
virtual void visit(AstSFormatF* nodep, AstNUser*) {
visitNodeDisplay(nodep, NULL, nodep->text(), nodep->exprsp());
}
virtual void visit(AstValuePlusArgs* nodep, AstNUser*) { virtual void visit(AstValuePlusArgs* nodep, AstNUser*) {
visitNodeDisplay(nodep, NULL, nodep->text(), nodep->exprsp()); visitNodeDisplay(nodep, NULL, nodep->text(), nodep->exprsp());
} }

View File

@ -287,6 +287,11 @@ private:
m_varp->attrIsolateAssign(true); m_varp->attrIsolateAssign(true);
nodep->unlinkFrBack()->deleteTree(); nodep=NULL; nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
} }
else if (nodep->attrType() == AstAttrType::VAR_SFORMAT) {
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
m_varp->attrSFormat(true);
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
}
} }
virtual void visit(AstDefImplicitDType* nodep, AstNUser*) { virtual void visit(AstDefImplicitDType* nodep, AstNUser*) {

View File

@ -517,6 +517,23 @@ vlsint64_t V3Number::toSQuad() const {
return (vlsint64_t)(extended); return (vlsint64_t)(extended);
} }
string V3Number::toString() const {
UASSERT(!isFourState(),"toString with 4-state "<<*this);
// Spec says always drop leading zeros, this isn't quite right, we space pad.
int bit=this->width()-1;
bool start=true;
while ((bit%8)!=7) bit++;
string str;
for (; bit>=0; bit -= 8) {
int v = bitsValue(bit-7, 8);
if (!start || v) {
str += (char)((v==0)?' ':v);
start = false; // Drop leading 0s
}
}
return str;
}
uint32_t V3Number::toHash() const { uint32_t V3Number::toHash() const {
return m_value[0]; return m_value[0];
} }

View File

@ -149,6 +149,7 @@ public:
vlsint32_t toSInt() const; vlsint32_t toSInt() const;
vluint64_t toUQuad() const; vluint64_t toUQuad() const;
vlsint64_t toSQuad() const; vlsint64_t toSQuad() const;
string toString() const;
uint32_t toHash() const; uint32_t toHash() const;
uint32_t dataWord(int word) const; uint32_t dataWord(int word) const;
uint32_t countOnes() const; uint32_t countOnes() const;

View File

@ -1168,6 +1168,7 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp)
// Find ports // Find ports
//map<string,int> name_to_pinnum; //map<string,int> name_to_pinnum;
int tpinnum = 0; // Note grammar starts pin counting at one int tpinnum = 0; // Note grammar starts pin counting at one
AstVar* sformatp = NULL;
for (AstNode* stmtp = taskStmtsp; stmtp; stmtp=stmtp->nextp()) { for (AstNode* stmtp = taskStmtsp; stmtp; stmtp=stmtp->nextp()) {
if (AstVar* portp = stmtp->castVar()) { if (AstVar* portp = stmtp->castVar()) {
if (portp->isIO()) { if (portp->isIO()) {
@ -1176,6 +1177,11 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp)
// That'll require a AstTpin or somesuch which will replace the ppinnum counting // That'll require a AstTpin or somesuch which will replace the ppinnum counting
//name_to_pinnum.insert(make_pair(portp->name(), tpinnum)); //name_to_pinnum.insert(make_pair(portp->name(), tpinnum));
tpinnum++; tpinnum++;
if (portp->attrSFormat()) {
sformatp = portp;
} else if (sformatp) {
nodep->v3error("/*verilator sformat*/ can only be applied to last argument of a function");
}
} }
} }
} }
@ -1184,15 +1190,17 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp)
int ppinnum = 0; int ppinnum = 0;
for (AstNode* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()) { for (AstNode* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()) {
if (ppinnum >= tpinnum) { if (ppinnum >= tpinnum) {
// Use v3warn so we'll only get the error once for each function if (sformatp) {
pinp->v3error("Too many arguments in function call to "<<nodep->taskp()->prettyTypeName()); tconnects.push_back(make_pair(sformatp, (AstNode*)NULL));
// We'll just delete them; seems less error prone than making a false argument } else {
pinp->unlinkFrBackWithNext()->deleteTree(); pinp=NULL; pinp->v3error("Too many arguments in function call to "<<nodep->taskp()->prettyTypeName());
break; // We'll just delete them; seems less error prone than making a false argument
} else { pinp->unlinkFrBackWithNext()->deleteTree(); pinp=NULL;
tconnects[ppinnum].second = pinp; break;
ppinnum++; }
} }
tconnects[ppinnum].second = pinp;
ppinnum++;
} }
while (ppinnum < tpinnum) { while (ppinnum < tpinnum) {

View File

@ -60,21 +60,22 @@
//###################################################################### //######################################################################
// Width state, as a visitor of each AstNode // Width state, as a visitor of each AstNode
enum Stage { PRELIM=1,FINAL=2,BOTH=3 }; enum Stage { PRELIM=1,FINAL=2,BOTH=3 };
class WidthVP : public AstNUser { class WidthVP : public AstNUser {
// Parameters to pass down hierarchy with visit functions. // Parameters to pass down hierarchy with visit functions.
int m_width; // Expression width, for (2+2), it's 32 bits int m_width; // Expression width, for (2+2), it's 32 bits
int m_minWidth; // Minimum width, for (2+2), it's 2 bits, for 32'2+32'2 it's 32 bits int m_minWidth; // Minimum width, for (2+2), it's 2 bits, for 32'2+32'2 it's 32 bits
Stage m_stage; // If true, report errors Stage m_stage; // If true, report errors
public: public:
WidthVP(int width, int minWidth, Stage stage) : m_width(width), m_minWidth(minWidth), m_stage(stage) {} WidthVP(int width, int minWidth, Stage stage) : m_width(width), m_minWidth(minWidth), m_stage(stage) {}
int width() const { return m_width; } int width() const { return m_width; }
int widthMin() const { return m_minWidth?m_minWidth:m_width; } int widthMin() const { return m_minWidth?m_minWidth:m_width; }
bool prelim() const { return m_stage&1; } bool prelim() const { return m_stage&1; }
bool final() const { return m_stage&2; } bool final() const { return m_stage&2; }
}; };
//######################################################################
class WidthVisitor : public AstNVisitor { class WidthVisitor : public AstNVisitor {
private: private:
@ -943,16 +944,36 @@ private:
// And do the arguments to the task/function too // And do the arguments to the task/function too
for (int accept_mode=1; accept_mode>=0; accept_mode--) { // Avoid duplicate code; just do inner stuff twice for (int accept_mode=1; accept_mode>=0; accept_mode--) { // Avoid duplicate code; just do inner stuff twice
V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp()); V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp());
for (V3TaskConnects::iterator it=tconnects.begin(); it!=tconnects.end(); ++it) { bool lastloop = false;
for (V3TaskConnects::iterator it=tconnects.begin(); !lastloop && it!=tconnects.end(); ++it) {
AstVar* portp = it->first; AstVar* portp = it->first;
AstNode* pinp = it->second; AstNode* pinp = it->second;
if (pinp!=NULL) { // Else argument error we'll find later if (pinp!=NULL) { // Else argument error we'll find later
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 if (portp->attrSFormat()
&& (!pinp->castSFormatF() || pinp->nextp())) { // Not already done
UINFO(4," sformat via metacomment: "<<nodep<<endl);
AstNRelinker handle;
pinp->unlinkFrBackWithNext(&handle); // Format + additional args, if any
AstNode* argsp = NULL;
if (pinp->nextp()) argsp = pinp->nextp()->unlinkFrBackWithNext();
string format;
if (pinp->castConst()) format = pinp->castConst()->num().toString();
else pinp->v3error("Format to $display-like function must have constant format string");
AstSFormatF* newp = new AstSFormatF(nodep->fileline(), format, argsp);
if (!newp->scopeNamep() && newp->formatScopeTracking()) {
newp->scopeNamep(new AstScopeName(newp->fileline()));
}
handle.relink(newp);
// Connection list is now incorrect (has extra args in it).
lastloop = true; // so exit early; next loop will correct it
}
else if (portp->basicp() && portp->basicp()->keyword()==AstBasicDTypeKwd::STRING
&& !pinp->castCvtPackString() && !pinp->castCvtPackString()
&& !(pinp->castVarRef() && pinp->castVarRef()->varp()->basicp()->keyword()==AstBasicDTypeKwd::STRING)) { && !(pinp->castVarRef() && pinp->castVarRef()->varp()->basicp()->keyword()==AstBasicDTypeKwd::STRING)) {
UINFO(4," Add CvtPackString: "<<pinp<<endl);
AstNRelinker handle; AstNRelinker handle;
pinp->unlinkFrBack(&handle); // No next, that's the next pin pinp->unlinkFrBack(&handle); // No next, that's the next pin
AstNode* newp = new AstCvtPackString(pinp->fileline(), pinp); AstNode* newp = new AstCvtPackString(pinp->fileline(), pinp);

View File

@ -589,6 +589,7 @@ escid \\[^ \t\f\r\n]+
"/*verilator public_flat*/" { FL; return yVL_PUBLIC_FLAT; } "/*verilator public_flat*/" { FL; return yVL_PUBLIC_FLAT; }
"/*verilator public_module*/" { FL; return yVL_PUBLIC_MODULE; } "/*verilator public_module*/" { FL; return yVL_PUBLIC_MODULE; }
"/*verilator sc_clock*/" { FL; return yVL_CLOCK; } "/*verilator sc_clock*/" { FL; return yVL_CLOCK; }
"/*verilator sformat*/" { FL; return yVL_SFORMAT; }
"/*verilator systemc_clock*/" { FL; return yVL_CLOCK; } "/*verilator systemc_clock*/" { FL; return yVL_CLOCK; }
"/*verilator tracing_off*/" {PARSEP->fileline()->tracingOn(false); } "/*verilator tracing_off*/" {PARSEP->fileline()->tracingOn(false); }
"/*verilator tracing_on*/" {PARSEP->fileline()->tracingOn(true); } "/*verilator tracing_on*/" {PARSEP->fileline()->tracingOn(true); }

View File

@ -416,6 +416,7 @@ class AstSenTree;
%token<fl> yVL_ISOLATE_ASSIGNMENTS "/*verilator isolate_assignments*/" %token<fl> yVL_ISOLATE_ASSIGNMENTS "/*verilator isolate_assignments*/"
%token<fl> yVL_NO_INLINE_MODULE "/*verilator no_inline_module*/" %token<fl> yVL_NO_INLINE_MODULE "/*verilator no_inline_module*/"
%token<fl> yVL_NO_INLINE_TASK "/*verilator no_inline_task*/" %token<fl> yVL_NO_INLINE_TASK "/*verilator no_inline_task*/"
%token<fl> yVL_SFORMAT "/*verilator sformat*/"
%token<fl> yVL_PARALLEL_CASE "/*verilator parallel_case*/" %token<fl> yVL_PARALLEL_CASE "/*verilator parallel_case*/"
%token<fl> yVL_PUBLIC "/*verilator public*/" %token<fl> yVL_PUBLIC "/*verilator public*/"
%token<fl> yVL_PUBLIC_FLAT "/*verilator public_flat*/" %token<fl> yVL_PUBLIC_FLAT "/*verilator public_flat*/"
@ -1525,6 +1526,7 @@ sigAttr<nodep>:
| yVL_PUBLIC { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC); } | yVL_PUBLIC { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC); }
| yVL_PUBLIC_FLAT { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT); } | yVL_PUBLIC_FLAT { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT); }
| yVL_ISOLATE_ASSIGNMENTS { $$ = new AstAttrOf($1,AstAttrType::VAR_ISOLATE_ASSIGNMENTS); } | yVL_ISOLATE_ASSIGNMENTS { $$ = new AstAttrOf($1,AstAttrType::VAR_ISOLATE_ASSIGNMENTS); }
| yVL_SFORMAT { $$ = new AstAttrOf($1,AstAttrType::VAR_SFORMAT); }
; ;
rangeListE<rangep>: // IEEE: [{packed_dimension}] rangeListE<rangep>: // IEEE: [{packed_dimension}]

32
test_regress/t/t_dpi_display.pl Executable file
View File

@ -0,0 +1,32 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 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.
compile (
v_flags2 => ["t/t_dpi_display_c.cpp"],
);
execute (
check_finished=>1,
expect=>quotemeta(
q{dpii_display_call:
dpii_display_call: c
dpii_display_call: co
dpii_display_call: cons
dpii_display_call: constant
dpii_display_call: constant_value
one10=0000000a
dpii_display_call: one10=0000000a
Mod=top.v 16= 10 10=0000000a
dpii_display_call: Mod=top.v 16= 10 10=0000000a
*-* All Finished *-*
}),
);
ok(1);
1;

View File

@ -0,0 +1,38 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// Copyright 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.
module t ();
`ifndef VERILATOR
`error "Only Verilator supports PLI-ish DPI calls and sformat conversion."
`endif
import "DPI-C" context dpii_display_call
= function void \$dpii_display (input string formatted /*verilator sformat*/ );
integer a;
initial begin
// Check variable width constant string conversions
$dpii_display("");
$dpii_display("c");
$dpii_display("co");
$dpii_display("cons");
$dpii_display("constant");
$dpii_display("constant_value");
a = $c("10"); // Don't optimize away "a"
$display ("one10=%x ",a); // Check single arg
$dpii_display("one10=%x ",a);
$display ("Mod=%m 16=%d 10=%x ",a,a); // Check multiarg
$dpii_display("Mod=%m 16=%d 10=%x ",a,a);
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,42 @@
// -*- C++ -*-
//*************************************************************************
//
// Copyright 2009-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.
//
//*************************************************************************
#include <stdio.h>
#include <svdpi.h>
//======================================================================
#if defined(VERILATOR)
# include "Vt_dpi_display__Dpi.h"
#elif defined(VCS)
# include "../vc_hdrs.h"
#elif defined(CADENCE)
# define NEED_EXTERNS
#else
# error "Unknown simulator for DPI test"
#endif
#ifdef NEED_EXTERNS
extern "C" {
extern void dpii_display_call (const char* c);
}
#endif
//======================================================================
void dpii_display_call(const char* c) {
VL_PRINTF("dpii_display_call: %s\n", c);
}