diff --git a/Changes b/Changes index 24bca0beb..81a383916 100644 --- a/Changes +++ b/Changes @@ -16,6 +16,8 @@ indicates the contributor was also the author of the fix; Thanks! *** Support declarations in loop initializers, bug172. [by Byron Bradley] +*** Support $test$plusargs and $value$plusargs, but see the docs! + *** Add VARHIDDEN warning when signal name hides module name. **** Fix MinGW compilation, bug184. [by Shankar Giri] diff --git a/bin/verilator b/bin/verilator index 27d06e877..55d14a92b 100755 --- a/bin/verilator +++ b/bin/verilator @@ -768,6 +768,7 @@ We'll compile this example into C++. #include "Vour.h" #include "verilated.h" int main(int argc, char **argv, char **env) { + Verilated::commandArgs(argc, argv); Vour* top = new Vour; while (!Verilated::gotFinish()) { top->eval(); } exit(0); @@ -825,6 +826,7 @@ This is an example similar to the above, but using SystemPerl. cat <sc_main.cpp #include "Vour.h" int sc_main(int argc, char **argv) { + Verilated::commandArgs(argc, argv); sc_clock clk ("clk",10, 0.5, 3, true); Vour* top; top = new Vour("top"); // SP_CELL (top, Vour); @@ -1080,7 +1082,9 @@ example: return main_time; } - int main() { + int main(int argc, char** argv) { + Verilated::commandArgs(argc, argv); // Remember args + top = new Vtop; // Create instance top->reset_l = 0; // Set some inputs @@ -1784,6 +1788,22 @@ arrays. Treated as $time. +=item $test$plusargs, $value$plusargs + +Supported, but the instantiating C++/SystemC testbench must call + + Verilated::commandArgs(argc, argv); + +to register the command line before calling $test$plusargs or +$value$plusargs. + +=item $timeformat + +Not supported as Verilator needs to determine all formatting at compile +time. Generally you can just ifdef them out for no ill effect. Note also +VL_TIME_MULTIPLER can be defined at compile time to move the decimal point +when displaying all times, model wide. + =back =head1 ERRORS AND WARNINGS diff --git a/include/verilated.cpp b/include/verilated.cpp index 8338f4ddb..65f23c7ea 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -25,6 +25,7 @@ #include "verilated.h" #include +#include #define VL_VALUE_STRING_MAX_WIDTH 1024 ///< Max static char array for VL_VALUE_STRING @@ -37,6 +38,38 @@ bool Verilated::s_calcUnusedSigs = false; bool Verilated::s_gotFinish = false; bool Verilated::s_assertOn = true; +//=========================================================================== +// Local Implementation Globals +// (Not in Verilated as they can be slow, and we want to mimimize the STL imports) + +class VerilatedImp { +protected: + friend class Verilated; + typedef vector ArgVec; + static ArgVec s_argVec; // Argument list + static bool s_argVecLoaded; // Ever loaded argument list + // METHODS +public: // But only for this C file + static string argPlusMatch(const char* prefixp) { + int len = strlen(prefixp); + if (!s_argVecLoaded) { + s_argVecLoaded = true; // Complain only once + vl_fatal("unknown",0,"", + "%Error: Verilog called $test$plusargs or $value$plusargs without" + " testbench C first calling Verilated::commandArgs(argc,argv)."); + } + for (ArgVec::iterator it=s_argVec.begin(); it!=s_argVec.end(); ++it) { + if ((*it)[0]=='+') { + if (0==strncmp(prefixp, it->c_str()+1, len)) return *it; + } + } + return ""; + } +}; + +VerilatedImp::ArgVec VerilatedImp::s_argVec; +bool VerilatedImp::s_argVecLoaded = false; + //=========================================================================== // User definable functions @@ -441,6 +474,32 @@ static inline void _vl_vsss_setbit(WDataOutP owp, int obits, int lsb, int nbits, VL_ASSIGNBIT_WI(0, lsb, owp, ld & 1); } } +static inline void _vl_vsss_based(WDataOutP owp, int obits, int baseLog2, const char* strp, int posstart, int posend) { + // Read in base "2^^baseLog2" digits from strp[posstart..posend-1] into owp of size obits. + int lsb = 0; + for (int i=0, pos=posend-1; i=posstart; pos--) { + switch (tolower (strp[pos])) { + case 'x': case 'z': case '?': //FALLTHRU + case '0': lsb += baseLog2; break; + case '1': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 1); lsb+=baseLog2; break; + case '2': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 2); lsb+=baseLog2; break; + case '3': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 3); lsb+=baseLog2; break; + case '4': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 4); lsb+=baseLog2; break; + case '5': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 5); lsb+=baseLog2; break; + case '6': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 6); lsb+=baseLog2; break; + case '7': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 7); lsb+=baseLog2; break; + case '8': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 8); lsb+=baseLog2; break; + case '9': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 9); lsb+=baseLog2; break; + case 'a': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 10); lsb+=baseLog2; break; + case 'b': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 11); lsb+=baseLog2; break; + case 'c': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 12); lsb+=baseLog2; break; + case 'd': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 13); lsb+=baseLog2; break; + case 'e': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 14); lsb+=baseLog2; break; + case 'f': _vl_vsss_setbit(owp,obits,lsb, baseLog2, 15); lsb+=baseLog2; break; + case '_': break; + } + } +} IData _vl_vsscanf(FILE* fp, // If a fscanf int fbits, WDataInP fromp, // Else if a sscanf @@ -480,7 +539,6 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf // Deal with all read-and-scan somethings // Note LSBs are preserved if there's an overflow const int obits = va_arg(ap, int); - int lsb = 0; WData qowp[2]; WDataOutP owp = qowp; if (obits > VL_QUADSIZE) { @@ -500,6 +558,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf _vl_vsss_read(fp,floc,fromp, tmp, NULL); if (!tmp[0]) goto done; int pos = strlen(tmp)-1; + int lsb = 0; for (int i=0; i=0; pos--) { _vl_vsss_setbit(owp,obits,lsb, 8, tmp[pos]); lsb+=8; } @@ -507,7 +566,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf } case 'd': { // Signed decimal _vl_vsss_skipspace(fp,floc,fromp); - _vl_vsss_read(fp,floc,fromp, tmp, "0123456789+-xz?_"); + _vl_vsss_read(fp,floc,fromp, tmp, "0123456789+-xXzZ?_"); if (!tmp[0]) goto done; vlsint64_t ld; sscanf(tmp,"%lld",&ld); @@ -517,7 +576,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf case 't': // FALLTHRU // Time case 'u': { // Unsigned decimal _vl_vsss_skipspace(fp,floc,fromp); - _vl_vsss_read(fp,floc,fromp, tmp, "0123456789+-xz?_"); + _vl_vsss_read(fp,floc,fromp, tmp, "0123456789+-xXzZ?_"); if (!tmp[0]) goto done; QData ld; sscanf(tmp,"%llu",&ld); @@ -526,67 +585,23 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf } case 'b': { _vl_vsss_skipspace(fp,floc,fromp); - _vl_vsss_read(fp,floc,fromp, tmp, "01xz?_"); + _vl_vsss_read(fp,floc,fromp, tmp, "01xXzZ?_"); if (!tmp[0]) goto done; - int pos = strlen(tmp)-1; - for (int i=0; i=0; pos--) { - switch(tmp[pos]) { - case 'x': case 'z': case '?': //FALLTHRU - case '0': lsb++; break; - case '1': _vl_vsss_setbit(owp,obits,lsb, 1, 1); lsb++; break; - case '_': break; - } - } + _vl_vsss_based(owp,obits, 1, tmp, 0, strlen(tmp)); break; } case 'o': { _vl_vsss_skipspace(fp,floc,fromp); - _vl_vsss_read(fp,floc,fromp, tmp, "01234567xz?_"); + _vl_vsss_read(fp,floc,fromp, tmp, "01234567xXzZ?_"); if (!tmp[0]) goto done; - int pos = strlen(tmp)-1; - for (int i=0; i=0; pos--) { - switch(tmp[pos]) { - case 'x': case 'z': case '?': //FALLTHRU - case '0': lsb+=3; break; - case '1': _vl_vsss_setbit(owp,obits,lsb, 3, 1); lsb+=3; break; - case '2': _vl_vsss_setbit(owp,obits,lsb, 3, 2); lsb+=3; break; - case '3': _vl_vsss_setbit(owp,obits,lsb, 3, 3); lsb+=3; break; - case '4': _vl_vsss_setbit(owp,obits,lsb, 3, 4); lsb+=3; break; - case '5': _vl_vsss_setbit(owp,obits,lsb, 3, 5); lsb+=3; break; - case '6': _vl_vsss_setbit(owp,obits,lsb, 3, 6); lsb+=3; break; - case '7': _vl_vsss_setbit(owp,obits,lsb, 3, 7); lsb+=3; break; - case '_': break; - } - } + _vl_vsss_based(owp,obits, 3, tmp, 0, strlen(tmp)); break; } case 'x': { _vl_vsss_skipspace(fp,floc,fromp); - _vl_vsss_read(fp,floc,fromp, tmp, "0123456789abcdefxz?_"); + _vl_vsss_read(fp,floc,fromp, tmp, "0123456789abcdefABCDEFxXzZ?_"); if (!tmp[0]) goto done; - int pos = strlen(tmp)-1; - for (int i=0; i=0; pos--) { - switch(tmp[pos]) { - case 'x': case 'z': case '?': //FALLTHRU - case '0': lsb+=4; break; - case '1': _vl_vsss_setbit(owp,obits,lsb, 4, 1); lsb+=4; break; - case '2': _vl_vsss_setbit(owp,obits,lsb, 4, 2); lsb+=4; break; - case '3': _vl_vsss_setbit(owp,obits,lsb, 4, 3); lsb+=4; break; - case '4': _vl_vsss_setbit(owp,obits,lsb, 4, 4); lsb+=4; break; - case '5': _vl_vsss_setbit(owp,obits,lsb, 4, 5); lsb+=4; break; - case '6': _vl_vsss_setbit(owp,obits,lsb, 4, 6); lsb+=4; break; - case '7': _vl_vsss_setbit(owp,obits,lsb, 4, 7); lsb+=4; break; - case '8': _vl_vsss_setbit(owp,obits,lsb, 4, 8); lsb+=4; break; - case '9': _vl_vsss_setbit(owp,obits,lsb, 4, 9); lsb+=4; break; - case 'a': _vl_vsss_setbit(owp,obits,lsb, 4, 10); lsb+=4; break; - case 'b': _vl_vsss_setbit(owp,obits,lsb, 4, 11); lsb+=4; break; - case 'c': _vl_vsss_setbit(owp,obits,lsb, 4, 12); lsb+=4; break; - case 'd': _vl_vsss_setbit(owp,obits,lsb, 4, 13); lsb+=4; break; - case 'e': _vl_vsss_setbit(owp,obits,lsb, 4, 14); lsb+=4; break; - case 'f': _vl_vsss_setbit(owp,obits,lsb, 4, 15); lsb+=4; break; - case '_': break; - } - } + _vl_vsss_based(owp,obits, 4, tmp, 0, strlen(tmp)); break; } default: @@ -851,6 +866,48 @@ void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords, } } +IData VL_TESTPLUSARGS_I(const char* formatp) { + string match = VerilatedImp::argPlusMatch(formatp); + if (match == "") return 0; + else return 1; +} + +IData VL_VALUEPLUSARGS_IW(int rbits, const char* prefixp, char fmt, WDataOutP rwp) { + string match = VerilatedImp::argPlusMatch(prefixp); + const char* dp = match.c_str() + 1 /*leading + */ + strlen(prefixp); + if (match == "") return 0; + VL_ZERO_RESET_W(rbits, rwp); + switch (tolower(fmt)) { + case '%': + break; + case 'd': + vlsint64_t ld; + sscanf(dp,"%lld",&ld); + VL_SET_WQ(rwp,ld); + break; + case 'b': + _vl_vsss_based(rwp,rbits, 1, dp, 0, strlen(dp)); + break; + case 'o': + _vl_vsss_based(rwp,rbits, 3, dp, 0, strlen(dp)); + break; + case 'h': //FALLTHRU + case 'x': + _vl_vsss_based(rwp,rbits, 4, dp, 0, strlen(dp)); + break; + case 's': + for (int i=0, lsb=0, pos=strlen(dp)-1; i=0; pos--) { + _vl_vsss_setbit(rwp,rbits,lsb, 8, dp[pos]); lsb+=8; + } + break; + default: // Compile time should have found all errors before this + vl_fatal (__FILE__, __LINE__, "", "$value$plusargs format error"); + break; + } + _VL_CLEAN_INPLACE_W(rbits,rwp); + return 1; +} + //=========================================================================== // Verilated:: Methods @@ -870,6 +927,15 @@ const char* Verilated::catName(const char* n1, const char* n2) { return strp; } +void Verilated::commandArgs(int argc, const char** argv) { + VerilatedImp::s_argVec.clear(); + for (int i=0; icastNode(); } }; +struct AstValuePlusArgs : public AstNodeMath { + // Parents: expr + // Child: variable to set. If NULL then this is a $test$plusargs instead of $value$plusargs +private: + string m_text; +public: + AstValuePlusArgs(FileLine* fileline, const string& text, AstNode* exprsp) + : AstNodeMath (fileline), m_text(text) { + setOp1p(exprsp); + } + ASTNODE_NODE_FUNCS(ValuePlusArgs, VALUEPLUSARGS) + virtual string name() const { return m_text; } + virtual string verilogKwd() const { return "$value$plusargs"; } + virtual string emitVerilog() { return verilogKwd(); } + virtual string emitC() { return "VL_VALUEPLUSARGS_%nq(%lw, %P, NULL)"; } + virtual bool isGateOptimizable() const { return false; } + virtual bool isPredictOptimizable() const { return false; } + virtual bool cleanOut() { return true; } + virtual V3Hash sameHash() const { return V3Hash(text()); } + virtual bool same(AstNode* samep) const { + return text()==samep->castValuePlusArgs()->text(); } + AstNode* exprsp() const { return op1p()->castNode(); } // op1 = Expressions to output + void exprsp(AstNode* nodep) { setOp1p(nodep); } // op1 = Expressions to output + string text() const { return m_text; } // * = Text to display + void text(const string& text) { m_text=text; } +}; + +struct AstTestPlusArgs : public AstNodeMath { + // Parents: expr + // Child: variable to set. If NULL then this is a $test$plusargs instead of $value$plusargs +private: + string m_text; +public: + AstTestPlusArgs(FileLine* fileline, const string& text) + : AstNodeMath (fileline), m_text(text) { } + ASTNODE_NODE_FUNCS(TestPlusArgs, TESTPLUSARGS) + virtual string name() const { return m_text; } + virtual string verilogKwd() const { return "$test$plusargs"; } + virtual string emitVerilog() { return verilogKwd(); } + virtual string emitC() { return "VL_VALUEPLUSARGS_%nq(%lw, %P, NULL)"; } + virtual bool isGateOptimizable() const { return false; } + virtual bool isPredictOptimizable() const { return false; } + virtual bool cleanOut() { return true; } + virtual V3Hash sameHash() const { return V3Hash(text()); } + virtual bool same(AstNode* samep) const { + return text()==samep->castTestPlusArgs()->text(); } + string text() const { return m_text; } // * = Text to display + void text(const string& text) { m_text=text; } +}; + struct AstGenFor : public AstNodeFor { AstGenFor(FileLine* fileline, AstNode* initsp, AstNode* condp, AstNode* incsp, AstNode* bodysp) diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 92020be49..893d7b165 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -236,6 +236,59 @@ public: virtual void visit(AstSScanF* nodep, AstNUser*) { displayNode(nodep, nodep->text(), nodep->exprsp(), true); } + virtual void visit(AstValuePlusArgs* nodep, AstNUser*) { + string prefix; + char format = '?'; + bool pct=false; + int got=0; + for (const char* cp = nodep->text().c_str(); *cp; cp++) { + if (pct) { + pct = false; + switch (tolower(*cp)) { + case '%': + prefix += *cp; + break; + case 'd': // FALLTHRU + case 'o': // FALLTHRU + case 'h': // FALLTHRU + case 'x': // FALLTHRU + case 'b': // FALLTHRU + case 's': + got++; format = tolower(*cp); + break; + case 'e': // FALLTHRU + case 'f': // FALLTHRU + case 'g': + got++; format = tolower(*cp); + nodep->v3error("Unsupported $value$plusargs format qualifier: '"<<*cp<<"'"<v3error("Illegal $value$plusargs format qualifier: '"<<*cp<<"'"<v3error("Missing or extra $value$plusargs format qualifier: '"<text()<<"'"<exprsp()); + puts("("); + puts(cvtToStr(nodep->exprsp()->widthMin())); // Note argument width, not node width (which is always 32) + putbs(","); + putsQuoted(prefix); + putbs(",'"); + puts(cvtToStr(format)); + putbs("',"); + nodep->exprsp()->iterateAndNext(*this); + puts(")"); + } + virtual void visit(AstTestPlusArgs* nodep, AstNUser*) { + puts("VL_TESTPLUSARGS_I("); + putsQuoted(nodep->text()); + puts(")"); + } virtual void visit(AstFGetS* nodep, AstNUser*) { checkMaxWords(nodep); emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), NULL); diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 51fad083f..29df8d5b2 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -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(AstValuePlusArgs* nodep, AstNUser*) { + visitNodeDisplay(nodep, NULL, nodep->text(), nodep->exprsp()); + } virtual void visit(AstFOpen* nodep, AstNUser*) { putbs(nodep->verilogKwd()); diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp index 51f0f29bd..1a625d132 100644 --- a/src/V3LinkLValue.cpp +++ b/src/V3LinkLValue.cpp @@ -166,6 +166,14 @@ private: } m_setRefLvalue = last_setRefLvalue; } + virtual void visit(AstValuePlusArgs* nodep, AstNUser*) { + bool last_setRefLvalue = m_setRefLvalue; + { + m_setRefLvalue = true; + nodep->exprsp()->iterateAndNext(*this); + } + m_setRefLvalue = last_setRefLvalue; + } // Nodes that change LValue state virtual void visit(AstSel* nodep, AstNUser*) { diff --git a/src/V3Signed.cpp b/src/V3Signed.cpp index ddccae0e6..b2949599a 100644 --- a/src/V3Signed.cpp +++ b/src/V3Signed.cpp @@ -86,6 +86,8 @@ private: virtual void visit(AstFGetS* nodep, AstNUser*) { signed_Ou_Ix(nodep); } virtual void visit(AstFScanF* nodep, AstNUser*) { signed_Ou_Ix(nodep); } virtual void visit(AstSScanF* nodep, AstNUser*) { signed_Ou_Ix(nodep); } + virtual void visit(AstTestPlusArgs* nodep, AstNUser*) { signed_Ou_Ix(nodep); } + virtual void visit(AstValuePlusArgs* nodep, AstNUser*) { signed_Ou_Ix(nodep); } // virtual void visit(AstConcat* nodep, AstNUser*) { signed_Ou_Ix(nodep); } virtual void visit(AstReplicate* nodep, AstNUser*) { signed_Ou_Ix(nodep); } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 0edb3183c..88417c45b 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -753,6 +753,13 @@ private: nodep->lsbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); nodep->msbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); } + virtual void visit(AstTestPlusArgs* nodep, AstNUser* vup) { + nodep->width(32,32); + } + virtual void visit(AstValuePlusArgs* nodep, AstNUser* vup) { + nodep->exprsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); + nodep->width(32,32); + } virtual void visit(AstUCStmt* nodep, AstNUser*) { // TOP LEVEL NODE // Just let all arguments seek their natural sizes diff --git a/src/verilog.l b/src/verilog.l index 318526504..779335011 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -184,8 +184,10 @@ escid \\[^ \t\f\r\n]+ "$sscanf" { FL; return yD_SSCANF; } "$stime" { FL; return yD_STIME; } "$stop" { FL; return yD_STOP; } + "$test$plusargs" { FL; return yD_TESTPLUSARGS; } "$time" { FL; return yD_TIME; } "$timeskew" { FL; return yaTIMINGSPEC; } + "$value$plusargs" { FL; return yD_VALUEPLUSARGS; } "$width" { FL; return yaTIMINGSPEC; } "$write" { FL; return yD_WRITE; } /* Keywords */ diff --git a/src/verilog.y b/src/verilog.y index 2b71097f2..633d83893 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -353,9 +353,11 @@ class AstSenTree; %token yD_SSCANF "$sscanf" %token yD_STIME "$stime" %token yD_STOP "$stop" +%token yD_TESTPLUSARGS "$test$plusargs" %token yD_TIME "$time" %token yD_UNIT "$unit" %token yD_UNSIGNED "$unsigned" +%token yD_VALUEPLUSARGS "$value$plusargs" %token yD_WARNING "$warning" %token yD_WRITE "$write" %token yD_aIGNORE "${ignored-bbox-sys}" @@ -1947,7 +1949,9 @@ system_f_call: // IEEE: system_tf_call (as func) | yD_SIGNED '(' expr ')' { $$ = new AstSigned($1,$3); } | yD_STIME { $$ = new AstSel($1,new AstTime($1),0,32); } | yD_TIME { $$ = new AstTime($1); } + | yD_TESTPLUSARGS '(' str ')' { $$ = new AstTestPlusArgs($1,*$3); } | yD_UNSIGNED '(' expr ')' { $$ = new AstUnsigned($1,$3); } + | yD_VALUEPLUSARGS '(' str ',' expr ')' { $$ = new AstValuePlusArgs($1,*$3,$5); } ; list_of_argumentsE: // IEEE: [list_of_arguments] diff --git a/test_c/sim_main.cpp b/test_c/sim_main.cpp index 79fa06db1..329fd322f 100644 --- a/test_c/sim_main.cpp +++ b/test_c/sim_main.cpp @@ -23,6 +23,7 @@ int main(int argc, char **argv, char **env) { if (0 && argc && argv && env) {} // Prevent unused variable warnings top = new Vtop; // Create instance of module + Verilated::commandArgs(argc, argv); Verilated::debug(0); #if VM_TRACE // If verilator was invoked with --trace diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 1a027b6ca..72ae8ab3f 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -248,6 +248,7 @@ sub new { ))], v_flags2 => [], # Overridden in some sim files v_other_filenames => [], # After the filename so we can spec multiple files + all_run_flags => [], # IV iv => 0, iv_flags => [split(/\s+/,"+define+iverilog -o $self->{obj_dir}/simiv")], @@ -495,6 +496,7 @@ sub execute { fails=>$param{fails}, cmd=>["$self->{obj_dir}/simiv", @{$param{ivrun_flags}}, + @{$param{all_run_flags}}, ]); } if ($param{nc}) { @@ -502,13 +504,16 @@ sub execute { fails=>$param{fails}, cmd=>[($ENV{VERILATOR_NCVERILOG}||"ncverilog"), @{$param{ncrun_flags}}, + @{$param{all_run_flags}}, ]); } if ($param{vcs}) { #my $fh = IO::File->new(">simv.key") or die "%Error: $! simv.key,"; #$fh->print("quit\n"); $fh->close; $self->_run(logfile=>"$self->{obj_dir}/vcs_sim.log", - cmd=>["./simv",], + cmd=>["./simv", + @{$param{all_run_flags}}, + ], %param, expect=>undef, # vcs expect isn't the same ); @@ -518,6 +523,7 @@ sub execute { ) { $self->_run(logfile=>"$self->{obj_dir}/vl_sim.log", cmd=>["$self->{obj_dir}/$param{VM_PREFIX}", + @{$param{all_run_flags}}, ], %param, ); @@ -731,6 +737,7 @@ sub _make_main { print $fh "int main(int argc, char **argv, char **env) {\n"; print $fh " double sim_time = $self->{sim_time};\n"; } + print $fh " Verilated::commandArgs(argc, argv);\n"; print $fh " Verilated::debug(".($self->{verilated_debug}?1:0).");\n"; print $fh " Verilated::randReset(".$self->{verilated_randReset}.");\n" if defined $self->{verilated_randReset}; print $fh " topp = new $VM_PREFIX (\"TOP\");\n"; diff --git a/test_regress/t/t_sys_plusargs.pl b/test_regress/t/t_sys_plusargs.pl new file mode 100755 index 000000000..a58e3c1f8 --- /dev/null +++ b/test_regress/t/t_sys_plusargs.pl @@ -0,0 +1,14 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } + +compile ( + v_flags2 => ['-v', 't/t_flag_libinc.v'], + ); + +execute ( + check_finished=>1, + all_run_flags => ['+PLUS +INT=1234 +STRSTR'], + ); + +ok(1); +1; diff --git a/test_regress/t/t_sys_plusargs.v b/test_regress/t/t_sys_plusargs.v new file mode 100644 index 000000000..c8908ed0d --- /dev/null +++ b/test_regress/t/t_sys_plusargs.v @@ -0,0 +1,38 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2009 by Wilson Snyder. + +module t; + + integer p_i; + reg [7*8:1] p_str; + + initial begin + if ($test$plusargs("PLUS")!==1) $stop; + if ($test$plusargs("PLUSNOT")!==0) $stop; + if ($test$plusargs("PL")!==1) $stop; + //if ($test$plusargs("")!==1) $stop; // Simulators differ in this answer + if ($test$plusargs("NOTTHERE")!==0) $stop; + + p_i = 10; + if ($value$plusargs("NOTTHERE%d", p_i)!==0) $stop; + if (p_i !== 10) $stop; + + if ($value$plusargs("INT=%d", p_i)!==1) $stop; + if (p_i !== 32'd1234) $stop; + + if ($value$plusargs("INT=%H", p_i)!==1) $stop; // tests uppercase % also + if (p_i !== 32'h1234) $stop; + + if ($value$plusargs("INT=%o", p_i)!==1) $stop; + if (p_i !== 32'o1234) $stop; + + if ($value$plusargs("IN%s", p_str)!==1) $stop; + $display("str='%s'",p_str); + if (p_str !== "T=1234") $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_sys_plusargs_bad.pl b/test_regress/t/t_sys_plusargs_bad.pl new file mode 100755 index 000000000..2495a77b9 --- /dev/null +++ b/test_regress/t/t_sys_plusargs_bad.pl @@ -0,0 +1,21 @@ +#!/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 ( + fails=>$Self->{v3}, + expect=> +q{%Error: t/t_sys_plusargs_bad.v:\d+: Missing or extra \$value\$plusargs format qualifier: 'NOTTHERE' +%Error: t/t_sys_plusargs_bad.v:\d+: Illegal \$value\$plusargs format qualifier: 'z' +%Error: t/t_sys_plusargs_bad.v:\d+: Missing or extra \$value\$plusargs format qualifier: 'INT=%x%x' +%Error: Exiting due to.*}, + ); + +ok(1); +1; + diff --git a/test_regress/t/t_sys_plusargs_bad.v b/test_regress/t/t_sys_plusargs_bad.v new file mode 100644 index 000000000..672873cf9 --- /dev/null +++ b/test_regress/t/t_sys_plusargs_bad.v @@ -0,0 +1,22 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2009 by Wilson Snyder. + +module t; + + integer p_i; + + initial begin + // BAD: Missing argument + if ($value$plusargs("NOTTHERE", p_i)!==0) $stop; + + // BAD: Bad letter + if ($value$plusargs("INT=%z", p_i)!==0) $stop; + + // BAD: Multi letter + if ($value$plusargs("INT=%x%x", p_i)!==0) $stop; + + $stop; + end +endmodule diff --git a/test_sp/sc_main.cpp b/test_sp/sc_main.cpp index 11bbcb90e..87114f9ce 100644 --- a/test_sp/sc_main.cpp +++ b/test_sp/sc_main.cpp @@ -26,6 +26,7 @@ Vtop *top; int sc_main(int argc, char* argv[]) { + Verilated::commandArgs(argc, argv); Verilated::randReset(2); Verilated::debug(0); // We compiled with it on for testing, turn it back off diff --git a/test_verilated/sim_main.cpp b/test_verilated/sim_main.cpp index 9e4d352c7..9bbdbdc90 100644 --- a/test_verilated/sim_main.cpp +++ b/test_verilated/sim_main.cpp @@ -19,6 +19,7 @@ double sc_time_stamp () { } int main(int argc, char **argv, char **env) { + Verilated::commandArgs(argc, argv); Verilated::debug(0); // We compiled with it on for testing, turn it back off top = new Vvgen;