Support $fopen and I/O with integer instead of `verilator_file_descriptor.

This commit is contained in:
Wilson Snyder 2011-07-01 13:41:21 -04:00
parent 6e41d532fe
commit a901e171b2
11 changed files with 86 additions and 56 deletions

View File

@ -7,6 +7,8 @@ indicates the contributor was also the author of the fix; Thanks!
*** Support disable for loop escapes. *** Support disable for loop escapes.
*** Support $fopen and I/O with integer instead of `verilator_file_descriptor.
**** Use 'vluint64_t' for SystemC instead of (same sized) 'uint64' for MSVC++. **** Use 'vluint64_t' for SystemC instead of (same sized) 'uint64' for MSVC++.
* Verilator 3.813 2011/06/28 * Verilator 3.813 2011/06/28

View File

@ -2313,11 +2313,6 @@ The rarely used optional parameter to $finish and $stop is ignored.
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.
Verilator will convert the integer used to hold the file descriptor into a
internal FILE*. To prevent core dumps due to mis-use, and because integers
are 32 bits while FILE*s may be 64 bits, the descriptor must be stored in a
reg [63:0] rather than an integer. The define `verilator_file_descriptor in
verilated.v can be used to hide this difference.
=item $fscanf, $sscanf =item $fscanf, $sscanf

View File

@ -26,7 +26,6 @@
#define _VERILATED_CPP_ #define _VERILATED_CPP_
#include "verilated_imp.h" #include "verilated_imp.h"
#include <cctype> #include <cctype>
#include <vector>
#define VL_VALUE_STRING_MAX_WIDTH 1024 ///< Max static char array for VL_VALUE_STRING #define VL_VALUE_STRING_MAX_WIDTH 1024 ///< Max static char array for VL_VALUE_STRING
@ -628,6 +627,10 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
//=========================================================================== //===========================================================================
// File I/O // File I/O
FILE* VL_CVT_I_FP(IData lhs) {
return VerilatedImp::fdToFp(lhs);
}
void _VL_VINT_TO_STRING(int obits, char* destoutp, WDataInP sourcep) { void _VL_VINT_TO_STRING(int obits, char* destoutp, WDataInP sourcep) {
// See also VL_DATA_TO_STRING_NW // See also VL_DATA_TO_STRING_NW
int lsb=obits-1; int lsb=obits-1;
@ -655,8 +658,8 @@ void _VL_STRING_TO_VINT(int obits, void* destp, int srclen, const char* srcp) {
for (; i<bytes; i++) { *op++ = 0; } for (; i<bytes; i++) { *op++ = 0; }
} }
IData VL_FGETS_IXQ(int obits, void* destp, QData fpq) { IData VL_FGETS_IXI(int obits, void* destp, IData fpi) {
FILE* fp = VL_CVT_Q_FP(fpq); FILE* fp = VL_CVT_I_FP(fpi);
if (VL_UNLIKELY(!fp)) return 0; if (VL_UNLIKELY(!fp)) return 0;
// The string needs to be padded with 0's in unused spaces in front of // The string needs to be padded with 0's in unused spaces in front of
@ -692,7 +695,13 @@ QData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode) {
_VL_VINT_TO_STRING(fnwords*VL_WORDSIZE, filenamez, filenamep); _VL_VINT_TO_STRING(fnwords*VL_WORDSIZE, filenamez, filenamep);
char modez[5]; char modez[5];
_VL_VINT_TO_STRING(VL_WORDSIZE, modez, &mode); _VL_VINT_TO_STRING(VL_WORDSIZE, modez, &mode);
return VL_CVT_FP_Q(fopen(filenamez,modez)); return VerilatedImp::fdNew(fopen(filenamez,modez));
}
void VL_FCLOSE_I(IData fdi) {
FILE* fp = VL_CVT_I_FP(fdi);
if (VL_UNLIKELY(!fp)) return;
fclose(fp);
VerilatedImp::fdDelete(fdi);
} }
void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) { void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) {
@ -726,8 +735,8 @@ void VL_WRITEF(const char* formatp, ...) {
VL_PRINTF("%s", output.c_str()); VL_PRINTF("%s", output.c_str());
} }
void VL_FWRITEF(QData fpq, const char* formatp, ...) { void VL_FWRITEF(IData fpi, const char* formatp, ...) {
FILE* fp = VL_CVT_Q_FP(fpq); FILE* fp = VL_CVT_I_FP(fpi);
if (VL_UNLIKELY(!fp)) return; if (VL_UNLIKELY(!fp)) return;
va_list ap; va_list ap;
@ -739,8 +748,8 @@ void VL_FWRITEF(QData fpq, const char* formatp, ...) {
fputs(output.c_str(), fp); fputs(output.c_str(), fp);
} }
IData VL_FSCANF_IX(QData fpq, const char* formatp, ...) { IData VL_FSCANF_IX(IData fpi, const char* formatp, ...) {
FILE* fp = VL_CVT_Q_FP(fpq); FILE* fp = VL_CVT_I_FP(fpi);
if (VL_UNLIKELY(!fp)) return 0; if (VL_UNLIKELY(!fp)) return 0;
va_list ap; va_list ap;

View File

@ -364,13 +364,13 @@ extern const char* vl_mc_scan_plusargs(const char* prefixp); // PLIish
#define VL_SET_QW(lwp) ( ((QData)(lwp[0])) | ((QData)(lwp[1])<<((QData)(VL_WORDSIZE)) )) #define VL_SET_QW(lwp) ( ((QData)(lwp[0])) | ((QData)(lwp[1])<<((QData)(VL_WORDSIZE)) ))
#define _VL_SET_QII(ld,rd) ( ((QData)(ld)<<VL_ULL(32)) | (QData)(rd) ) #define _VL_SET_QII(ld,rd) ( ((QData)(ld)<<VL_ULL(32)) | (QData)(rd) )
/// Return FILE* from IData
FILE* VL_CVT_I_FP(IData lhs);
/// Return IData from FILE*
IData VL_CVT_FP_I(FILE* fp);
// Use a union to avoid cast-to-different-size warnings // Use a union to avoid cast-to-different-size warnings
/// Return FILE* from QData
static inline FILE* VL_CVT_Q_FP(QData lhs) { union { FILE* fp; QData q; } u; u.q=lhs; return u.fp; }
/// Return void* from QData /// Return void* from QData
static inline void* VL_CVT_Q_VP(QData lhs) { union { void* fp; QData q; } u; u.q=lhs; return u.fp; } static inline void* VL_CVT_Q_VP(QData lhs) { union { void* fp; QData q; } u; u.q=lhs; return u.fp; }
/// Return QData from FILE*
static inline QData VL_CVT_FP_Q(FILE* fp) { union { FILE* fp; QData q; } u; u.q=0; u.fp=fp; return u.q; }
/// Return QData from void* /// Return QData from void*
static inline QData VL_CVT_VP_Q(void* fp) { union { void* fp; QData q; } u; u.q=0; u.fp=fp; return u.q; } static inline QData VL_CVT_VP_Q(void* fp) { union { void* fp; QData q; } u; u.q=0; u.fp=fp; return u.q; }

View File

@ -27,11 +27,7 @@
`define coverage_block_off `define coverage_block_off
`endif `endif
// Hide file descriptor difference // Hide file descriptor difference - deprecated - for older versions
`ifdef verilator `define verilator_file_descriptor integer
`define verilator_file_descriptor reg [63:0]
`else
`define verilator_file_descriptor integer
`endif
`endif // guard `endif // guard

View File

@ -35,6 +35,7 @@
#include <map> #include <map>
#include <vector> #include <vector>
#include <deque>
#include <string> #include <string>
class VerilatedScope; class VerilatedScope;
@ -62,9 +63,18 @@ class VerilatedImp {
ExportNameMap m_exportMap; ///< Map of <export_func_proto, func number> ExportNameMap m_exportMap; ///< Map of <export_func_proto, func number>
int m_exportNext; ///< Next export funcnum int m_exportNext; ///< Next export funcnum
// File I/O
vector<FILE*> m_fdps; ///< File descriptors
deque<IData> m_fdFree; ///< List of free descriptors (SLOW - FOPEN/CLOSE only)
public: // But only for verilated*.cpp public: // But only for verilated*.cpp
// CONSTRUCTORS // CONSTRUCTORS
VerilatedImp() : m_argVecLoaded(false), m_exportNext(0) {} VerilatedImp() : m_argVecLoaded(false), m_exportNext(0) {
m_fdps.resize(3);
m_fdps[0] = stdin;
m_fdps[1] = stdout;
m_fdps[2] = stderr;
}
~VerilatedImp() {} ~VerilatedImp() {}
// METHODS - arguments // METHODS - arguments
@ -184,6 +194,34 @@ public: // But only for verilated*.cpp
} }
// We don't free up m_exportMap until the end, because we can't be sure // We don't free up m_exportMap until the end, because we can't be sure
// what other models are using the assigned funcnum's. // what other models are using the assigned funcnum's.
public: // But only for verilated*.cpp
// METHODS - file IO
static IData fdNew(FILE* fp) {
if (VL_UNLIKELY(!fp)) return 0;
// Bit 31 indicates it's a descriptor not a MCD
if (s_s.m_fdFree.empty()) {
// Need to create more space in m_fdps and m_fdFree
size_t start = s_s.m_fdps.size();
s_s.m_fdps.resize(start*2);
for (size_t i=start; i<start*2; i++) s_s.m_fdFree.push_back((IData)i);
}
IData idx = s_s.m_fdFree.back(); s_s.m_fdFree.pop_back();
s_s.m_fdps[idx] = fp;
return (idx | (1UL<<31)); // bit 31 indicates not MCD
}
static void fdDelete(IData fdi) {
IData idx = VL_MASK_I(31) & fdi;
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return;
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free
s_s.m_fdps[idx] = NULL;
s_s.m_fdFree.push_back(idx);
}
static inline FILE* fdToFp(IData fdi) {
IData idx = VL_MASK_I(31) & fdi;
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return NULL;
return s_s.m_fdps[idx];
}
}; };
#endif // Guard #endif // Guard

View File

@ -2697,7 +2697,7 @@ struct AstFEof : public AstNodeUniop {
ASTNODE_NODE_FUNCS(FEof, FEOF) ASTNODE_NODE_FUNCS(FEof, FEOF)
virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; } virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; }
virtual string emitVerilog() { return "%f$feof(%l)"; } virtual string emitVerilog() { return "%f$feof(%l)"; }
virtual string emitC() { return "(%li ? feof(VL_CVT_Q_FP(%li)) : true)"; } virtual string emitC() { return "(%li ? feof(VL_CVT_I_FP(%li)) : true)"; }
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;}
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersLhs() {return false;}
virtual int instrCount() const { return widthInstrs()*16; } virtual int instrCount() const { return widthInstrs()*16; }
@ -2710,7 +2710,7 @@ struct AstFGetC : public AstNodeUniop {
virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; } virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; }
virtual string emitVerilog() { return "%f$fgetc(%l)"; } virtual string emitVerilog() { return "%f$fgetc(%l)"; }
// Non-existent filehandle returns EOF // Non-existent filehandle returns EOF
virtual string emitC() { return "(%li ? fgetc(VL_CVT_Q_FP(%li)) : -1)"; } virtual string emitC() { return "(%li ? fgetc(VL_CVT_I_FP(%li)) : -1)"; }
virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;} virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;}
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersLhs() {return false;}
virtual int instrCount() const { return widthInstrs()*64; } virtual int instrCount() const { return widthInstrs()*64; }

View File

@ -344,13 +344,11 @@ public:
puts(");\n"); puts(");\n");
} }
virtual void visit(AstFClose* nodep, AstNUser*) { virtual void visit(AstFClose* nodep, AstNUser*) {
puts("if ("); puts("VL_FCLOSE_I(");
nodep->filep()->iterateAndNext(*this); nodep->filep()->iterateAndNext(*this);
puts(") { fclose (VL_CVT_Q_FP("); puts("); ");
nodep->filep()->iterateAndNext(*this);
puts(")); ");
nodep->filep()->iterateAndNext(*this); // For saftey, so user doesn't later WRITE with it. nodep->filep()->iterateAndNext(*this); // For saftey, so user doesn't later WRITE with it.
puts("=0; }\n"); puts("=0;\n");
} }
virtual void visit(AstFFlush* nodep, AstNUser*) { virtual void visit(AstFFlush* nodep, AstNUser*) {
if (!nodep->filep()) { if (!nodep->filep()) {
@ -358,7 +356,7 @@ public:
} else { } else {
puts("if ("); puts("if (");
nodep->filep()->iterateAndNext(*this); nodep->filep()->iterateAndNext(*this);
puts(") { fflush (VL_CVT_Q_FP("); puts(") { fflush (VL_CVT_I_FP(");
nodep->filep()->iterateAndNext(*this); nodep->filep()->iterateAndNext(*this);
puts(")); }\n"); puts(")); }\n");
} }

View File

@ -759,55 +759,55 @@ private:
} }
virtual void visit(AstDisplay* nodep, AstNUser*) { virtual void visit(AstDisplay* nodep, AstNUser*) {
if (nodep->filep()) { if (nodep->filep()) {
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p()); nodep->filep()->iterateAndNext(*this,WidthVP(32,32,BOTH).p());
widthCheck(nodep,"file_descriptor (see docs)",nodep->filep(),64,64); widthCheck(nodep,"file_descriptor",nodep->filep(),32,32);
} }
// Just let all arguments seek their natural sizes // Just let all arguments seek their natural sizes
nodep->iterateChildren(*this,WidthVP(ANYSIZE,0,BOTH).p()); nodep->iterateChildren(*this,WidthVP(ANYSIZE,0,BOTH).p());
} }
virtual void visit(AstFOpen* nodep, AstNUser*) { virtual void visit(AstFOpen* nodep, AstNUser*) {
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p()); nodep->filep()->iterateAndNext(*this,WidthVP(32,32,BOTH).p());
nodep->filenamep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); nodep->filenamep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->modep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); nodep->modep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
widthCheck(nodep,"file_descriptor (see docs)",nodep->filep(),64,64); widthCheck(nodep,"file_descriptor",nodep->filep(),32,32);
} }
virtual void visit(AstFClose* nodep, AstNUser*) { virtual void visit(AstFClose* nodep, AstNUser*) {
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p()); nodep->filep()->iterateAndNext(*this,WidthVP(32,32,BOTH).p());
widthCheck(nodep,"file_descriptor (see docs)",nodep->filep(),64,64); widthCheck(nodep,"file_descriptor",nodep->filep(),32,32);
} }
virtual void visit(AstFEof* nodep, AstNUser*) { virtual void visit(AstFEof* nodep, AstNUser*) {
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p()); nodep->filep()->iterateAndNext(*this,WidthVP(32,32,BOTH).p());
nodep->width(1,1); nodep->width(1,1);
widthCheck(nodep,"file_descriptor (see docs)",nodep->filep(),64,64); widthCheck(nodep,"file_descriptor",nodep->filep(),32,32);
} }
virtual void visit(AstFFlush* nodep, AstNUser*) { virtual void visit(AstFFlush* nodep, AstNUser*) {
if (nodep->filep()) { if (nodep->filep()) {
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p()); nodep->filep()->iterateAndNext(*this,WidthVP(32,32,BOTH).p());
widthCheck(nodep,"file_descriptor (see docs)",nodep->filep(),64,64); widthCheck(nodep,"file_descriptor",nodep->filep(),32,32);
} }
} }
virtual void visit(AstFGetC* nodep, AstNUser* vup) { virtual void visit(AstFGetC* nodep, AstNUser* vup) {
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p()); nodep->filep()->iterateAndNext(*this,WidthVP(32,32,BOTH).p());
if (vup->c()->prelim()) { if (vup->c()->prelim()) {
nodep->width(32,8); nodep->width(32,8);
} }
widthCheck(nodep,"file_descriptor (see docs)",nodep->filep(),64,64); widthCheck(nodep,"file_descriptor",nodep->filep(),32,32);
} }
virtual void visit(AstFGetS* nodep, AstNUser* vup) { virtual void visit(AstFGetS* nodep, AstNUser* vup) {
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p()); nodep->filep()->iterateAndNext(*this,WidthVP(32,32,BOTH).p());
nodep->strgp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); nodep->strgp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
if (vup->c()->prelim()) { if (vup->c()->prelim()) {
nodep->width(32,32); nodep->width(32,32);
} }
widthCheck(nodep,"file_descriptor (see docs)",nodep->filep(),64,64); widthCheck(nodep,"file_descriptor",nodep->filep(),32,32);
} }
virtual void visit(AstFScanF* nodep, AstNUser* vup) { virtual void visit(AstFScanF* nodep, AstNUser* vup) {
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p()); nodep->filep()->iterateAndNext(*this,WidthVP(32,32,BOTH).p());
nodep->exprsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); nodep->exprsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
if (vup->c()->prelim()) { if (vup->c()->prelim()) {
nodep->width(32,32); nodep->width(32,32);
} }
widthCheck(nodep,"file_descriptor (see docs)",nodep->filep(),64,64); widthCheck(nodep,"file_descriptor",nodep->filep(),32,32);
} }
virtual void visit(AstSScanF* nodep, AstNUser* vup) { virtual void visit(AstSScanF* nodep, AstNUser* vup) {
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());

View File

@ -2497,11 +2497,7 @@ module t_case_write1_tasks ();
endtask endtask
task big_case; task big_case;
`ifdef verilator
input [ 63:0] fd;
`else
input [ 31:0] fd; input [ 31:0] fd;
`endif
input [ 31:0] foo; input [ 31:0] foo;
reg [STRLEN*8: 1] foobar; reg [STRLEN*8: 1] foobar;
// verilator no_inline_task // verilator no_inline_task

View File

@ -10,11 +10,7 @@ module t_case_write2_tasks ();
// verilator lint_off WIDTH // verilator lint_off WIDTH
// verilator lint_off CASEINCOMPLETE // verilator lint_off CASEINCOMPLETE
`ifdef verilator
`define FD_BITS 63:0
`else
`define FD_BITS 31:0 `define FD_BITS 31:0
`endif
parameter STRLEN = 78; parameter STRLEN = 78;
task ozonerab; task ozonerab;