Support and .
This commit is contained in:
parent
d608fd77b9
commit
c7d8eb126f
2
Changes
2
Changes
|
|
@ -18,6 +18,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
|||
|
||||
*** Support $test$plusargs and $value$plusargs, but see the docs!
|
||||
|
||||
*** Support $sformat and $swrite.
|
||||
|
||||
*** Add VARHIDDEN warning when signal name hides module name.
|
||||
|
||||
**** Fix MinGW compilation, bug184. [by Shankar Giri]
|
||||
|
|
|
|||
|
|
@ -1282,7 +1282,7 @@ output. [signal_32_bits = $c32("...");] This allows for compatibility with
|
|||
other simulators which require a differently named PLI function name for
|
||||
each different output width.
|
||||
|
||||
=item $display, $write, $fdisplay, $fwrite
|
||||
=item $display, $write, $fdisplay, $fwrite, $sformat, $swrite
|
||||
|
||||
Format arguments may use C fprintf sizes after the % escape. Per the
|
||||
Verilog standard, %x prints a number with the natural width, %0x prints a
|
||||
|
|
@ -1730,10 +1730,11 @@ $unsigned, $warning.
|
|||
|
||||
Generally supported.
|
||||
|
||||
=item $display, $write, $fdisplay, $fwrite
|
||||
=item $display, $write, $fdisplay, $fwrite, $swrite
|
||||
|
||||
$display and friends must have a constant format string as the first
|
||||
argument (as with C's printf), you cannot simply list variables standalone.
|
||||
argument (as with C's printf). The rare usage which lists variables
|
||||
standalone without a format is not supported.
|
||||
|
||||
=item $displayb, $displayh, $displayo, $writeb, $writeh, $writeo, etc
|
||||
|
||||
|
|
|
|||
|
|
@ -698,6 +698,16 @@ QData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode) {
|
|||
return VL_CVT_FP_Q(fopen(filenamez,modez));
|
||||
}
|
||||
|
||||
void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) {
|
||||
va_list ap;
|
||||
va_start(ap,formatp);
|
||||
string output;
|
||||
_vl_vsformat(output, formatp, ap);
|
||||
va_end(ap);
|
||||
|
||||
_VL_STRING_TO_VINT(obits, destp, output.length(), output.c_str());
|
||||
}
|
||||
|
||||
void VL_WRITEF(const char* formatp, ...) {
|
||||
va_list ap;
|
||||
va_start(ap,formatp);
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ extern WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp); ///< Zero reset a
|
|||
extern WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool is_modulus);
|
||||
|
||||
/// File I/O
|
||||
extern IData VL_FGETS_IXQ(int sbits, void* strgp, QData fpq);
|
||||
extern IData VL_FGETS_IXQ(int obits, void* destp, QData fpq);
|
||||
|
||||
extern QData VL_FOPEN_WI(int fnwords, WDataInP ofilename, IData mode);
|
||||
extern QData VL_FOPEN_QI(QData ofilename, IData mode);
|
||||
|
|
@ -221,6 +221,8 @@ extern IData VL_SSCANF_IIX(int lbits, IData ld, const char* formatp, ...);
|
|||
extern IData VL_SSCANF_IQX(int lbits, QData ld, const char* formatp, ...);
|
||||
extern IData VL_SSCANF_IWX(int lbits, WDataInP lwp, const char* formatp, ...);
|
||||
|
||||
extern void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...);
|
||||
|
||||
extern IData VL_TESTPLUSARGS_I(const char* formatp);
|
||||
extern IData VL_VALUEPLUSARGS_IW(int rbits, const char* prefixp, char fmt, WDataOutP rwp);
|
||||
|
||||
|
|
|
|||
|
|
@ -65,9 +65,7 @@ private:
|
|||
AstNode* timesp = nodep->exprsp(); if (timesp) timesp->unlinkFrBack();
|
||||
timesp = timesp->addNext(new AstTime(nodep->fileline()));
|
||||
nodep->exprsp(timesp);
|
||||
if (!nodep->scopeNamep()
|
||||
&& (nodep->name().find("%m") != string::npos
|
||||
|| nodep->name().find("%M") != string::npos)) {
|
||||
if (!nodep->scopeNamep() && nodep->formatScopeTracking()) {
|
||||
nodep->scopeNamep(new AstScopeName(nodep->fileline()));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
14
src/V3Ast.h
14
src/V3Ast.h
|
|
@ -1164,20 +1164,24 @@ public:
|
|||
void iterateChildren(AstNVisitor& v, AstNUser* vup=NULL) { }
|
||||
};
|
||||
|
||||
class AstNodePli : public AstNodeStmt {
|
||||
class AstNodeDisplay : public AstNodeStmt {
|
||||
// AstDisplay, AstSFormat or anything else with a format that might have %m
|
||||
string m_text;
|
||||
public:
|
||||
AstNodePli(FileLine* fl, const string& text, AstNode* exprsp)
|
||||
AstNodeDisplay(FileLine* fl, const string& text, AstNode* exprsp)
|
||||
: AstNodeStmt(fl), m_text(text) {
|
||||
addNOp1p(exprsp); }
|
||||
ASTNODE_BASE_FUNCS(NodePli)
|
||||
addNOp1p(exprsp); addNOp2p(NULL); }
|
||||
ASTNODE_BASE_FUNCS(NodeDisplay)
|
||||
virtual string name() const { return m_text; }
|
||||
virtual int instrCount() const { return instrCountPli(); }
|
||||
void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output
|
||||
AstNode* exprsp() const { return op1p()->castNode(); } // op1 = Expressions to output
|
||||
string text() const { return m_text; } // * = Text to display
|
||||
void text(const string& text) { m_text=text; }
|
||||
// op2p,op3p... used by AstDisplay
|
||||
AstScopeName* scopeNamep() const { return op2p()->castScopeName(); }
|
||||
void scopeNamep(AstNode* nodep) { setNOp2p(nodep); }
|
||||
bool formatScopeTracking() const { // Track scopeNamep(); Ok if over-eager
|
||||
return (name().find("%m") != string::npos || name().find("%M") != string::npos); }
|
||||
};
|
||||
|
||||
struct AstNodeText : public AstNode {
|
||||
|
|
|
|||
|
|
@ -1382,15 +1382,15 @@ public:
|
|||
void ignoreOverlap(bool flag) { m_ignoreOverlap = flag; }
|
||||
};
|
||||
|
||||
struct AstDisplay : public AstNodePli {
|
||||
struct AstDisplay : public AstNodeDisplay {
|
||||
// Parents: stmtlist
|
||||
// Children: file which must be a varref, MATH to print
|
||||
private:
|
||||
AstDisplayType m_displayType;
|
||||
public:
|
||||
AstDisplay(FileLine* fileline, AstDisplayType dispType, const string& text, AstNode* filep, AstNode* exprsp)
|
||||
: AstNodePli (fileline, text, exprsp) {
|
||||
setNOp2p(filep);
|
||||
: AstNodeDisplay (fileline, text, exprsp) {
|
||||
setNOp3p(filep);
|
||||
m_displayType = dispType;
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(Display, DISPLAY)
|
||||
|
|
@ -1406,14 +1406,37 @@ public:
|
|||
virtual bool same(AstNode* samep) const {
|
||||
return displayType()==samep->castDisplay()->displayType()
|
||||
&& text()==samep->castDisplay()->text(); }
|
||||
// op1 used by AstNodePli
|
||||
// op1,op2 used by AstNodeDisplay
|
||||
AstDisplayType displayType() const { return m_displayType; }
|
||||
void displayType(AstDisplayType type) { m_displayType = type; }
|
||||
bool addNewline() const { return displayType().addNewline(); } // * = Add a newline for $display
|
||||
AstNode* filep() const { return op2p(); }
|
||||
void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); }
|
||||
AstScopeName* scopeNamep() const { return op3p()->castScopeName(); }
|
||||
void scopeNamep(AstNode* nodep) { setNOp3p(nodep); }
|
||||
AstNode* filep() const { return op3p(); }
|
||||
void filep(AstNodeVarRef* nodep) { setNOp3p(nodep); }
|
||||
};
|
||||
|
||||
struct AstSFormat : public AstNodeDisplay {
|
||||
// Parents: statement container
|
||||
// Children: string to load
|
||||
// Children: varrefs to print
|
||||
AstSFormat(FileLine* fileline, AstNode* lhsp, const string& text, AstNode* exprsp)
|
||||
: AstNodeDisplay (fileline, text, exprsp) {
|
||||
setOp3p(lhsp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(SFormat, SFORMAT)
|
||||
virtual string verilogKwd() const { return "$sformat"; }
|
||||
virtual string emitVerilog() { V3ERROR_NA; return ""; }
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual bool isGateOptimizable() const { return false; }
|
||||
virtual bool isPredictOptimizable() const { return true; }
|
||||
virtual bool isSplittable() const { return true; }
|
||||
virtual bool isOutputter() const { return false; }
|
||||
virtual bool cleanOut() { return false; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(text()); }
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return text()==samep->castSFormat()->text(); }
|
||||
// op1,op2 used by AstNodeDisplay
|
||||
AstNode* lhsp() const { return op3p(); }
|
||||
void lhsp(AstNode* nodep) { setOp3p(nodep); }
|
||||
};
|
||||
|
||||
struct AstFClose : public AstNodeStmt {
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ private:
|
|||
nodep->iterateChildren(*this);
|
||||
insureClean(nodep->condp());
|
||||
}
|
||||
virtual void visit(AstNodePli* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeDisplay* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
insureCleanAndNext (nodep->exprsp());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1380,7 +1380,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstDisplay* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeDisplay* nodep, AstNUser*) {
|
||||
// Substitute constants into displays. The main point of this is to
|
||||
// simplify assertion methodologies which call functions with display's.
|
||||
// This eliminates a pile of wide temps, and makes the C a whole lot more readable.
|
||||
|
|
|
|||
|
|
@ -114,9 +114,9 @@ public:
|
|||
putbs("VL_ASSIGNBIT_");
|
||||
emitIQW(selp->fromp());
|
||||
if (nodep->rhsp()->isAllOnesV()) {
|
||||
putbs("O(");
|
||||
puts("O(");
|
||||
} else {
|
||||
putbs("I(");
|
||||
puts("I(");
|
||||
}
|
||||
puts(cvtToStr(nodep->widthMin())+",");
|
||||
selp->lsbp()->iterateAndNext(*this); puts(", ");
|
||||
|
|
@ -124,7 +124,7 @@ public:
|
|||
} else {
|
||||
putbs("VL_ASSIGNSEL_");
|
||||
emitIQW (selp->fromp());
|
||||
putbs("II");
|
||||
puts("II");
|
||||
emitIQW(nodep->rhsp());
|
||||
puts("(");
|
||||
puts(cvtToStr(nodep->widthMin())+",");
|
||||
|
|
@ -230,6 +230,9 @@ public:
|
|||
if (nodep->addNewline()) text += "\n";
|
||||
displayNode(nodep, text, nodep->exprsp(), false);
|
||||
}
|
||||
virtual void visit(AstSFormat* nodep, AstNUser*) {
|
||||
displayNode(nodep, nodep->text(), nodep->exprsp(), false);
|
||||
}
|
||||
virtual void visit(AstFScanF* nodep, AstNUser*) {
|
||||
displayNode(nodep, nodep->text(), nodep->exprsp(), true);
|
||||
}
|
||||
|
|
@ -278,9 +281,9 @@ public:
|
|||
puts(cvtToStr(nodep->exprsp()->widthMin())); // Note argument width, not node width (which is always 32)
|
||||
putbs(",");
|
||||
putsQuoted(prefix);
|
||||
putbs(",'");
|
||||
puts(cvtToStr(format));
|
||||
putbs("',");
|
||||
putbs(",");
|
||||
puts("'"); puts(cvtToStr(format)); puts("'");
|
||||
puts(",");
|
||||
nodep->exprsp()->iterateAndNext(*this);
|
||||
puts(")");
|
||||
}
|
||||
|
|
@ -1050,6 +1053,13 @@ void EmitCStmts::displayEmit(AstNode* nodep, bool isScan) {
|
|||
} else {
|
||||
puts("VL_WRITEF(");
|
||||
}
|
||||
} else if (AstSFormat* dispp = nodep->castSFormat()) {
|
||||
isStmt = true;
|
||||
puts("VL_SFORMAT_X(");
|
||||
puts(cvtToStr(dispp->lhsp()->widthMin()));
|
||||
putbs(",");
|
||||
dispp->lhsp()->iterate(*this);
|
||||
putbs(",");
|
||||
} else {
|
||||
isStmt = true;
|
||||
nodep->v3fatalSrc("Unknown displayEmit node type");
|
||||
|
|
@ -1165,8 +1175,8 @@ void EmitCStmts::displayNode(AstNode* nodep, const string& vformat, AstNode* exp
|
|||
case 'm': {
|
||||
emitDispState.pushFormat("%S");
|
||||
emitDispState.pushArg(NULL, "vlSymsp->name()");
|
||||
if (!nodep->castDisplay()) nodep->v3fatalSrc("Non-Display with %m");
|
||||
AstScopeName* scopenamep = nodep->castDisplay()->scopeNamep();
|
||||
if (!nodep->castNodeDisplay()) nodep->v3fatalSrc("Non-Display with %m");
|
||||
AstScopeName* scopenamep = nodep->castNodeDisplay()->scopeNamep();
|
||||
if (!scopenamep) nodep->v3fatalSrc("Display with %m but no AstScopeName");
|
||||
for (AstText* textp=scopenamep->scopeAttrp(); textp; textp=textp->nextp()->castText()) {
|
||||
emitDispState.pushFormat(textp->text());
|
||||
|
|
|
|||
|
|
@ -172,10 +172,10 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
virtual void visit(AstCoverInc*, AstNUser*) {} // N/A
|
||||
virtual void visit(AstCoverToggle*, AstNUser*) {} // N/A
|
||||
|
||||
void visitNodeDisplay(AstNode* nodep, AstNode* filep, const string& text, AstNode* exprsp) {
|
||||
void visitNodeDisplay(AstNode* nodep, AstNode* fileOrStrgp, const string& text, AstNode* exprsp) {
|
||||
putbs(nodep->verilogKwd());
|
||||
putbs(" (");
|
||||
if (filep) { filep->iterateAndNext(*this); putbs(","); }
|
||||
if (fileOrStrgp) { fileOrStrgp->iterateAndNext(*this); putbs(","); }
|
||||
puts("\"");
|
||||
putsNoTracking(text); // Not putsQuoted, as display text contains \ already
|
||||
puts("\"");
|
||||
|
|
@ -194,6 +194,9 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
virtual void visit(AstSScanF* nodep, AstNUser*) {
|
||||
visitNodeDisplay(nodep, nodep->fromp(), nodep->text(), nodep->exprsp());
|
||||
}
|
||||
virtual void visit(AstSFormat* nodep, AstNUser*) {
|
||||
visitNodeDisplay(nodep, nodep->lhsp(), nodep->text(), nodep->exprsp());
|
||||
}
|
||||
virtual void visit(AstValuePlusArgs* nodep, AstNUser*) {
|
||||
visitNodeDisplay(nodep, NULL, nodep->text(), nodep->exprsp());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -174,6 +174,16 @@ private:
|
|||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
virtual void visit(AstSFormat* nodep, AstNUser*) {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{
|
||||
m_setRefLvalue = true;
|
||||
nodep->lhsp()->iterateAndNext(*this);
|
||||
m_setRefLvalue = false;
|
||||
nodep->exprsp()->iterateAndNext(*this);
|
||||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
|
||||
// Nodes that change LValue state
|
||||
virtual void visit(AstSel* nodep, AstNUser*) {
|
||||
|
|
|
|||
|
|
@ -302,21 +302,29 @@ private:
|
|||
nodep->iterateChildren(*this);
|
||||
expectFormat(nodep, nodep->text(), nodep->exprsp(), true);
|
||||
}
|
||||
virtual void visit(AstDisplay* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->filep()) expectDescriptor(nodep, nodep->filep()->castNodeVarRef());
|
||||
|
||||
void expectNodeDisplay(AstNodeDisplay* nodep) {
|
||||
// AstSFormat also handled here
|
||||
expectFormat(nodep, nodep->text(), nodep->exprsp(), false);
|
||||
if ((nodep->castDisplay() && nodep->castDisplay()->displayType().needScopeTracking())
|
||||
|| nodep->formatScopeTracking()) {
|
||||
nodep->scopeNamep(new AstScopeName(nodep->fileline()));
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeDisplay* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
expectNodeDisplay(nodep);
|
||||
}
|
||||
virtual void visit(AstDisplay* nodep, AstNUser* vup) {
|
||||
nodep->iterateChildren(*this);
|
||||
expectNodeDisplay(nodep);
|
||||
if (nodep->filep()) expectDescriptor(nodep, nodep->filep()->castNodeVarRef());
|
||||
if (!m_assertp
|
||||
&& (nodep->displayType() == AstDisplayType::INFO
|
||||
|| nodep->displayType() == AstDisplayType::WARNING
|
||||
|| nodep->displayType() == AstDisplayType::ERROR
|
||||
|| nodep->displayType() == AstDisplayType::FATAL)) {
|
||||
nodep->v3error(nodep->verilogKwd()+" only allowed under a assertion.");
|
||||
}
|
||||
if (nodep->displayType().needScopeTracking()
|
||||
|| nodep->name().find("%m") != string::npos
|
||||
|| nodep->name().find("%M") != string::npos) {
|
||||
nodep->scopeNamep(new AstScopeName(nodep->fileline()));
|
||||
nodep->v3error(nodep->verilogKwd()+" only allowed under an assertion.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ private:
|
|||
}
|
||||
|
||||
// VISITORS - Special
|
||||
virtual void visit(AstDisplay* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeDisplay* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
//
|
||||
UINFO(9," Display in "<<nodep->text()<<endl);
|
||||
|
|
|
|||
|
|
@ -545,7 +545,7 @@ private:
|
|||
|
||||
// default
|
||||
// These types are definately not reducable
|
||||
// AstCoverInc, AstNodePli, AstArraySel, AstStop, AstFinish,
|
||||
// AstCoverInc, AstDisplay, AstArraySel, AstStop, AstFinish,
|
||||
// AstRand, AstTime, AstUCFunc, AstCCall, AstCStmt, AstUCStmt
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
badNodeType(nodep);
|
||||
|
|
|
|||
|
|
@ -682,7 +682,7 @@ private:
|
|||
widthCheck(nodep,"Assign RHS",nodep->rhsp(),awidth,awidth);
|
||||
//if (debug()) nodep->dumpTree(cout," AssignOut: ");
|
||||
}
|
||||
virtual void visit(AstNodePli* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeDisplay* nodep, AstNUser*) {
|
||||
// Excludes NodeDisplay, see below
|
||||
// TOP LEVEL NODE
|
||||
// Just let all arguments seek their natural sizes
|
||||
|
|
|
|||
|
|
@ -180,10 +180,12 @@ escid \\[^ \t\f\r\n]+
|
|||
"$removal" { FL; return yaTIMINGSPEC; }
|
||||
"$setup" { FL; return yaTIMINGSPEC; }
|
||||
"$setuphold" { FL; return yaTIMINGSPEC; }
|
||||
"$sformat" { FL; return yD_SFORMAT; }
|
||||
"$skew" { FL; return yaTIMINGSPEC; }
|
||||
"$sscanf" { FL; return yD_SSCANF; }
|
||||
"$stime" { FL; return yD_STIME; }
|
||||
"$stop" { FL; return yD_STOP; }
|
||||
"$swrite" { FL; return yD_SWRITE; }
|
||||
"$test$plusargs" { FL; return yD_TESTPLUSARGS; }
|
||||
"$time" { FL; return yD_TIME; }
|
||||
"$timeskew" { FL; return yaTIMINGSPEC; }
|
||||
|
|
|
|||
|
|
@ -355,10 +355,12 @@ class AstSenTree;
|
|||
%token<fl> yD_RANDOM "$random"
|
||||
%token<fl> yD_READMEMB "$readmemb"
|
||||
%token<fl> yD_READMEMH "$readmemh"
|
||||
%token<fl> yD_SFORMAT "$sformat"
|
||||
%token<fl> yD_SIGNED "$signed"
|
||||
%token<fl> yD_SSCANF "$sscanf"
|
||||
%token<fl> yD_STIME "$stime"
|
||||
%token<fl> yD_STOP "$stop"
|
||||
%token<fl> yD_SWRITE "$swrite"
|
||||
%token<fl> yD_TESTPLUSARGS "$test$plusargs"
|
||||
%token<fl> yD_TIME "$time"
|
||||
%token<fl> yD_UNIT "$unit"
|
||||
|
|
@ -1926,6 +1928,9 @@ system_t_call<nodep>: // IEEE: system_tf_call (as task)
|
|||
| yD_STOP parenE { $$ = new AstStop($1); }
|
||||
| yD_STOP '(' expr ')' { $$ = new AstStop($1); }
|
||||
//
|
||||
| yD_SFORMAT '(' expr ',' str commaVRDListE ')' { $$ = new AstSFormat($1,$3,*$5,$6); }
|
||||
| yD_SWRITE '(' expr ',' str commaVRDListE ')' { $$ = new AstSFormat($1,$3,*$5,$6); }
|
||||
//
|
||||
| yD_DISPLAY parenE { $$ = new AstDisplay($1,AstDisplayType::DISPLAY,"", NULL,NULL); }
|
||||
| yD_DISPLAY '(' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::DISPLAY,*$3,NULL,$4); }
|
||||
| yD_WRITE '(' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::WRITE, *$3,NULL,$4); }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
#!/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 (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2008 by Wilson Snyder.
|
||||
|
||||
`include "verilated.v"
|
||||
|
||||
module t;
|
||||
|
||||
// Note $sscanf already tested elsewhere
|
||||
|
||||
reg [3:0] n;
|
||||
reg [63:0] q;
|
||||
reg [16*8:1] wide;
|
||||
|
||||
reg [48*8:1] str;
|
||||
reg [48*8:1] str2;
|
||||
|
||||
initial begin
|
||||
n = 4'b1100;
|
||||
q = 64'h1234_5678_abcd_0123;
|
||||
wide = "hello-there12345";
|
||||
$sformat(str, "n=%b q=%d w=%s", n, q, wide);
|
||||
`ifdef TEST_VERBOSE $display("str=%0s",str); `endif
|
||||
if (str !== "n=1100 q= 1311768467750060323 w=hello-there12345") $stop;
|
||||
|
||||
q = {q[62:0],1'b1};
|
||||
$swrite(str2, "n=%b q=%d w=%s", n, q, wide);
|
||||
`ifdef TEST_VERBOSE $display("str2=%0s",str2); `endif
|
||||
if (str2 !== "n=1100 q= 2623536935500120647 w=hello-there12345") $stop;
|
||||
|
||||
$swrite(str2, "mod=%m");
|
||||
`ifdef TEST_VERBOSE $display("str2=%0s",str2); `endif
|
||||
`ifdef verilator
|
||||
if (str2 !== "mod=TOP.v") $stop;
|
||||
`else
|
||||
if (str2 !== "mod=top.t") $stop;
|
||||
`endif
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#!/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.
|
||||
|
||||
top_filename("t/t_sys_sformat.v");
|
||||
|
||||
compile (
|
||||
# Avoid inlining our simple example, to make sure verilated.h works right
|
||||
verilator_flags2 => ["-O0"],
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
Loading…
Reference in New Issue