Support , .

This commit is contained in:
Wilson Snyder 2008-06-27 20:04:20 -04:00
parent d962dfe48c
commit 0703843ac1
16 changed files with 176 additions and 3 deletions

View File

@ -5,7 +5,7 @@ indicates the contributor was also the author of the fix; Thanks!
* Verilator 3.66* * Verilator 3.66*
*** Support $feof, $fflush. [Holger Waechtler] *** Support $feof, $fgetc, $fgets, $fflush. [Holger Waechtler]
*** Support $random. *** Support $random.

View File

@ -117,6 +117,7 @@ DISTFILES_INC = $(INFOS) .gitignore COPYING *.in *.ac \
test_verilated/vgen*.pl \ test_verilated/vgen*.pl \
test_regress/t/*.cpp \ test_regress/t/*.cpp \
test_regress/t/*.h \ test_regress/t/*.h \
test_regress/t/*.dat \
test_regress/t/*.mem \ test_regress/t/*.mem \
test_regress/t/*.out \ test_regress/t/*.out \
test_regress/t/*.pl \ test_regress/t/*.pl \

View File

@ -1554,7 +1554,7 @@ them with a $write with the appropriate format specifier.
The rarely used optional parameter to $finish and $stop is ignored. The rarely used optional parameter to $finish and $stop is ignored.
=item $fopen, $fclose, $fdisplay, $feof, $fflush, $fwrite =item $fopen, $fclose, $fdisplay, $feof, $fflush, $fgetc, $fgets, $fwrite
File descriptors passed to the file PLI calls must be file descriptors, not File descriptors passed to the file PLI calls must be file descriptors, not
MCDs, which includes the mode parameter to $fopen being mandatory. MCDs, which includes the mode parameter to $fopen being mandatory.

View File

@ -248,6 +248,34 @@ void _VL_VINT_TO_STRING(int obits, char* destoutp, WDataInP sourcep) {
while (isspace(*(destp-1)) && destp>destoutp) *--destp = '\0'; // Drop trailing spaces while (isspace(*(destp-1)) && destp>destoutp) *--destp = '\0'; // Drop trailing spaces
} }
IData VL_FGETS_IXQ(int sbits, void* strgp, QData fpq) {
FILE* fp = VL_CVT_Q_FP(fpq);
if (!fp) return 0;
// The string needs to be padded with 0's in unused spaces in front of
// any read data. This means we can't know in what location the first
// character will finally live, so we need to copy. Yuk.
IData bytes = VL_BYTES_I(sbits);
char buffer[bytes];
// We don't use fgets, as we must read \0s.
IData got = 0;
char* cp = buffer;
while (got < bytes) {
int c = getc(fp);
if (c==EOF) break;
*cp++ = c; got++;
if (c=='\n') break;
}
// Convert to Verilog format
char* op = ((char*)(strgp));
IData i;
for (i=0; i<got; i++) { *op++ = buffer[got-1-i]; }
for (; i<bytes; i++) { *op++ = 0; }
return got;
}
QData VL_FOPEN_QI(QData filename, IData mode) { QData VL_FOPEN_QI(QData filename, IData mode) {
IData fnw[2]; VL_SET_WQ(fnw, filename); IData fnw[2]; VL_SET_WQ(fnw, filename);
return VL_FOPEN_WI(2, fnw, mode); return VL_FOPEN_WI(2, fnw, mode);

View File

@ -199,6 +199,23 @@ inline const char* VL_VALUE_FORMATTED_I(int obits, char fmt, bool drop0, IData l
} }
/// File I/O /// File I/O
extern IData VL_FGETS_IXQ(int sbits, void* strgp, QData fpq);
inline IData VL_FGETS_IIQ(int, int bits, int, CData& strg, QData fpq) {
return VL_FGETS_IXQ(bits, &strg, fpq);
}
inline IData VL_FGETS_IIQ(int, int bits, int, SData& strg, QData fpq) {
return VL_FGETS_IXQ(bits, &strg, fpq);
}
inline IData VL_FGETS_IIQ(int, int bits, int, IData& strg, QData fpq) {
return VL_FGETS_IXQ(bits, &strg, fpq);
}
inline IData VL_FGETS_IQQ(int, int bits, int, QData& strg, QData fpq) {
return VL_FGETS_IXQ(bits, &strg, fpq);
}
inline IData VL_FGETS_IWQ(int, int bits, int, WDataOutP strgp, QData fpq) {
return VL_FGETS_IXQ(bits, strgp, fpq);
}
extern QData VL_FOPEN_WI(int fnwords, WDataInP ofilename, IData mode); extern QData VL_FOPEN_WI(int fnwords, WDataInP ofilename, IData mode);
extern QData VL_FOPEN_QI(QData ofilename, IData mode); extern QData VL_FOPEN_QI(QData ofilename, IData mode);
inline QData VL_FOPEN_II(IData ofilename, IData mode) { return VL_FOPEN_QI(ofilename,mode); } inline QData VL_FOPEN_II(IData ofilename, IData mode) { return VL_FOPEN_QI(ofilename,mode); }

View File

@ -110,10 +110,13 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
//========================================================================= //=========================================================================
// Integer size macros // Integer size macros
#define VL_BYTESIZE 8 ///< Bits in a byte
#define VL_WORDSIZE 32 ///< Bits in a word #define VL_WORDSIZE 32 ///< Bits in a word
#define VL_QUADSIZE 64 ///< Bits in a quadword #define VL_QUADSIZE 64 ///< Bits in a quadword
#define VL_WORDSIZE_LOG2 5 ///< log2(VL_WORDSIZE) #define VL_WORDSIZE_LOG2 5 ///< log2(VL_WORDSIZE)
/// Bytes this number of bits needs (1 bit=1 byte)
#define VL_BYTES_I(nbits) (((nbits)+(VL_BYTESIZE-1))/VL_BYTESIZE)
/// Words this number of bits needs (1 bit=1 word) /// Words this number of bits needs (1 bit=1 word)
#define VL_WORDS_I(nbits) (((nbits)+(VL_WORDSIZE-1))/VL_WORDSIZE) #define VL_WORDS_I(nbits) (((nbits)+(VL_WORDSIZE-1))/VL_WORDSIZE)

View File

@ -2118,6 +2118,21 @@ struct AstFEof : public AstNodeUniop {
AstNode* filep() const { return lhsp(); } AstNode* filep() const { return lhsp(); }
}; };
struct AstFGetC : public AstNodeUniop {
AstFGetC(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {}
virtual ~AstFGetC() {}
virtual AstType type() const { return AstType::FEOF;}
virtual AstNode* clone() { return new AstFGetC(*this); }
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; }
virtual string emitVerilog() { return "%k$fgetc(%l)"; }
virtual string emitOperator() { return "VL_FGETC"; }
virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;}
virtual bool sizeMattersLhs() {return false;}
virtual int instrCount() const { return widthInstrs()*64; }
AstNode* filep() const { return lhsp(); }
};
//====================================================================== //======================================================================
// Binary ops // Binary ops
@ -2729,6 +2744,22 @@ struct AstReplicate : public AstNodeBiop {
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;} virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
virtual int instrCount() const { return widthInstrs()*2; } virtual int instrCount() const { return widthInstrs()*2; }
}; };
struct AstFGetS : public AstNodeBiop {
AstFGetS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {}
virtual ~AstFGetS() {}
virtual AstType type() const { return AstType::FEOF;}
virtual AstNode* clone() { return new AstFGetS(*this); }
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { V3ERROR_NA; }
virtual string emitVerilog() { return "%k$fgets(%l,%r)"; }
virtual string emitOperator() { return "VL_FGETS"; }
virtual bool cleanOut() {return false;}
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
virtual int instrCount() const { return widthInstrs()*64; }
AstNode* strgp() const { return lhsp(); }
AstNode* filep() const { return rhsp(); }
};
//====================================================================== //======================================================================
// SysVerilog assertions // SysVerilog assertions

View File

@ -306,6 +306,13 @@ public:
nodep->filep()->iterateAndNext(*this); nodep->filep()->iterateAndNext(*this);
puts(")); "); puts(")); ");
} }
virtual void visit(AstFGetC* nodep, AstNUser*) {
puts("(");
nodep->filep()->iterateAndNext(*this);
puts("? fgetc(VL_CVT_Q_FP(");
nodep->filep()->iterateAndNext(*this);
puts(")) : -1)"); // Non-existant filehandle should return EOF
}
virtual void visit(AstWhile* nodep, AstNUser*) { virtual void visit(AstWhile* nodep, AstNUser*) {
nodep->precondsp()->iterateAndNext(*this); nodep->precondsp()->iterateAndNext(*this);
puts("while ("); puts("while (");

View File

@ -116,6 +116,23 @@ private:
} }
m_setRefLvalue = last_setRefLvalue; m_setRefLvalue = last_setRefLvalue;
} }
virtual void visit(AstFGetC* nodep, AstNUser*) {
bool last_setRefLvalue = m_setRefLvalue;
{
m_setRefLvalue = true;
nodep->filep()->iterateAndNext(*this);
}
m_setRefLvalue = last_setRefLvalue;
}
virtual void visit(AstFGetS* nodep, AstNUser*) {
bool last_setRefLvalue = m_setRefLvalue;
{
m_setRefLvalue = true;
nodep->filep()->iterateAndNext(*this);
nodep->strgp()->iterateAndNext(*this);
}
m_setRefLvalue = last_setRefLvalue;
}
virtual void visit(AstReadMem* nodep, AstNUser*) { virtual void visit(AstReadMem* nodep, AstNUser*) {
bool last_setRefLvalue = m_setRefLvalue; bool last_setRefLvalue = m_setRefLvalue;
{ {

View File

@ -332,6 +332,14 @@ private:
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
expectDescriptor(nodep, nodep->filep()->castNodeVarRef()); expectDescriptor(nodep, nodep->filep()->castNodeVarRef());
} }
virtual void visit(AstFGetC* nodep, AstNUser*) {
nodep->iterateChildren(*this);
expectDescriptor(nodep, nodep->filep()->castNodeVarRef());
}
virtual void visit(AstFGetS* nodep, AstNUser*) {
nodep->iterateChildren(*this);
expectDescriptor(nodep, nodep->filep()->castNodeVarRef());
}
virtual void visit(AstDisplay* nodep, AstNUser*) { virtual void visit(AstDisplay* nodep, AstNUser*) {
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
if (nodep->filep()) expectDescriptor(nodep, nodep->filep()->castNodeVarRef()); if (nodep->filep()) expectDescriptor(nodep, nodep->filep()->castNodeVarRef());

View File

@ -81,6 +81,8 @@ private:
virtual void visit(AstOneHot* nodep,AstNUser*) { signed_Ou_Ix(nodep); } virtual void visit(AstOneHot* nodep,AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstOneHot0* nodep,AstNUser*) { signed_Ou_Ix(nodep); } virtual void visit(AstOneHot0* nodep,AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstFEof* nodep, AstNUser*) { signed_Ou_Ix(nodep); } virtual void visit(AstFEof* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstFGetC* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstFGetS* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
// //
virtual void visit(AstConcat* 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); } virtual void visit(AstReplicate* nodep, AstNUser*) { signed_Ou_Ix(nodep); }

View File

@ -576,12 +576,25 @@ private:
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p()); nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p());
} }
virtual void visit(AstFEof* nodep, AstNUser*) { virtual void visit(AstFEof* nodep, AstNUser*) {
nodep->lhsp()->iterateAndNext(*this,WidthVP(64,64,BOTH).p()); nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p());
nodep->width(1,1); nodep->width(1,1);
} }
virtual void visit(AstFFlush* nodep, AstNUser*) { virtual void visit(AstFFlush* nodep, AstNUser*) {
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p()); nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p());
} }
virtual void visit(AstFGetC* nodep, AstNUser* vup) {
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p());
if (vup->c()->prelim()) {
nodep->width(32,8);
}
}
virtual void visit(AstFGetS* nodep, AstNUser* vup) {
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p());
nodep->strgp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
if (vup->c()->prelim()) {
nodep->width(32,32);
}
}
virtual void visit(AstReadMem* nodep, AstNUser*) { virtual void visit(AstReadMem* nodep, AstNUser*) {
nodep->filenamep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); nodep->filenamep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->memp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); nodep->memp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());

View File

@ -134,6 +134,8 @@ escid \\[^ \t\f\r\n]+
"$fdisplay" {yylval.fileline = CRELINE(); return yD_FDISPLAY;} "$fdisplay" {yylval.fileline = CRELINE(); return yD_FDISPLAY;}
"$feof" {yylval.fileline = CRELINE(); return yD_FEOF;} "$feof" {yylval.fileline = CRELINE(); return yD_FEOF;}
"$fflush" {yylval.fileline = CRELINE(); return yD_FFLUSH;} "$fflush" {yylval.fileline = CRELINE(); return yD_FFLUSH;}
"$fgetc" {yylval.fileline = CRELINE(); return yD_FGETC;}
"$fgets" {yylval.fileline = CRELINE(); return yD_FGETS;}
"$finish" {yylval.fileline = CRELINE(); return yD_FINISH;} "$finish" {yylval.fileline = CRELINE(); return yD_FINISH;}
"$fopen" {yylval.fileline = CRELINE(); return yD_FOPEN;} "$fopen" {yylval.fileline = CRELINE(); return yD_FOPEN;}
"$fullskew" {yylval.fileline = CRELINE(); return yaTIMINGSPEC;} "$fullskew" {yylval.fileline = CRELINE(); return yaTIMINGSPEC;}

View File

@ -228,6 +228,8 @@ class AstSenTree;
%token<fileline> yD_FDISPLAY "$fdisplay" %token<fileline> yD_FDISPLAY "$fdisplay"
%token<fileline> yD_FEOF "$feof" %token<fileline> yD_FEOF "$feof"
%token<fileline> yD_FFLUSH "$fflush" %token<fileline> yD_FFLUSH "$fflush"
%token<fileline> yD_FGETC "$fgetc"
%token<fileline> yD_FGETS "$fgets"
%token<fileline> yD_FINISH "$finish" %token<fileline> yD_FINISH "$finish"
%token<fileline> yD_FOPEN "$fopen" %token<fileline> yD_FOPEN "$fopen"
%token<fileline> yD_FWRITE "$fwrite" %token<fileline> yD_FWRITE "$fwrite"
@ -1083,6 +1085,8 @@ exprNoStr: expr yP_OROR expr { $$ = new AstLogOr ($2,$1,$3); }
| yD_CLOG2 '(' expr ')' { $$ = new AstCLog2($1,$3); } | yD_CLOG2 '(' expr ')' { $$ = new AstCLog2($1,$3); }
| yD_COUNTONES '(' expr ')' { $$ = new AstCountOnes($1,$3); } | yD_COUNTONES '(' expr ')' { $$ = new AstCountOnes($1,$3); }
| yD_FEOF '(' expr ')' { $$ = new AstFEof($1,$3); } | yD_FEOF '(' expr ')' { $$ = new AstFEof($1,$3); }
| yD_FGETC '(' expr ')' { $$ = new AstFGetC($1,$3); }
| yD_FGETS '(' varRefDotBit ',' expr ')' { $$ = new AstFGetS($1,$3,$5); }
| yD_ISUNKNOWN '(' expr ')' { $$ = new AstIsUnknown($1,$3); } | yD_ISUNKNOWN '(' expr ')' { $$ = new AstIsUnknown($1,$3); }
| yD_ONEHOT '(' expr ')' { $$ = new AstOneHot($1,$3); } | yD_ONEHOT '(' expr ')' { $$ = new AstOneHot($1,$3); }
| yD_ONEHOT0 '(' expr ')' { $$ = new AstOneHot0($1,$3); } | yD_ONEHOT0 '(' expr ')' { $$ = new AstOneHot0($1,$3); }

View File

@ -8,6 +8,11 @@
module t; module t;
`verilator_file_descriptor file; `verilator_file_descriptor file;
integer chars;
reg [1*8:1] letterl;
reg [8*8:1] letterq;
reg [16*8:1] letterw;
initial begin initial begin
// Display formatting // Display formatting
`ifdef verilator `ifdef verilator
@ -30,6 +35,7 @@ module t;
`endif `endif
begin begin
// Check for opening errors
file = $fopen("obj_dir/DOES_NOT_EXIST","r"); // The "r" is required so we get a FD not a MFD file = $fopen("obj_dir/DOES_NOT_EXIST","r"); // The "r" is required so we get a FD not a MFD
if (|file) $stop; // Should not exist, IE must return 0 if (|file) $stop; // Should not exist, IE must return 0
end end
@ -40,6 +46,37 @@ module t;
$fclose(file); $fclose(file);
end end
begin
// Check read functions
file = $fopen("t/t_sys_file_input.dat","r");
if ($feof(file)) $stop;
// $fgetc
if ($fgetc(file) != "h") $stop;
if ($fgetc(file) != "i") $stop;
if ($fgetc(file) != "\n") $stop;
// $fgets
chars = $fgets(letterl, file);
$write("c=%0d l=%s\n", chars, letterl);
if (chars != 1) $stop;
if (letterl != "l") $stop;
chars = $fgets(letterq, file);
$write("c=%0d q=%x=%s", chars, letterq, letterq); // Output includes newline
if (chars != 5) $stop;
if (letterq != "\0\0\0quad\n") $stop;
letterw = "5432109876543210";
chars = $fgets(letterw, file);
$write("c=%0d w=%s", chars, letterw); // Output includes newline
if (chars != 10) $stop;
if (letterw != "\0\0\0\0\0\0widestuff\n") $stop;
$fclose(file);
end
$write("*-* All Finished *-*\n"); $write("*-* All Finished *-*\n");
$finish(0); // Test arguments to finish $finish(0); // Test arguments to finish
end end

View File

@ -0,0 +1,3 @@
hi
lquad
widestuff