Support $ferror, #1638.

This commit is contained in:
Wilson Snyder 2020-04-05 11:22:05 -04:00
parent b617cd5549
commit a494ad5ec7
12 changed files with 74 additions and 2 deletions

View File

@ -7,7 +7,7 @@ The contributors that suggested a given feature are shown in []. Thanks!
** Add simplistic class support with many restrictions, see manual, #377.
**** Support $fflush without arguments, #1638.
**** Support $ferror, and $fflush without arguments, #1638.
* Verilator 4.032 2020-04-04

View File

@ -3867,7 +3867,8 @@ $dumplimit/$dumpportlimit are currently ignored.
The rarely used optional parameter to $finish and $stop is ignored.
=item $fopen, $fclose, $fdisplay, $feof, $fflush, $fgetc, $fgets, $fscanf, $fwrite
=item $fopen, $fclose, $fdisplay, $ferror, $feof, $fflush, $fgetc, $fgets,
$fscanf, $fwrite
File descriptors passed to the file PLI calls must be file descriptors, not
MCDs, which includes the mode parameter to $fopen being mandatory.

View File

@ -1148,6 +1148,13 @@ IData VL_FGETS_IXI(int obits, void* destp, IData fpi) VL_MT_SAFE {
return got;
}
IData VL_FERROR_IN(IData, std::string& outputr) VL_MT_SAFE {
// We ignore lhs/fpi - IEEE says "most recent error" so probably good enough
IData ret = errno;
outputr = std::string(::strerror(ret));
return ret;
}
IData VL_FOPEN_NI(const std::string& filename, IData mode) VL_MT_SAFE {
// While threadsafe, each thread can only access different file handles
char modez[5];

View File

@ -424,6 +424,7 @@ inline IData VL_LEN_IN(const std::string& ld) { return ld.length(); }
extern std::string VL_TOLOWER_NN(const std::string& ld);
extern std::string VL_TOUPPER_NN(const std::string& ld);
extern IData VL_FERROR_IN(IData fpi, std::string& outputr) VL_MT_SAFE;
extern IData VL_FOPEN_NI(const std::string& filename, IData mode) VL_MT_SAFE;
extern void VL_READMEM_N(bool hex, int bits, QData depth, int array_lsb,
const std::string& filename, void* memp, QData start,

View File

@ -4912,6 +4912,30 @@ public:
AstNode* filep() const { return lhsp(); }
};
class AstFError : public AstNodeMath {
public:
AstFError(FileLine* fl, AstNode* filep, AstNode* strp)
: ASTGEN_SUPER(fl) {
setOp1p(filep);
setOp2p(strp);
}
ASTNODE_NODE_FUNCS(FError)
virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; }
virtual string emitVerilog() { return "%f$ferror(%l, %r)"; }
virtual string emitC() { V3ERROR_NA_RETURN(""); }
virtual bool cleanOut() const { return true; }
virtual bool cleanLhs() const { return true; }
virtual bool sizeMattersLhs() const { return false; }
virtual int instrCount() const { return widthInstrs() * 64; }
virtual bool isPure() const { return false; } // SPECIAL: $display has 'visual' ordering
void filep(AstNode* nodep) { setOp1p(nodep); }
AstNode* filep() const { return op1p(); }
void strp(AstNode* nodep) { setOp2p(nodep); }
AstNode* strp() const { return op2p(); }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const { return true; }
};
class AstFGetC : public AstNodeUniop {
public:
AstFGetC(FileLine* fl, AstNode* lhsp)

View File

@ -482,6 +482,13 @@ public:
putsQuoted(nodep->text());
puts(")");
}
virtual void visit(AstFError* nodep) VL_OVERRIDE {
puts("VL_FERROR_IN(");
iterateAndNextNull(nodep->filep());
putbs(", ");
iterateAndNextNull(nodep->strp());
puts(")");
}
virtual void visit(AstFGetS* nodep) VL_OVERRIDE {
checkMaxWords(nodep);
emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), NULL);

View File

@ -102,6 +102,16 @@ private:
}
m_setRefLvalue = last_setRefLvalue;
}
virtual void visit(AstFError* nodep) VL_OVERRIDE {
bool last_setRefLvalue = m_setRefLvalue;
{
m_setRefLvalue = true;
iterateAndNextNull(nodep->filep());
iterateAndNextNull(nodep->strp());
m_setRefLvalue = false;
}
m_setRefLvalue = last_setRefLvalue;
}
virtual void visit(AstFFlush* nodep) VL_OVERRIDE {
bool last_setRefLvalue = m_setRefLvalue;
{

View File

@ -378,6 +378,10 @@ private:
iterateChildren(nodep);
expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef));
}
virtual void visit(AstFError* nodep) VL_OVERRIDE {
iterateChildren(nodep);
expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef));
}
virtual void visit(AstFEof* nodep) VL_OVERRIDE {
iterateChildren(nodep);
expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef));

View File

@ -3088,6 +3088,14 @@ private:
assertAtStatement(nodep);
iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
}
virtual void visit(AstFError* nodep) VL_OVERRIDE {
if (m_vup->prelim()) {
iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
// We only support string types, not packed array
iterateCheckString(nodep, "$ferror string result", nodep->strp(), BOTH);
nodep->dtypeSetLogicUnsized(32, 1, AstNumeric::SIGNED); // Spec says integer return
}
}
virtual void visit(AstFEof* nodep) VL_OVERRIDE {
if (m_vup->prelim()) {
iterateCheckFileDesc(nodep, nodep->filep(), BOTH);

View File

@ -217,6 +217,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"$fdisplayh" { FL; return yD_FDISPLAYH; }
"$fdisplayo" { FL; return yD_FDISPLAYO; }
"$feof" { FL; return yD_FEOF; }
"$ferror" { FL; return yD_FERROR; }
"$fflush" { FL; return yD_FFLUSH; }
"$fgetc" { FL; return yD_FGETC; }
"$fgets" { FL; return yD_FGETS; }

View File

@ -570,6 +570,7 @@ class AstSenTree;
%token<fl> yD_FDISPLAYH "$fdisplayh"
%token<fl> yD_FDISPLAYO "$fdisplayo"
%token<fl> yD_FEOF "$feof"
%token<fl> yD_FERROR "$ferror"
%token<fl> yD_FFLUSH "$fflush"
%token<fl> yD_FGETC "$fgetc"
%token<fl> yD_FGETS "$fgets"
@ -3331,6 +3332,7 @@ system_f_call_or_t<nodep>: // IEEE: part of system_tf_call (can be task or func)
| yD_DIMENSIONS '(' exprOrDataType ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_DIMENSIONS,$3); }
| yD_EXP '(' expr ')' { $$ = new AstExpD($1,$3); }
| yD_FEOF '(' expr ')' { $$ = new AstFEof($1,$3); }
| yD_FERROR '(' idClassSel ',' idClassSel ')' { $$ = new AstFError($1, $3, $5); }
| yD_FGETC '(' expr ')' { $$ = new AstFGetC($1,$3); }
| yD_FGETS '(' idClassSel ',' expr ')' { $$ = new AstFGetS($1,$3,$5); }
| yD_FREAD '(' idClassSel ',' expr ')' { $$ = new AstFRead($1,$3,$5,NULL,NULL); }

View File

@ -9,6 +9,8 @@
`define STRINGIFY(x) `"x`"
`define ratio_error(a,b) (((a)>(b) ? ((a)-(b)) : ((b)-(a))) /(a))
`define checkr(gotv,expv) do if (`ratio_error((gotv),(expv))>0.0001) begin $write("%%Error: %s:%0d: got=%g exp=%g\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
module t;
integer file;
@ -75,6 +77,11 @@ module t;
// The "r" is required so we get a FD not a MFD
file = $fopen("DOES_NOT_EXIST","r");
if (|file) $stop; // Should not exist, IE must return 0
// Check error function
s = "";
i = $ferror(file, s);
`checkh(i, 2);
`checks(s, "No such file or directory");
end
begin