Support $value$plusargs with variables, bug1165.

This commit is contained in:
Wilson Snyder 2017-05-18 22:41:43 -04:00
parent ce879122bb
commit b032fce962
12 changed files with 149 additions and 98 deletions

View File

@ -11,6 +11,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
*** Support arrayed parameter overrides, bug1153. [John Stevenson]
*** Support $value$plusargs with variables, bug1165. [Wesley Terpstra]
**** Support modport access to un-modport objects, bug1161. [Todd Strader]
**** Add stack trace when can't optimize function, bug1158. [Todd Strader]

View File

@ -302,8 +302,7 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
bool inPct = false;
bool widthSet = false;
int width = 0;
const char* pos = formatp;
for (; *pos; ++pos) {
for (const char* pos = formatp; *pos; ++pos) {
if (!inPct && pos[0]=='%') {
pctp = pos;
inPct = true;
@ -1077,22 +1076,36 @@ IData VL_TESTPLUSARGS_I(const char* formatp) {
else return 1;
}
IData VL_VALUEPLUSARGS_IN(int, const char* prefixp, char, string& ldr) {
const string& match = VerilatedImp::argPlusMatch(prefixp);
const char* dp = match.c_str() + 1 /*leading + */ + strlen(prefixp);
if (match == "") return 0;
ldr = string(dp);
return 1;
}
IData VL_VALUEPLUSARGS_INW(int rbits, const string& ld, WDataOutP rwp) {
string prefix;
bool inPct = false;
bool done = false;
char fmt = ' ';
for (const char* posp = ld.c_str(); !done && *posp; ++posp) {
if (!inPct && posp[0]=='%') {
inPct = true;
} else if (!inPct) { // Normal text
prefix += *posp;
} else { // Format character
switch (tolower(*posp)) {
case '%':
prefix += *posp;
inPct = false;
break;
default:
fmt = *posp;
done = true;
break;
}
}
}
IData VL_VALUEPLUSARGS_IW(int rbits, const char* prefixp, char fmt, WDataOutP rwp) {
const string& match = VerilatedImp::argPlusMatch(prefixp);
const char* dp = match.c_str() + 1 /*leading + */ + strlen(prefixp);
const string& match = VerilatedImp::argPlusMatch(prefix.c_str());
const char* dp = match.c_str() + 1 /*leading + */ + prefix.length();
if (match == "") return 0;
VL_ZERO_RESET_W(rbits, rwp);
switch (tolower(fmt)) {
case '%':
break;
case 'd':
vlsint64_t ld;
sscanf(dp,"%30" VL_PRI64 "d",&ld);
@ -1108,18 +1121,47 @@ IData VL_VALUEPLUSARGS_IW(int rbits, const char* prefixp, char fmt, WDataOutP rw
case 'x':
_vl_vsss_based(rwp,rbits, 4, dp, 0, (int)strlen(dp));
break;
case 's':
for (int i=0, lsb=0, pos=((int)strlen(dp))-1; i<rbits && pos>=0; pos--) {
_vl_vsss_setbit(rwp,rbits,lsb, 8, dp[pos]); lsb+=8;
case 's': // string/no conversion
for (int i=0, lsb=0, posp=((int)strlen(dp))-1; i<rbits && posp>=0; posp--) {
_vl_vsss_setbit(rwp,rbits,lsb, 8, dp[posp]); lsb+=8;
}
break;
default: // Compile time should have found all errors before this
vl_fatal (__FILE__, __LINE__, "", "$value$plusargs format error");
break;
case 'e': //FALLTHRU - Unsupported
case 'f': //FALLTHRU - Unsupported
case 'g': //FALLTHRU - Unsupported
default: // Other simulators simply return 0 in these cases and don't error out
return 0;
}
_VL_CLEAN_INPLACE_W(rbits,rwp);
return 1;
}
IData VL_VALUEPLUSARGS_INN(int rbits, const string& ld, string& rdr) {
string prefix;
bool inPct = false;
bool done = false;
for (const char* posp = ld.c_str(); !done && *posp; ++posp) {
if (!inPct && posp[0]=='%') {
inPct = true;
} else if (!inPct) { // Normal text
prefix += *posp;
} else { // Format character
switch (tolower(*posp)) {
case '%':
prefix += *posp;
inPct = false;
break;
default:
done = true;
break;
}
}
}
const string& match = VerilatedImp::argPlusMatch(prefix.c_str());
const char* dp = match.c_str() + 1 /*leading + */ + prefix.length();
if (match == "") return 0;
rdr = string(dp);
return 1;
}
const char* vl_mc_scan_plusargs(const char* prefixp) {
const string& match = VerilatedImp::argPlusMatch(prefixp);

View File

@ -66,6 +66,19 @@ extern void VL_READMEM_N(bool hex, int width, int depth, int array_lsb, int fnwo
extern IData VL_SSCANF_INX(int lbits, const string& ld, const char* formatp, ...);
extern void VL_SFORMAT_X(int obits_ignored, string &output, const char* formatp, ...);
extern string VL_SFORMATF_NX(const char* formatp, ...);
extern IData VL_VALUEPLUSARGS_IN(int rbits, const char* prefixp, char fmt, string& ldr);
extern IData VL_VALUEPLUSARGS_INW(int rbits, const string& ld, WDataOutP rdp);
inline IData VL_VALUEPLUSARGS_INI(int rbits, const string& ld, IData& rdr) {
IData rwp[1];
IData got = VL_VALUEPLUSARGS_INW(rbits,ld,rwp);
if (got) rdr = rwp[0];
return got;
}
inline IData VL_VALUEPLUSARGS_INQ(int rbits, const string& ld, QData& rdr) {
IData rwp[2];
IData got = VL_VALUEPLUSARGS_INW(rbits,ld,rwp);
if (got) rdr = VL_SET_QW(rwp);
return got;
}
extern IData VL_VALUEPLUSARGS_INN(int, const string& ld, string& rdr);
#endif // Guard

View File

@ -2658,28 +2658,24 @@ public:
class 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);
AstValuePlusArgs(FileLine* fileline, AstNode* searchp, AstNode* outp)
: AstNodeMath (fileline) {
setOp1p(searchp); setOp2p(outp);
}
ASTNODE_NODE_FUNCS(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 string emitVerilog() { return "%f$value$plusargs(%l, %k%r)"; }
virtual string emitC() { V3ERROR_NA; return ""; }
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(); } // 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; }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(AstNode* samep) const { return true; }
AstNode* searchp() const { return op1p(); } // op1 = Search expression
void searchp(AstNode* nodep) { setOp1p(nodep); }
AstNode* outp() const { return op2p(); } // op2 = Expressions to output
void outp(AstNode* nodep) { setOp2p(nodep); }
};
class AstTestPlusArgs : public AstNodeMath {

View File

@ -277,54 +277,15 @@ public:
displayNode(nodep, NULL, nodep->text(), nodep->exprsp(), true);
}
virtual void visit(AstValuePlusArgs* nodep) {
string prefix;
char format = '?';
bool pct=false;
int got=0;
string txt = nodep->text();
for (string::const_iterator it=txt.begin(); it!=txt.end(); ++it) {
char ch = *it;
if (pct) {
pct = false;
switch (tolower(ch)) {
case '%':
prefix += ch;
break;
case 'd': // FALLTHRU
case 'o': // FALLTHRU
case 'h': // FALLTHRU
case 'x': // FALLTHRU
case 'b': // FALLTHRU
case 'v': // FALLTHRU
case 's':
got++; format = tolower(ch);
break;
case 'e': // FALLTHRU
case 'f': // FALLTHRU
case 'g':
got++; format = tolower(ch);
nodep->v3error("Unsupported $value$plusargs format qualifier: '"<<ch<<"'"<<endl);
break;
default:
got++;
nodep->v3error("Illegal $value$plusargs format qualifier: '"<<ch<<"'"<<endl);
break;
}
}
else if (ch == '%') pct = true;
else prefix += ch;
}
if (got!=1) nodep->v3error("Missing or extra $value$plusargs format qualifier: '"<<nodep->text()<<"'"<<endl);
puts("VL_VALUEPLUSARGS_I");
emitIQW(nodep->exprsp());
puts("VL_VALUEPLUSARGS_IN");
emitIQW(nodep->outp());
puts("(");
puts(cvtToStr(nodep->exprsp()->widthMin())); // Note argument width, not node width (which is always 32)
putbs(",");
putsQuoted(prefix);
putbs(",");
puts("'"); puts(cvtToStr(format)); puts("'");
puts(cvtToStr(nodep->outp()->widthMin()));
puts(",");
nodep->exprsp()->iterateAndNext(*this);
emitCvtPackStr(nodep->searchp());
puts(",");
putbs("");
nodep->outp()->iterateAndNext(*this);
puts(")");
}
virtual void visit(AstTestPlusArgs* nodep) {
@ -618,6 +579,23 @@ public:
puts(nodep->hiername());
puts(nodep->varp()->name());
}
void emitCvtPackStr(AstNode* nodep) {
if (AstConst* constp = nodep->castConst()) {
putbs("string(");
putsQuoted(constp->num().toString());
puts(")");
} else {
putbs("VL_CVT_PACK_STR_N");
emitIQW(nodep);
puts("(");
if (nodep->isWide()) {
puts(cvtToStr(nodep->widthWords())); // Note argument width, not node width (which is always 32)
puts(",");
}
nodep->iterateAndNext(*this);
puts(")");
}
}
void emitConstant(AstConst* nodep, AstVarRef* assigntop, const string& assignString) {
// Put out constant set to the specified variable, or given variable in a string
if (nodep->num().isFourState()) {

View File

@ -238,10 +238,6 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
virtual void visit(AstSFormatF* nodep) {
visitNodeDisplay(nodep, NULL, nodep->text(), nodep->exprsp());
}
virtual void visit(AstValuePlusArgs* nodep) {
visitNodeDisplay(nodep, NULL, nodep->text(), nodep->exprsp());
}
virtual void visit(AstFOpen* nodep) {
putfs(nodep,nodep->verilogKwd());
putbs(" (");

View File

@ -174,8 +174,10 @@ private:
virtual void visit(AstValuePlusArgs* nodep) {
bool last_setRefLvalue = m_setRefLvalue;
{
m_setRefLvalue = false;
nodep->searchp()->iterateAndNext(*this);
m_setRefLvalue = true;
nodep->exprsp()->iterateAndNext(*this);
nodep->outp()->iterateAndNext(*this);
}
m_setRefLvalue = last_setRefLvalue;
}

View File

@ -2094,7 +2094,8 @@ private:
}
virtual void visit(AstValuePlusArgs* nodep) {
if (m_vup->prelim()) {
userIterateAndNext(nodep->exprsp(), WidthVP(SELF,BOTH).p());
userIterateAndNext(nodep->searchp(), WidthVP(SELF,BOTH).p());
userIterateAndNext(nodep->outp(), WidthVP(SELF,BOTH).p());
nodep->dtypeSetSigned32(); // Spec says integer return
}
}

View File

@ -2710,12 +2710,12 @@ system_f_call<nodep>: // IEEE: system_tf_call (as func)
| yD_SQRT '(' expr ')' { $$ = new AstSqrtD($1,$3); }
| yD_SSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstSScanF($1,*$5,$3,$6); }
| yD_STIME parenE { $$ = new AstSel($1,new AstTime($1),0,32); }
| yD_SYSTEM '(' expr ')' { $$ = new AstSystemF($1,$3); }
| yD_SYSTEM '(' expr ')' { $$ = new AstSystemF($1,$3); }
| yD_TESTPLUSARGS '(' str ')' { $$ = new AstTestPlusArgs($1,*$3); }
| yD_TIME parenE { $$ = new AstTime($1); }
| yD_UNPACKED_DIMENSIONS '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_UNPK_DIMENSIONS,$3); }
| yD_UNSIGNED '(' expr ')' { $$ = new AstUnsigned($1,$3); }
| yD_VALUEPLUSARGS '(' str ',' expr ')' { $$ = new AstValuePlusArgs($1,*$3,$5); }
| yD_VALUEPLUSARGS '(' expr ',' expr ')' { $$ = new AstValuePlusArgs($1,$3,$5); }
;
exprOrDataType<nodep>: // expr | data_type: combined to prevent conflicts

View File

@ -8,6 +8,8 @@ module t;
integer p_i;
reg [7*8:1] p_str;
string sv_str;
reg [7*8:1] p_in;
string sv_in;
initial begin
if ($test$plusargs("PLUS")!==1) $stop;
@ -29,14 +31,34 @@ module t;
if ($value$plusargs("INT=%o", p_i)!==1) $stop;
if (p_i !== 32'o1234) $stop;
p_str = "none";
if ($value$plusargs("IN%s", p_str)!==1) $stop;
$display("str='%s'",p_str);
if (p_str !== "T=1234") $stop;
sv_str = "none";
if ($value$plusargs("IN%s", sv_str)!==1) $stop;
$display("str='%s'",sv_str);
if (sv_str != "T=1234") $stop;
p_in = "IN%s";
`ifdef VERILATOR
p_in = $c(p_in); // Prevent constant propagation
`endif
sv_str = "none";
if ($value$plusargs(p_in, sv_str)!==1) $stop;
$display("str='%s'",sv_str);
if (sv_str != "T=1234") $stop;
sv_in = "INT=%d";
`ifdef VERILATOR
if ($c1(0)) sv_in = "NEVER"; // Prevent constant propagation
`endif
p_i = 0;
if ($value$plusargs(sv_in, p_i)!==1) $stop;
$display("i='%d'",p_i);
if (p_i !== 32'd1234) $stop;
$write("*-* All Finished *-*\n");
$finish;
end

View File

@ -8,13 +8,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# 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.*},
);
);
execute (
check_finished=>1,
);
ok(1);
1;

View File

@ -17,6 +17,7 @@ module t;
// BAD: Multi letter
if ($value$plusargs("INT=%x%x", p_i)!==0) $stop;
$stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule