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*
*** Support $feof, $fflush. [Holger Waechtler]
*** Support $feof, $fgetc, $fgets, $fflush. [Holger Waechtler]
*** Support $random.

View File

@ -117,6 +117,7 @@ DISTFILES_INC = $(INFOS) .gitignore COPYING *.in *.ac \
test_verilated/vgen*.pl \
test_regress/t/*.cpp \
test_regress/t/*.h \
test_regress/t/*.dat \
test_regress/t/*.mem \
test_regress/t/*.out \
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.
=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
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
}
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) {
IData fnw[2]; VL_SET_WQ(fnw, filename);
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
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_QI(QData ofilename, IData 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
#define VL_BYTESIZE 8 ///< Bits in a byte
#define VL_WORDSIZE 32 ///< Bits in a word
#define VL_QUADSIZE 64 ///< Bits in a quadword
#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)
#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(); }
};
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
@ -2729,6 +2744,22 @@ struct AstReplicate : public AstNodeBiop {
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
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

View File

@ -306,6 +306,13 @@ public:
nodep->filep()->iterateAndNext(*this);
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*) {
nodep->precondsp()->iterateAndNext(*this);
puts("while (");

View File

@ -116,6 +116,23 @@ private:
}
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*) {
bool last_setRefLvalue = m_setRefLvalue;
{

View File

@ -332,6 +332,14 @@ private:
nodep->iterateChildren(*this);
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*) {
nodep->iterateChildren(*this);
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(AstOneHot0* 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(AstReplicate* nodep, AstNUser*) { signed_Ou_Ix(nodep); }

View File

@ -576,12 +576,25 @@ private:
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p());
}
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);
}
virtual void visit(AstFFlush* nodep, AstNUser*) {
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*) {
nodep->filenamep()->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;}
"$feof" {yylval.fileline = CRELINE(); return yD_FEOF;}
"$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;}
"$fopen" {yylval.fileline = CRELINE(); return yD_FOPEN;}
"$fullskew" {yylval.fileline = CRELINE(); return yaTIMINGSPEC;}

View File

@ -228,6 +228,8 @@ class AstSenTree;
%token<fileline> yD_FDISPLAY "$fdisplay"
%token<fileline> yD_FEOF "$feof"
%token<fileline> yD_FFLUSH "$fflush"
%token<fileline> yD_FGETC "$fgetc"
%token<fileline> yD_FGETS "$fgets"
%token<fileline> yD_FINISH "$finish"
%token<fileline> yD_FOPEN "$fopen"
%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_COUNTONES '(' expr ')' { $$ = new AstCountOnes($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_ONEHOT '(' expr ')' { $$ = new AstOneHot($1,$3); }
| yD_ONEHOT0 '(' expr ')' { $$ = new AstOneHot0($1,$3); }

View File

@ -8,6 +8,11 @@
module t;
`verilator_file_descriptor file;
integer chars;
reg [1*8:1] letterl;
reg [8*8:1] letterq;
reg [16*8:1] letterw;
initial begin
// Display formatting
`ifdef verilator
@ -30,6 +35,7 @@ module t;
`endif
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
if (|file) $stop; // Should not exist, IE must return 0
end
@ -40,6 +46,37 @@ module t;
$fclose(file);
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");
$finish(0); // Test arguments to finish
end

View File

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