From 314cd921290b8fe1f9933caeef6062ab40bbea5e Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 3 Sep 2019 21:28:15 -0400 Subject: [PATCH] Support $fseek, $ftell, $frewind, bug1496. --- Changes | 2 + docs/CONTRIBUTORS | 1 + src/V3AstNodes.h | 80 +++++++++++++++++++++++++++++++ src/V3EmitC.cpp | 19 ++++++++ src/V3Width.cpp | 14 ++++++ src/verilog.l | 3 ++ src/verilog.y | 6 +++ test_regress/t/t_sys_file_basic.v | 23 +++++++++ 8 files changed, 148 insertions(+) diff --git a/Changes b/Changes index 713b033e3..7b447ec18 100644 --- a/Changes +++ b/Changes @@ -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] diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 9ebe614e1..38e17c2a0 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -6,6 +6,7 @@ Please see the Verilator manual for additional contributors. Alex Chadwick Gianfranco Costamagna +Howard Su Jeremy Bennett John Coiner Kanad Kanhere diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 234bfcf00..b96d2b167 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -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 diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index fcaef06e3..df57260eb 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -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 diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 9403ef13d..41ef4116a 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -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); diff --git a/src/verilog.l b/src/verilog.l index 2810fc2bb..3b9cb009e 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -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; } diff --git a/src/verilog.y b/src/verilog.y index 77b490d09..e2d38658e 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -517,7 +517,10 @@ class AstSenTree; %token yD_FLOOR "$floor" %token yD_FOPEN "$fopen" %token yD_FREAD "$fread" +%token yD_FREWIND "$frewind" %token yD_FSCANF "$fscanf" +%token yD_FSEEK "$fseek" +%token yD_FTELL "$ftell" %token yD_FWRITE "$fwrite" %token yD_HIGH "$high" %token yD_HYPOT "$hypot" @@ -2907,8 +2910,11 @@ system_f_call_or_t: // 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); } diff --git a/test_regress/t/t_sys_file_basic.v b/test_regress/t/t_sys_file_basic.v index c4fc6f097..e8fc7d014 100644 --- a/test_regress/t/t_sys_file_basic.v +++ b/test_regress/t/t_sys_file_basic.v @@ -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