Support $fseek, $ftell, $frewind, bug1496.

This commit is contained in:
Wilson Snyder 2019-09-03 21:28:15 -04:00
parent 3bc260c55d
commit 314cd92129
8 changed files with 148 additions and 0 deletions

View File

@ -4,6 +4,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
* Verilator 4.019 devel
*** Support $fseek, $ftell, $frewind, bug1496. [Howard Su]
**** Fix make test with no VERILATOR_ROOT, bug1494. [Ahmed El-Mahmoudy]

View File

@ -6,6 +6,7 @@ Please see the Verilator manual for additional contributors.
Alex Chadwick
Gianfranco Costamagna
Howard Su
Jeremy Bennett
John Coiner
Kanad Kanhere

View File

@ -2876,6 +2876,86 @@ public:
void countp(AstNode* nodep) { setNOp4p(nodep); }
};
class AstFRewind : public AstNodeMath {
// Parents: stmtlist
// Children: file which must be a varref
public:
AstFRewind(FileLine* fileline, AstNode* filep)
: AstNodeMath(fileline) {
setNOp2p(filep);
}
ASTNODE_NODE_FUNCS(FRewind)
virtual string verilogKwd() const { return "$frewind"; }
virtual string emitVerilog() { V3ERROR_NA; return ""; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual bool isGateOptimizable() const { return false; }
virtual bool isPredictOptimizable() const { return false; }
virtual bool isPure() const { return false; }
virtual bool isOutputter() const { return true; }
virtual bool isUnlikely() const { return true; }
virtual bool cleanOut() { return false; }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const { return true; }
AstNode* filep() const { return op2p(); }
void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); }
};
class AstFTell : public AstNodeMath {
// Parents: stmtlist
// Children: file which must be a varref
public:
AstFTell(FileLine* fileline, AstNode* filep)
: AstNodeMath(fileline) {
setNOp2p(filep);
}
ASTNODE_NODE_FUNCS(FTell)
virtual string verilogKwd() const { return "$ftell"; }
virtual string emitVerilog() { V3ERROR_NA; return ""; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual bool isGateOptimizable() const { return false; }
virtual bool isPredictOptimizable() const { return false; }
virtual bool isPure() const { return false; }
virtual bool isOutputter() const { return true; }
virtual bool isUnlikely() const { return true; }
virtual bool cleanOut() { return false; }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const { return true; }
AstNode* filep() const { return op2p(); }
void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); }
};
class AstFSeek : public AstNodeMath {
// Parents: expr
// Children: file which must be a varref
// Children: offset
// Children: operation
public:
AstFSeek(FileLine* fileline, AstNode* filep,
AstNode* offset, AstNode* operation)
: AstNodeMath(fileline) {
setOp2p(filep);
setNOp3p(offset);
setNOp4p(operation);
}
ASTNODE_NODE_FUNCS(FSeek)
virtual string verilogKwd() const { return "$fseek"; }
virtual string emitVerilog() { V3ERROR_NA; return ""; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual bool isGateOptimizable() const { return false; }
virtual bool isPredictOptimizable() const { return false; }
virtual bool isPure() const { return false; } // SPECIAL: has 'visual' ordering
virtual bool isOutputter() const { return true; } // SPECIAL: makes output
virtual bool cleanOut() { return false; }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(const AstNode* samep) const { return true; }
AstNode* filep() const { return op2p(); }
void filep(AstNode* nodep) { setOp2p(nodep); }
AstNode* offset() const { return op3p(); }
void offset(AstNode* nodep) { setNOp3p(nodep); }
AstNode* operation() const { return op4p(); }
void operation(AstNode* nodep) { setNOp4p(nodep); }
};
class AstFScanF : public AstNodeMath {
// Parents: expr
// Children: file which must be a varref

View File

@ -395,6 +395,25 @@ public:
puts(")); }\n");
}
}
virtual void visit(AstFSeek* nodep) {
puts("(fseek(VL_CVT_I_FP(");
iterateAndNextNull(nodep->filep());
puts("),");
iterateAndNextNull(nodep->offset());
puts(",");
iterateAndNextNull(nodep->operation());
puts(")==-1?-1:0)");
}
virtual void visit(AstFTell* nodep) {
puts("ftell(VL_CVT_I_FP(");
iterateAndNextNull(nodep->filep());
puts("))");
}
virtual void visit(AstFRewind* nodep) {
puts("(fseek(VL_CVT_I_FP(");
iterateAndNextNull(nodep->filep());
puts("), 0, 0)==-1?-1:0)");
}
virtual void visit(AstFRead* nodep) {
puts("VL_FREAD_I(");
puts(cvtToStr(nodep->memp()->widthMin())); // Need real storage width

View File

@ -2342,6 +2342,20 @@ private:
iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
}
}
virtual void visit(AstFRewind* nodep) {
iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
nodep->dtypeSetLogicUnsized(32, 1, AstNumeric::SIGNED); // Spec says integer return
}
virtual void visit(AstFTell* nodep) {
iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
nodep->dtypeSetLogicUnsized(32, 1, AstNumeric::SIGNED); // Spec says integer return
}
virtual void visit(AstFSeek* nodep) {
iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
iterateCheckSigned32(nodep, "$fseek offset", nodep->offset(), BOTH);
iterateCheckSigned32(nodep, "$fseek operation", nodep->operation(), BOTH);
nodep->dtypeSetLogicUnsized(32, 1, AstNumeric::SIGNED); // Spec says integer return
}
virtual void visit(AstFGetC* nodep) {
if (m_vup->prelim()) {
iterateCheckFileDesc(nodep, nodep->filep(), BOTH);

View File

@ -179,6 +179,9 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"$fopen" { FL; return yD_FOPEN; }
"$fread" { FL; return yD_FREAD; }
"$fscanf" { FL; return yD_FSCANF; }
"$fseek" { FL; return yD_FSEEK; }
"$ftell" { FL; return yD_FTELL; }
"$frewind" { FL; return yD_FREWIND; }
"$fullskew" { FL; return yaTIMINGSPEC; }
"$fwrite" { FL; return yD_FWRITE; }
"$hold" { FL; return yaTIMINGSPEC; }

View File

@ -517,7 +517,10 @@ class AstSenTree;
%token<fl> yD_FLOOR "$floor"
%token<fl> yD_FOPEN "$fopen"
%token<fl> yD_FREAD "$fread"
%token<fl> yD_FREWIND "$frewind"
%token<fl> yD_FSCANF "$fscanf"
%token<fl> yD_FSEEK "$fseek"
%token<fl> yD_FTELL "$ftell"
%token<fl> yD_FWRITE "$fwrite"
%token<fl> yD_HIGH "$high"
%token<fl> yD_HYPOT "$hypot"
@ -2907,8 +2910,11 @@ system_f_call_or_t<nodep>: // IEEE: part of system_tf_call (can be task or func)
| yD_FREAD '(' idClassSel ',' expr ')' { $$ = new AstFRead($1,$3,$5,NULL,NULL); }
| yD_FREAD '(' idClassSel ',' expr ',' expr ')' { $$ = new AstFRead($1,$3,$5,$7,NULL); }
| yD_FREAD '(' idClassSel ',' expr ',' expr ',' expr ')' { $$ = new AstFRead($1,$3,$5,$7,$9); }
| yD_FREWIND '(' idClassSel ')' { $$ = new AstFRewind($1, $3); }
| yD_FLOOR '(' expr ')' { $$ = new AstFloorD($1,$3); }
| yD_FSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstFScanF($1,*$5,$3,$6); }
| yD_FSEEK '(' idClassSel ',' expr ',' expr ')' { $$ = new AstFSeek($1,$3,$5,$7); }
| yD_FTELL '(' idClassSel ')' { $$ = new AstFTell($1, $3); }
| yD_HIGH '(' exprOrDataType ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_HIGH,$3,NULL); }
| yD_HIGH '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_HIGH,$3,$5); }
| yD_HYPOT '(' expr ',' expr ')' { $$ = new AstHypotD($1,$3,$5); }

View File

@ -24,6 +24,8 @@ module t;
reg [31:0] v_worda;
reg [31:0] v_wordb;
integer v_length, v_off;
`ifdef TEST_VERBOSE
`define verbose 1'b1
`else
@ -225,6 +227,27 @@ module t;
if ($fgetc(file) != "\n") $stop;
v_length = $ftell(file);
$frewind(file);
v_off = $ftell(file);
if (v_off != 0) $stop;
$fseek(file, 10, 0);
v_off = $ftell(file);
if (v_off != 10) $stop;
$fseek(file, 1, 1);
v_off = $ftell(file);
if (v_off != 11) $stop;
$fseek(file, -1, 1);
v_off = $ftell(file);
if (v_off != 10) $stop;
$fseek(file, v_length, 0);
v_off = $ftell(file);
if (v_off != v_length) $stop;
if ($fseek(file, 0, 2) != 0) $stop;
v_off = $ftell(file);
if (v_off < v_length) $stop;
$fclose(file);
end