Add support for , . Bug14.

This commit is contained in:
Wilson Snyder 2008-07-01 14:15:10 -04:00
parent 1a8c8bec0d
commit 701bd38d01
16 changed files with 656 additions and 87 deletions

View File

@ -5,9 +5,9 @@ indicates the contributor was also the author of the fix; Thanks!
* Verilator 3.66* * Verilator 3.66*
*** Support $feof, $fgetc, $fgets, $fflush. [Holger Waechtler] *** Add $feof, $fgetc, $fgets, $fflush, $fscanf, $sscanf. [Holger Waechtler]
*** Support $random. *** Add $random.
**** Internal changes to how $displays get compiled and executed. **** Internal changes to how $displays get compiled and executed.

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, $fgetc, $fgets, $fwrite =item $fopen, $fclose, $fdisplay, $feof, $fflush, $fgetc, $fgets, $fscanf, $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.
@ -1564,6 +1564,11 @@ 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 reg [63:0] rather than an integer. The define `verilator_file_descriptor in
verilated.v can be used to hide this difference. verilated.v can be used to hide this difference.
=item $fscanf, $sscanf
Only integer formats are supported; %e, %f, %m, %r, %v, and %z are not
supported.
=item $fullskew, $hold, $nochange, $period, $recovery, $recrem, $removal, =item $fullskew, $hold, $nochange, $period, $recovery, $recrem, $removal,
$setup, $setuphold, $skew, $timeskew, $width $setup, $setuphold, $skew, $timeskew, $width

View File

@ -145,8 +145,11 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
// Format a Verilog $write style format into the output list // Format a Verilog $write style format into the output list
// The format must be pre-processed (and lower cased) by Verilator // The format must be pre-processed (and lower cased) by Verilator
// Arguments are in "width, arg-value (or WDataIn* if wide)" form // Arguments are in "width, arg-value (or WDataIn* if wide)" form
//
// Note uses a single buffer internally; presumes only one usage per printf // Note uses a single buffer internally; presumes only one usage per printf
static VL_THREAD char str[VL_VALUE_STRING_MAX_WIDTH]; // Note also assumes variables < 64 are not wide, this assumption is
// sometimes not true in low-level routines written here in verilated.cpp
static VL_THREAD char tmp[VL_VALUE_STRING_MAX_WIDTH];
bool inPct = false; bool inPct = false;
bool widthSet = false; bool widthSet = false;
int width = 0; int width = 0;
@ -184,12 +187,12 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
} }
default: { default: {
// Deal with all read-and-print somethings // Deal with all read-and-print somethings
int bits = va_arg(ap, int); const int lbits = va_arg(ap, int);
QData ld = 0; QData ld = 0;
WDataInP lwp; WDataInP lwp;
if (bits <= VL_QUADSIZE) { if (lbits <= VL_QUADSIZE) {
WData qlwp[2]; WData qlwp[2];
ld = _VL_VA_ARG_Q(ap, bits); ld = _VL_VA_ARG_Q(ap, lbits);
VL_SET_WQ(qlwp,ld); VL_SET_WQ(qlwp,ld);
lwp = qlwp; lwp = qlwp;
} else { } else {
@ -197,38 +200,14 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
ld = lwp[0]; ld = lwp[0];
if (fmt == 'u' || fmt == 'd') fmt = 'x'; // Not supported, but show something if (fmt == 'u' || fmt == 'd') fmt = 'x'; // Not supported, but show something
} }
int lsb=bits-1; int lsb=lbits-1;
if (widthSet && width==0) while (lsb && !VL_BITISSET_W(lwp,lsb)) lsb--; if (widthSet && width==0) while (lsb && !VL_BITISSET_W(lwp,lsb)) lsb--;
switch (fmt) { switch (fmt) {
case 'b':
for (; lsb>=0; lsb--) {
output += ((lwp[VL_BITWORD_I(lsb)]>>VL_BITBIT_I(lsb)) & 1) + '0';
}
break;
case 'c': { case 'c': {
IData charval = ld & 0xff; IData charval = ld & 0xff;
output += charval; output += charval;
break; break;
} }
case 'd': { // Signed decimal
int digits=sprintf(str,"%lld",(vlsint64_t)(VL_EXTENDS_QQ(bits,bits,ld)));
int needmore = width-digits;
if (needmore>0) output.append(needmore,' '); // Pre-pad spaces
output += str;
break;
}
case 'o':
for (; lsb>=0; lsb--) {
lsb = (lsb / 3) * 3; // Next digit
// Octal numbers may span more than one wide word,
// so we need to grab each bit separately and check for overrun
// Octal is rare, so we'll do it a slow simple way
output += ('0'
+ ((VL_BITISSETLIMIT_W(lwp, bits, lsb+0)) ? 1 : 0)
+ ((VL_BITISSETLIMIT_W(lwp, bits, lsb+1)) ? 2 : 0)
+ ((VL_BITISSETLIMIT_W(lwp, bits, lsb+2)) ? 4 : 0));
}
break;
case 's': case 's':
for (; lsb>=0; lsb--) { for (; lsb>=0; lsb--) {
lsb = (lsb / 8) * 8; // Next digit lsb = (lsb / 8) * 8; // Next digit
@ -236,13 +215,37 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
output += (charval==0)?' ':charval; output += (charval==0)?' ':charval;
} }
break; break;
case 'u': { // Unsigned decimal case 'd': { // Signed decimal
int digits=sprintf(str,"%llu",ld); int digits=sprintf(tmp,"%lld",(vlsint64_t)(VL_EXTENDS_QQ(lbits,lbits,ld)));
int needmore = width-digits; int needmore = width-digits;
if (needmore>0) output.append(needmore,' '); // Pre-pad spaces if (needmore>0) output.append(needmore,' '); // Pre-pad spaces
output += str; output += tmp;
break; break;
} }
case 'u': { // Unsigned decimal
int digits=sprintf(tmp,"%llu",ld);
int needmore = width-digits;
if (needmore>0) output.append(needmore,' '); // Pre-pad spaces
output += tmp;
break;
}
case 'b':
for (; lsb>=0; lsb--) {
output += ((lwp[VL_BITWORD_I(lsb)]>>VL_BITBIT_I(lsb)) & 1) + '0';
}
break;
case 'o':
for (; lsb>=0; lsb--) {
lsb = (lsb / 3) * 3; // Next digit
// Octal numbers may span more than one wide word,
// so we need to grab each bit separately and check for overrun
// Octal is rare, so we'll do it a slow simple way
output += ('0'
+ ((VL_BITISSETLIMIT_W(lwp, lbits, lsb+0)) ? 1 : 0)
+ ((VL_BITISSETLIMIT_W(lwp, lbits, lsb+1)) ? 2 : 0)
+ ((VL_BITISSETLIMIT_W(lwp, lbits, lsb+2)) ? 4 : 0));
}
break;
case 'x': case 'x':
for (; lsb>=0; lsb--) { for (; lsb>=0; lsb--) {
lsb = (lsb / 4) * 4; // Next digit lsb = (lsb / 4) * 4; // Next digit
@ -261,6 +264,227 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
} }
} }
static inline bool _vl_vsss_eof(FILE* fp, int& floc) {
return fp ? feof(fp) : (floc<0);
}
static inline void _vl_vsss_advance(FILE* fp, int& floc) {
if (fp) fgetc(fp);
else floc -= 8;
}
static inline int _vl_vsss_peek(FILE* fp, int& floc, WDataInP fromp) {
// Get a character without advancing
if (fp) {
int data = fgetc(fp);
if (data == EOF) return EOF;
ungetc(data,fp);
return data;
} else {
if (floc < 0) return EOF;
floc = floc & ~7; // Align to closest character
int data = (fromp[VL_BITWORD_I(floc)] >> VL_BITBIT_I(floc)) & 0xff;
return data;
}
}
static inline void _vl_vsss_skipspace(FILE* fp, int& floc, WDataInP fromp) {
while (1) {
int c = _vl_vsss_peek(fp, floc, fromp);
if (c==EOF || !isspace(c)) return;
_vl_vsss_advance(fp, floc);
}
}
static inline void _vl_vsss_read(FILE* fp, int& floc, WDataInP fromp,
char* tmpp, const char* acceptp) {
// Read into tmp, consisting of characters from acceptp list
char* cp = tmpp;
while (1) {
int c = _vl_vsss_peek(fp, floc, fromp);
if (c==EOF || isspace(c)) break;
if (acceptp!=NULL // String - allow anything
&& NULL==strchr(acceptp, c)) break;
if (acceptp!=NULL) c = tolower(c); // Non-strings we'll simplify
*cp++ = c;
_vl_vsss_advance(fp, floc);
}
*cp++ = '\0';
//VL_PRINTF("\t_read got='%s'\n", tmpp);
}
static inline void _vl_vsss_setbit(WDataOutP owp, int obits, int lsb, int nbits, IData ld) {
for (; nbits && lsb<obits; nbits--, lsb++, ld>>=1) {
VL_ASSIGNBIT_WI(0, lsb, owp, ld & 1);
}
}
IData _vl_vsscanf(FILE* fp, // If a fscanf
int fbits, WDataInP fromp, // Else if a sscanf
const char* formatp, va_list ap) {
// Read a Verilog $sscanf/$fscanf style format into the output list
// The format must be pre-processed (and lower cased) by Verilator
// Arguments are in "width, arg-value (or WDataIn* if wide)" form
static VL_THREAD char tmp[VL_VALUE_STRING_MAX_WIDTH];
int floc = fbits - 1;
IData got = 0;
bool inPct = false;
const char* pos = formatp;
for (; *pos && !_vl_vsss_eof(fp,floc); ++pos) {
//VL_PRINTF("_vlscan fmt='%c' floc=%d file='%c'\n", pos[0], floc, _vl_vsss_peek(fp,floc,fromp));
if (!inPct && pos[0]=='%') {
inPct = true;
} else if (!inPct && isspace(pos[0])) { // Format spaces
while (isspace(pos[1])) pos++;
_vl_vsss_skipspace(fp,floc,fromp);
} else if (!inPct) { // Expected Format
_vl_vsss_skipspace(fp,floc,fromp);
int c = _vl_vsss_peek(fp,floc,fromp);
if (c != pos[0]) goto done;
else _vl_vsss_advance(fp,floc);
} else { // Format character
// Skip loading spaces
inPct = false;
char fmt = pos[0];
switch (fmt) {
case '%': {
int c = _vl_vsss_peek(fp,floc,fromp);
if (c != '%') goto done;
else _vl_vsss_advance(fp,floc);
break;
}
default: {
// Deal with all read-and-scan somethings
// Note LSBs are preserved if there's an overflow
const int obits = va_arg(ap, int);
int lsb = 0;
WData qowp[2];
WDataOutP owp = qowp;
if (obits > VL_QUADSIZE) {
owp = va_arg(ap,WDataOutP);
}
for (int i=0; i<VL_WORDS_I(obits); i++) owp[i] = 0;
switch (fmt) {
case 'c': {
int c = _vl_vsss_peek(fp,floc,fromp);
if (c==EOF) goto done;
else _vl_vsss_advance(fp,floc);
owp[0] = c;
break;
}
case 's': {
_vl_vsss_skipspace(fp,floc,fromp);
_vl_vsss_read(fp,floc,fromp, tmp, NULL);
if (!tmp[0]) goto done;
int pos = strlen(tmp)-1;
for (int i=0; i<obits && pos>=0; pos--) {
_vl_vsss_setbit(owp,obits,lsb, 8, tmp[pos]); lsb+=8;
}
break;
}
case 'd': { // Signed decimal
_vl_vsss_skipspace(fp,floc,fromp);
_vl_vsss_read(fp,floc,fromp, tmp, "0123456789+-xz?_");
if (!tmp[0]) goto done;
vlsint64_t ld;
sscanf(tmp,"%lld",&ld);
VL_SET_WQ(owp,ld);
break;
}
case 'u': { // Unsigned decimal
_vl_vsss_skipspace(fp,floc,fromp);
_vl_vsss_read(fp,floc,fromp, tmp, "0123456789+-xz?_");
if (!tmp[0]) goto done;
QData ld;
sscanf(tmp,"%llu",&ld);
VL_SET_WQ(owp,ld);
break;
}
case 'b': {
_vl_vsss_skipspace(fp,floc,fromp);
_vl_vsss_read(fp,floc,fromp, tmp, "01xz?_");
if (!tmp[0]) goto done;
int pos = strlen(tmp)-1;
for (int i=0; i<obits && pos>=0; pos--) {
switch(tmp[pos]) {
case 'x': case 'z': case '?': //FALLTHRU
case '0': lsb++; break;
case '1': _vl_vsss_setbit(owp,obits,lsb, 1, 1); lsb++; break;
case '_': break;
}
}
break;
}
case 'o': {
_vl_vsss_skipspace(fp,floc,fromp);
_vl_vsss_read(fp,floc,fromp, tmp, "01234567xz?_");
if (!tmp[0]) goto done;
int pos = strlen(tmp)-1;
for (int i=0; i<obits && pos>=0; pos--) {
switch(tmp[pos]) {
case 'x': case 'z': case '?': //FALLTHRU
case '0': lsb+=3; break;
case '1': _vl_vsss_setbit(owp,obits,lsb, 3, 1); lsb+=3; break;
case '2': _vl_vsss_setbit(owp,obits,lsb, 3, 2); lsb+=3; break;
case '3': _vl_vsss_setbit(owp,obits,lsb, 3, 3); lsb+=3; break;
case '4': _vl_vsss_setbit(owp,obits,lsb, 3, 4); lsb+=3; break;
case '5': _vl_vsss_setbit(owp,obits,lsb, 3, 5); lsb+=3; break;
case '6': _vl_vsss_setbit(owp,obits,lsb, 3, 6); lsb+=3; break;
case '7': _vl_vsss_setbit(owp,obits,lsb, 3, 7); lsb+=3; break;
case '_': break;
}
}
break;
}
case 'x': {
_vl_vsss_skipspace(fp,floc,fromp);
_vl_vsss_read(fp,floc,fromp, tmp, "0123456789abcdefxz?_");
if (!tmp[0]) goto done;
int pos = strlen(tmp)-1;
for (int i=0; i<obits && pos>=0; pos--) {
switch(tmp[pos]) {
case 'x': case 'z': case '?': //FALLTHRU
case '0': lsb+=4; break;
case '1': _vl_vsss_setbit(owp,obits,lsb, 4, 1); lsb+=4; break;
case '2': _vl_vsss_setbit(owp,obits,lsb, 4, 2); lsb+=4; break;
case '3': _vl_vsss_setbit(owp,obits,lsb, 4, 3); lsb+=4; break;
case '4': _vl_vsss_setbit(owp,obits,lsb, 4, 4); lsb+=4; break;
case '5': _vl_vsss_setbit(owp,obits,lsb, 4, 5); lsb+=4; break;
case '6': _vl_vsss_setbit(owp,obits,lsb, 4, 6); lsb+=4; break;
case '7': _vl_vsss_setbit(owp,obits,lsb, 4, 7); lsb+=4; break;
case '8': _vl_vsss_setbit(owp,obits,lsb, 4, 8); lsb+=4; break;
case '9': _vl_vsss_setbit(owp,obits,lsb, 4, 9); lsb+=4; break;
case 'a': _vl_vsss_setbit(owp,obits,lsb, 4, 10); lsb+=4; break;
case 'b': _vl_vsss_setbit(owp,obits,lsb, 4, 11); lsb+=4; break;
case 'c': _vl_vsss_setbit(owp,obits,lsb, 4, 12); lsb+=4; break;
case 'd': _vl_vsss_setbit(owp,obits,lsb, 4, 13); lsb+=4; break;
case 'e': _vl_vsss_setbit(owp,obits,lsb, 4, 14); lsb+=4; break;
case 'f': _vl_vsss_setbit(owp,obits,lsb, 4, 15); lsb+=4; break;
case '_': break;
}
}
break;
}
default:
string msg = string("%%Error: Unknown _vl_vsscanf code: ")+pos[0]+"\n";
vl_fatal(__FILE__,__LINE__,"",msg.c_str());
break;
} // switch
got++;
// Reload data if non-wide (if wide, we put it in the right place directly)
if (obits <= VL_BYTESIZE) {
CData* p = va_arg(ap,CData*); *p = owp[0];
} else if (obits <= VL_SHORTSIZE) {
SData* p = va_arg(ap,SData*); *p = owp[0];
} else if (obits <= VL_WORDSIZE) {
IData* p = va_arg(ap,IData*); *p = owp[0];
} else if (obits <= VL_QUADSIZE) {
QData* p = va_arg(ap,QData*); *p = VL_SET_QW(owp);
}
}
} // switch
}
}
done:
return got;
}
//=========================================================================== //===========================================================================
// File I/O // File I/O
@ -327,7 +551,6 @@ QData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode) {
} }
void VL_WRITEF(const char* formatp, ...) { void VL_WRITEF(const char* formatp, ...) {
va_list ap; va_list ap;
va_start(ap,formatp); va_start(ap,formatp);
string output; string output;
@ -351,6 +574,43 @@ 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, ...) {
FILE* fp = VL_CVT_Q_FP(fpq);
if (VL_UNLIKELY(!fp)) return 0;
va_list ap;
va_start(ap,formatp);
IData got = _vl_vsscanf(fp, 0, NULL, formatp, ap);
va_end(ap);
return got;
}
IData VL_SSCANF_IIX(int lbits, IData ld, const char* formatp, ...) {
IData fnw[2]; VL_SET_WI(fnw, ld);
va_list ap;
va_start(ap,formatp);
IData got = _vl_vsscanf(NULL, lbits, fnw, formatp, ap);
va_end(ap);
return got;
}
IData VL_SSCANF_IQX(int lbits, QData ld, const char* formatp, ...) {
IData fnw[2]; VL_SET_WQ(fnw, ld);
va_list ap;
va_start(ap,formatp);
IData got = _vl_vsscanf(NULL, lbits, fnw, formatp, ap);
va_end(ap);
return got;
}
IData VL_SSCANF_IWX(int lbits, WDataInP lwp, const char* formatp, ...) {
va_list ap;
va_start(ap,formatp);
IData got = _vl_vsscanf(NULL, lbits, lwp, formatp, ap);
va_end(ap);
return got;
}
void VL_READMEM_Q(bool hex, int width, int depth, int array_lsb, int, void VL_READMEM_Q(bool hex, int width, int depth, int array_lsb, int,
QData ofilename, void* memp, IData start, IData end) { QData ofilename, void* memp, IData start, IData end) {
IData fnw[2]; VL_SET_WQ(fnw, ofilename); IData fnw[2]; VL_SET_WQ(fnw, ofilename);

View File

@ -209,6 +209,11 @@ inline void VL_READMEM_I(bool hex, int width, int depth, int array_lsb, int fnwo
extern void VL_WRITEF(const char* formatp, ...); extern void VL_WRITEF(const char* formatp, ...);
extern void VL_FWRITEF(QData fpq, const char* formatp, ...); extern void VL_FWRITEF(QData fpq, const char* formatp, ...);
extern IData VL_FSCANF_IX(QData fpq, const char* formatp, ...);
extern IData VL_SSCANF_IIX(int lbits, IData ld, const char* formatp, ...);
extern IData VL_SSCANF_IQX(int lbits, QData ld, const char* formatp, ...);
extern IData VL_SSCANF_IWX(int lbits, WDataInP lwp, const char* formatp, ...);
//========================================================================= //=========================================================================
// Base macros // Base macros
@ -219,7 +224,9 @@ extern void VL_FWRITEF(QData fpq, const char* formatp, ...);
#define VL_BITISSETLIMIT_W(data,width,bit) (((bit)<(width)) && data[VL_BITWORD_I(bit)] & (VL_UL(1)<<VL_BITBIT_I(bit))) #define VL_BITISSETLIMIT_W(data,width,bit) (((bit)<(width)) && data[VL_BITWORD_I(bit)] & (VL_UL(1)<<VL_BITBIT_I(bit)))
/// Create two 32-bit words from quadword /// Create two 32-bit words from quadword
#define VL_SET_WQ(decl,data) { decl[0]=(data); decl[1]=((data)>>VL_WORDSIZE); } #define VL_SET_WQ(owp,data) { owp[0]=(data); owp[1]=((data)>>VL_WORDSIZE); }
#define VL_SET_WI(owp,data) { owp[0]=(data); owp[1]=0; }
#define VL_SET_QW(lwp) ( ((QData)(lwp[0])) | ((QData)(lwp[1])<<((QData)(VL_WORDSIZE)) ))
// Use a union to avoid cast-to-different-size warnings // Use a union to avoid cast-to-different-size warnings
/// Return FILE* from QData /// Return FILE* from QData

View File

@ -111,6 +111,7 @@ 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_BYTESIZE 8 ///< Bits in a byte
#define VL_SHORTSIZE 16 ///< Bits in a short
#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)

View File

@ -1349,6 +1349,78 @@ struct AstFFlush : public AstNodeStmt {
void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); }
}; };
struct AstFScanF : public AstNodeMath {
// Parents: expr
// Children: file which must be a varref
// Children: varrefs to load
private:
string m_text;
public:
AstFScanF(FileLine* fileline, const string& text, AstNode* filep, AstNode* exprsp)
: AstNodeMath (fileline), m_text(text) {
addNOp1p(exprsp);
setNOp2p(filep);
}
virtual ~AstFScanF() {}
virtual AstType type() const { return AstType::FSCANF;}
virtual AstNode* clone() { return new AstFScanF(*this); }
virtual string name() const { return m_text; }
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
virtual string verilogKwd() const { return "$fscanf"; }
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 isSplittable() 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(text()); }
virtual bool same(AstNode* samep) const {
return text()==samep->castFScanF()->text(); }
AstNode* exprsp() const { return op1p()->castNode(); } // op1 = Expressions to output
void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output
string text() const { return m_text; } // * = Text to display
void text(const string& text) { m_text=text; }
AstNode* filep() const { return op2p(); }
void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); }
};
struct AstSScanF : public AstNodeMath {
// Parents: expr
// Children: file which must be a varref
// Children: varrefs to load
private:
string m_text;
public:
AstSScanF(FileLine* fileline, const string& text, AstNode* fromp, AstNode* exprsp)
: AstNodeMath (fileline), m_text(text) {
addNOp1p(exprsp);
setOp2p(fromp);
}
virtual ~AstSScanF() {}
virtual AstType type() const { return AstType::SSCANF;}
virtual AstNode* clone() { return new AstSScanF(*this); }
virtual string name() const { return m_text; }
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
virtual string verilogKwd() const { return "$sscanf"; }
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 isSplittable() 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(text()); }
virtual bool same(AstNode* samep) const {
return text()==samep->castSScanF()->text(); }
AstNode* exprsp() const { return op1p()->castNode(); } // op1 = Expressions to output
void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output
string text() const { return m_text; } // * = Text to display
void text(const string& text) { m_text=text; }
AstNode* fromp() const { return op2p(); }
void fromp(AstNode* nodep) { setOp2p(nodep); }
};
struct AstReadMem : public AstNodeStmt { struct AstReadMem : public AstNodeStmt {
private: private:
bool m_isHex; // readmemh, not readmemb bool m_isHex; // readmemh, not readmemb

View File

@ -78,8 +78,10 @@ public:
//int debug() { return 9; } //int debug() { return 9; }
// METHODS // METHODS
void displayEmit(AstDisplay* nodep); void displayNode(AstNode* nodep, const string& vformat, AstNode* exprsp, bool isScan);
void displayArg(AstDisplay* dispp, AstNode** elistp, string vfmt, char fmtLetter); void displayEmit(AstNode* nodep, bool isScan);
void displayArg(AstNode* dispp, AstNode** elistp, bool isScan,
string vfmt, char fmtLetter);
void emitVarDecl(AstVar* nodep, const string& prefixIfImp); void emitVarDecl(AstVar* nodep, const string& prefixIfImp);
typedef enum {EVL_IO, EVL_SIG, EVL_TEMP, EVL_STATIC, EVL_ALL} EisWhich; typedef enum {EVL_IO, EVL_SIG, EVL_TEMP, EVL_STATIC, EVL_ALL} EisWhich;
@ -229,7 +231,23 @@ public:
nodep->lhsp()->iterateAndNext(*this); nodep->lhsp()->iterateAndNext(*this);
puts(");\n"); puts(");\n");
} }
virtual void visit(AstDisplay* nodep, AstNUser*); // BELOW virtual void visit(AstDisplay* nodep, AstNUser*) {
string text = nodep->text();
if (nodep->addNewline()) text += "\\n";
displayNode(nodep, text, nodep->exprsp(), false);
}
virtual void visit(AstFScanF* nodep, AstNUser*) {
displayNode(nodep, nodep->text(), nodep->exprsp(), true);
}
virtual void visit(AstSScanF* nodep, AstNUser*) {
displayNode(nodep, nodep->text(), nodep->exprsp(), true);
}
void checkMaxWords(AstNode* nodep) {
if (nodep->widthWords() > VL_TO_STRING_MAX_WORDS) {
nodep->v3error("String of "<<nodep->width()<<" bits exceeds hardcoded limit VL_TO_STRING_MAX_WORDS in verilatedos.h\n");
}
}
virtual void visit(AstFOpen* nodep, AstNUser*) { virtual void visit(AstFOpen* nodep, AstNUser*) {
nodep->filep()->iterateAndNext(*this); nodep->filep()->iterateAndNext(*this);
puts(" = VL_FOPEN_"); puts(" = VL_FOPEN_");
@ -241,9 +259,7 @@ public:
puts(cvtToStr(nodep->filenamep()->widthWords())); puts(cvtToStr(nodep->filenamep()->widthWords()));
putbs(", "); putbs(", ");
} }
if (nodep->filenamep()->widthWords() > VL_TO_STRING_MAX_WORDS) { checkMaxWords(nodep->filenamep());
nodep->v3error("String of "<<nodep->filenamep()->width()<<" bits exceeds hardcoded limit VL_TO_STRING_MAX_WORDS in verilatedos.h\n");
}
nodep->filenamep()->iterateAndNext(*this); nodep->filenamep()->iterateAndNext(*this);
putbs(", "); putbs(", ");
nodep->modep()->iterateAndNext(*this); nodep->modep()->iterateAndNext(*this);
@ -270,9 +286,7 @@ public:
puts(cvtToStr(array_lsb)); puts(cvtToStr(array_lsb));
putbs(","); putbs(",");
puts(cvtToStr(nodep->filenamep()->widthWords())); puts(cvtToStr(nodep->filenamep()->widthWords()));
if (nodep->filenamep()->widthWords() > VL_TO_STRING_MAX_WORDS) { checkMaxWords(nodep->filenamep());
nodep->v3error("String of "<<nodep->filenamep()->width()<<" bits exceeds hardcoded limit VL_TO_STRING_MAX_WORDS in verilatedos.h\n");
}
putbs(", "); putbs(", ");
nodep->filenamep()->iterateAndNext(*this); nodep->filenamep()->iterateAndNext(*this);
putbs(", "); putbs(", ");
@ -950,16 +964,40 @@ struct EmitDispState {
} }
} emitDispState; } emitDispState;
void EmitCStmts::displayEmit(AstDisplay* nodep) { void EmitCStmts::displayEmit(AstNode* nodep, bool isScan) {
if (emitDispState.m_format != "") { if (emitDispState.m_format == ""
&& nodep->castDisplay()) { // not fscanf etc, as they need to return value
// NOP
} else {
// Format // Format
if (nodep->filep()) { bool isStmt;
puts("VL_FWRITEF("); if (AstFScanF* dispp = nodep->castFScanF()) {
nodep->filep()->iterate(*this); isStmt = false;
puts(",\""); puts("VL_FSCANF_IX(");
dispp->filep()->iterate(*this);
puts(",");
} else if (AstSScanF* dispp = nodep->castSScanF()) {
isStmt = false;
checkMaxWords(dispp->fromp());
puts("VL_SSCANF_I"); emitIQW(dispp->fromp()); puts("X(");
puts(cvtToStr(dispp->fromp()->widthMin()));
puts(",");
dispp->fromp()->iterate(*this);
puts(",");
} else if (AstDisplay* dispp = nodep->castDisplay()) {
isStmt = true;
if (dispp->filep()) {
puts("VL_FWRITEF(");
dispp->filep()->iterate(*this);
puts(",");
} else {
puts("VL_WRITEF(");
}
} else { } else {
puts("VL_WRITEF(\""); isStmt = true;
nodep->v3fatalSrc("Unknown displayEmit node type");
} }
puts("\"");
ofp()->putsNoTracking(emitDispState.m_format); ofp()->putsNoTracking(emitDispState.m_format);
puts("\""); puts("\"");
// Arguments // Arguments
@ -970,17 +1008,24 @@ void EmitCStmts::displayEmit(AstDisplay* nodep) {
ofp()->indentInc(); ofp()->indentInc();
ofp()->putbs(""); ofp()->putbs("");
if (func!="") puts(func); if (func!="") puts(func);
if (argp) argp->iterate(*this); if (argp) {
if (isScan) puts("&(");
argp->iterate(*this);
if (isScan) puts(")");
}
ofp()->indentDec(); ofp()->indentDec();
} }
// End // End
puts(");\n"); puts(")");
if (isStmt) puts(";\n");
else puts(" ");
// Prep for next // Prep for next
emitDispState.clear(); emitDispState.clear();
} }
} }
void EmitCStmts::displayArg(AstDisplay* dispp, AstNode** elistp, string vfmt, char fmtLetter) { void EmitCStmts::displayArg(AstNode* dispp, AstNode** elistp, bool isScan,
string vfmt, char fmtLetter) {
// Print display argument, edits elistp // Print display argument, edits elistp
AstNode* argp = *elistp; AstNode* argp = *elistp;
if (!argp) { if (!argp) {
@ -993,16 +1038,17 @@ void EmitCStmts::displayArg(AstDisplay* dispp, AstNode** elistp, string vfmt, ch
} }
if (argp && argp->isWide() if (argp && argp->isWide()
&& (fmtLetter=='d'||fmtLetter=='u')) { && (fmtLetter=='d'||fmtLetter=='u')) {
argp->v3error("Unsupported: $display of dec format of > 64 bit results (use hex format instead)"); argp->v3error("Unsupported: "<<dispp->verilogKwd()<<" of dec format of > 64 bit results (use hex format instead)");
} }
if (argp && argp->widthMin()>8 && fmtLetter=='c') { if (argp && argp->widthMin()>8 && fmtLetter=='c') {
// Technically legal, but surely not what the user intended. // Technically legal, but surely not what the user intended.
argp->v3error("$display of char format of > 8 bit result"); argp->v3error(dispp->verilogKwd()<<" of char format of > 8 bit result");
} }
//string pfmt = "%"+displayFormat(argp, vfmt, fmtLetter)+fmtLetter; //string pfmt = "%"+displayFormat(argp, vfmt, fmtLetter)+fmtLetter;
string pfmt; string pfmt;
if ((fmtLetter=='u' || fmtLetter=='d') if ((fmtLetter=='u' || fmtLetter=='d')
&& !isScan
&& vfmt == "") { // Size decimal output. Spec says leading spaces, not zeros && vfmt == "") { // Size decimal output. Spec says leading spaces, not zeros
double mantissabits = argp->widthMin() - ((fmtLetter=='d')?1:0); double mantissabits = argp->widthMin() - ((fmtLetter=='d')?1:0);
double maxval = pow(2.0, mantissabits); double maxval = pow(2.0, mantissabits);
@ -1021,15 +1067,15 @@ void EmitCStmts::displayArg(AstDisplay* dispp, AstNode** elistp, string vfmt, ch
*elistp = (*elistp)->nextp(); *elistp = (*elistp)->nextp();
} }
void EmitCStmts::visit(AstDisplay* nodep, AstNUser*) { void EmitCStmts::displayNode(AstNode* nodep, const string& vformat, AstNode* exprsp,
string vformat = nodep->text(); bool isScan) {
AstNode* elistp = nodep->exprsp(); AstNode* elistp = exprsp;
// Convert Verilog display to C printf formats // Convert Verilog display to C printf formats
// "%0t" becomes "%d" // "%0t" becomes "%d"
emitDispState.clear(); emitDispState.clear();
string vfmt = ""; string vfmt = "";
string::iterator pos = vformat.begin(); string::const_iterator pos = vformat.begin();
bool inPct = false; bool inPct = false;
for (; pos != vformat.end(); ++pos) { for (; pos != vformat.end(); ++pos) {
//UINFO(1,"Parse '"<<*pos<<"' IP"<<inPct<<" List "<<(void*)(elistp)<<endl); //UINFO(1,"Parse '"<<*pos<<"' IP"<<inPct<<" List "<<(void*)(elistp)<<endl);
@ -1051,21 +1097,23 @@ void EmitCStmts::visit(AstDisplay* nodep, AstNUser*) {
emitDispState.pushFormat("%%"); // We're printf'ing it, so need to quote the % emitDispState.pushFormat("%%"); // We're printf'ing it, so need to quote the %
break; break;
// Special codes // Special codes
case '~': displayArg(nodep,&elistp,vfmt,'d'); break; // Signed decimal case '~': displayArg(nodep,&elistp,isScan, vfmt,'d'); break; // Signed decimal
// Spec: h d o b c l // Spec: h d o b c l
case 'b': displayArg(nodep,&elistp,vfmt,'b'); break; case 'b': displayArg(nodep,&elistp,isScan, vfmt,'b'); break;
case 'c': displayArg(nodep,&elistp,vfmt,'c'); break; case 'c': displayArg(nodep,&elistp,isScan, vfmt,'c'); break;
case 't': case 't':
case 'd': displayArg(nodep,&elistp,vfmt,'u'); break; // Unsigned decimal case 'd': displayArg(nodep,&elistp,isScan, vfmt,'u'); break; // Unsigned decimal
case 'o': displayArg(nodep,&elistp,vfmt,'o'); break; case 'o': displayArg(nodep,&elistp,isScan, vfmt,'o'); break;
case 'h': case 'h':
case 'x': displayArg(nodep,&elistp,vfmt,'x'); break; case 'x': displayArg(nodep,&elistp,isScan, vfmt,'x'); break;
case 's': displayArg(nodep,&elistp,vfmt,'s'); break; case 's': displayArg(nodep,&elistp,isScan, vfmt,'s'); break;
case 'm': { case 'm': {
emitDispState.pushFormat("%S"); emitDispState.pushFormat("%S");
emitDispState.pushArg(NULL, "vlSymsp->name()"); emitDispState.pushArg(NULL, "vlSymsp->name()");
if (!nodep->scopeNamep()) nodep->v3fatalSrc("Display with %m but no AstScopeName"); if (!nodep->castDisplay()) nodep->v3fatalSrc("Non-Display with %m");
for (AstText* textp=nodep->scopeNamep()->scopeAttrp(); textp; textp=textp->nextp()->castText()) { AstScopeName* scopenamep = nodep->castDisplay()->scopeNamep();
if (!scopenamep) nodep->v3fatalSrc("Display with %m but no AstScopeName");
for (AstText* textp=scopenamep->scopeAttrp(); textp; textp=textp->nextp()->castText()) {
emitDispState.pushFormat(textp->text()); emitDispState.pushFormat(textp->text());
} }
break; break;
@ -1086,8 +1134,7 @@ void EmitCStmts::visit(AstDisplay* nodep, AstNUser*) {
// expectFormat also checks this, and should have found it first, so internal // expectFormat also checks this, and should have found it first, so internal
elistp->v3error("Internal: Extra arguments for $display format\n"); elistp->v3error("Internal: Extra arguments for $display format\n");
} }
if (nodep->addNewline()) emitDispState.pushFormat("\\n"); displayEmit(nodep, isScan);
displayEmit(nodep);
} }
//###################################################################### //######################################################################

View File

@ -163,19 +163,30 @@ public:
virtual void visit(AstCoverInc*, AstNUser*) { virtual void visit(AstCoverInc*, AstNUser*) {
// N/A // N/A
} }
virtual void visit(AstDisplay* nodep, AstNUser*) {
void visitNodeDisplay(AstNode* nodep, AstNode* filep, const string& text, AstNode* exprsp) {
putbs(nodep->verilogKwd()); putbs(nodep->verilogKwd());
putbs(" ("); putbs(" (");
if (nodep->filep()) { nodep->filep()->iterateAndNext(*this); putbs(","); } if (filep) { filep->iterateAndNext(*this); putbs(","); }
puts("\""); puts("\"");
ofp()->putsNoTracking(nodep->text()); ofp()->putsNoTracking(text);
puts("\""); puts("\"");
for (AstNode* expp=nodep->exprsp(); expp; expp = expp->nextp()) { for (AstNode* expp=exprsp; expp; expp = expp->nextp()) {
puts(","); puts(",");
expp->iterateAndNext(*this); expp->iterateAndNext(*this);
} }
puts(");\n"); puts(");\n");
} }
virtual void visit(AstDisplay* nodep, AstNUser*) {
visitNodeDisplay(nodep, nodep->filep(), nodep->text(), nodep->exprsp());
}
virtual void visit(AstFScanF* nodep, AstNUser*) {
visitNodeDisplay(nodep, nodep->filep(), nodep->text(), nodep->exprsp());
}
virtual void visit(AstSScanF* nodep, AstNUser*) {
visitNodeDisplay(nodep, nodep->fromp(), nodep->text(), nodep->exprsp());
}
virtual void visit(AstFOpen* nodep, AstNUser*) { virtual void visit(AstFOpen* nodep, AstNUser*) {
putbs(nodep->verilogKwd()); putbs(nodep->verilogKwd());
putbs(" ("); putbs(" (");

View File

@ -133,6 +133,23 @@ private:
} }
m_setRefLvalue = last_setRefLvalue; m_setRefLvalue = last_setRefLvalue;
} }
virtual void visit(AstFScanF* nodep, AstNUser*) {
bool last_setRefLvalue = m_setRefLvalue;
{
m_setRefLvalue = true;
nodep->filep()->iterateAndNext(*this);
nodep->exprsp()->iterateAndNext(*this);
}
m_setRefLvalue = last_setRefLvalue;
}
virtual void visit(AstSScanF* nodep, AstNUser*) {
bool last_setRefLvalue = m_setRefLvalue;
{
m_setRefLvalue = true;
nodep->exprsp()->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

@ -312,22 +312,24 @@ private:
} }
} }
void expectFormat(AstNode* nodep, const string& format, AstNode* argp) { void expectFormat(AstNode* nodep, const string& format, AstNode* argp, bool isScan) {
// Check display arguments // Check display arguments
bool inPct = false; bool inPct = false;
for (const char* inp = format.c_str(); *inp; inp++) { for (const char* inp = format.c_str(); *inp; inp++) {
char ch = *inp; // Breaks with iterators... char ch = tolower(*inp); // Breaks with iterators...
if (!inPct && ch=='%') { if (!inPct && ch=='%') {
inPct = true; inPct = true;
} else if (inPct) { } else if (inPct) {
inPct = false; inPct = false;
switch (tolower(ch)) { switch (ch) {
case '0': case '1': case '2': case '3': case '4': case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': case '5': case '6': case '7': case '8': case '9':
inPct = true; inPct = true;
break; break;
case '%': break; // %% - just output a % case '%': break; // %% - just output a %
case 'm': break; // %m - auto insert "name" case 'm': // %m - auto insert "name"
if (isScan) nodep->v3error("Unsupported: %m in $fscanf");
break;
default: // Most operators, just move to next argument default: // Most operators, just move to next argument
if (!V3Number::displayedFmtLegal(ch)) { if (!V3Number::displayedFmtLegal(ch)) {
nodep->v3error("Unknown $display format code: %"<<ch); nodep->v3error("Unknown $display format code: %"<<ch);
@ -376,10 +378,19 @@ private:
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
expectDescriptor(nodep, nodep->filep()->castNodeVarRef()); expectDescriptor(nodep, nodep->filep()->castNodeVarRef());
} }
virtual void visit(AstFScanF* nodep, AstNUser*) {
nodep->iterateChildren(*this);
expectDescriptor(nodep, nodep->filep()->castNodeVarRef());
expectFormat(nodep, nodep->text(), nodep->exprsp(), true);
}
virtual void visit(AstSScanF* nodep, AstNUser*) {
nodep->iterateChildren(*this);
expectFormat(nodep, nodep->text(), nodep->exprsp(), true);
}
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());
expectFormat(nodep, nodep->name(), nodep->exprsp()); expectFormat(nodep, nodep->text(), nodep->exprsp(), false);
if (!m_assertp if (!m_assertp
&& (nodep->displayType() == AstDisplayType::INFO && (nodep->displayType() == AstDisplayType::INFO
|| nodep->displayType() == AstDisplayType::WARNING || nodep->displayType() == AstDisplayType::WARNING

View File

@ -83,6 +83,8 @@ private:
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(AstFGetC* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstFGetS* nodep, AstNUser*) { signed_Ou_Ix(nodep); } virtual void visit(AstFGetS* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstFScanF* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstSScanF* 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

@ -595,6 +595,20 @@ private:
nodep->width(32,32); nodep->width(32,32);
} }
} }
virtual void visit(AstFScanF* nodep, AstNUser* vup) {
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p());
nodep->exprsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
if (vup->c()->prelim()) {
nodep->width(32,32);
}
}
virtual void visit(AstSScanF* nodep, AstNUser* vup) {
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->exprsp()->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

@ -138,6 +138,7 @@ escid \\[^ \t\f\r\n]+
"$fgets" {yylval.fileline = CRELINE(); return yD_FGETS;} "$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;}
"$fscanf" {yylval.fileline = CRELINE(); return yD_FSCANF;}
"$fullskew" {yylval.fileline = CRELINE(); return yaTIMINGSPEC;} "$fullskew" {yylval.fileline = CRELINE(); return yaTIMINGSPEC;}
"$fwrite" {yylval.fileline = CRELINE(); return yD_FWRITE;} "$fwrite" {yylval.fileline = CRELINE(); return yD_FWRITE;}
"$hold" {yylval.fileline = CRELINE(); return yaTIMINGSPEC;} "$hold" {yylval.fileline = CRELINE(); return yaTIMINGSPEC;}
@ -153,6 +154,7 @@ escid \\[^ \t\f\r\n]+
"$setup" {yylval.fileline = CRELINE(); return yaTIMINGSPEC;} "$setup" {yylval.fileline = CRELINE(); return yaTIMINGSPEC;}
"$setuphold" {yylval.fileline = CRELINE(); return yaTIMINGSPEC;} "$setuphold" {yylval.fileline = CRELINE(); return yaTIMINGSPEC;}
"$skew" {yylval.fileline = CRELINE(); return yaTIMINGSPEC;} "$skew" {yylval.fileline = CRELINE(); return yaTIMINGSPEC;}
"$sscanf" {yylval.fileline = CRELINE(); return yD_SSCANF;}
"$stop" {yylval.fileline = CRELINE(); return yD_STOP;} "$stop" {yylval.fileline = CRELINE(); return yD_STOP;}
"$time" {yylval.fileline = CRELINE(); return yD_TIME;} "$time" {yylval.fileline = CRELINE(); return yD_TIME;}
"$timeskew" {yylval.fileline = CRELINE(); return yaTIMINGSPEC;} "$timeskew" {yylval.fileline = CRELINE(); return yaTIMINGSPEC;}

View File

@ -232,6 +232,7 @@ class AstSenTree;
%token<fileline> yD_FGETS "$fgets" %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_FSCANF "$fscanf"
%token<fileline> yD_FWRITE "$fwrite" %token<fileline> yD_FWRITE "$fwrite"
%token<fileline> yD_INFO "$info" %token<fileline> yD_INFO "$info"
%token<fileline> yD_ISUNKNOWN "$isunknown" %token<fileline> yD_ISUNKNOWN "$isunknown"
@ -241,6 +242,7 @@ class AstSenTree;
%token<fileline> yD_READMEMB "$readmemb" %token<fileline> yD_READMEMB "$readmemb"
%token<fileline> yD_READMEMH "$readmemh" %token<fileline> yD_READMEMH "$readmemh"
%token<fileline> yD_SIGNED "$signed" %token<fileline> yD_SIGNED "$signed"
%token<fileline> yD_SSCANF "$sscanf"
%token<fileline> yD_STOP "$stop" %token<fileline> yD_STOP "$stop"
%token<fileline> yD_TIME "$time" %token<fileline> yD_TIME "$time"
%token<fileline> yD_UNSIGNED "$unsigned" %token<fileline> yD_UNSIGNED "$unsigned"
@ -429,6 +431,7 @@ class AstSenTree;
%type<assignwp> gateBuf gateNot gateAnd gateNand gateOr gateNor gateXor gateXnor %type<assignwp> gateBuf gateNot gateAnd gateNand gateOr gateNor gateXor gateXnor
%type<nodep> gateAndPinList gateOrPinList gateXorPinList %type<nodep> gateAndPinList gateOrPinList gateXorPinList
%type<nodep> commaEListE %type<nodep> commaEListE
%type<nodep> commaVRDListE vrdList
%type<nodep> pslStmt pslDir pslDirOne pslProp %type<nodep> pslStmt pslDir pslDirOne pslProp
%type<nodep> pslDecl %type<nodep> pslDecl
@ -1087,6 +1090,8 @@ exprNoStr: expr yP_OROR expr { $$ = new AstLogOr ($2,$1,$3); }
| yD_FEOF '(' expr ')' { $$ = new AstFEof($1,$3); } | yD_FEOF '(' expr ')' { $$ = new AstFEof($1,$3); }
| yD_FGETC '(' expr ')' { $$ = new AstFGetC($1,$3); } | yD_FGETC '(' expr ')' { $$ = new AstFGetC($1,$3); }
| yD_FGETS '(' varRefDotBit ',' expr ')' { $$ = new AstFGetS($1,$3,$5); } | yD_FGETS '(' varRefDotBit ',' expr ')' { $$ = new AstFGetS($1,$3,$5); }
| yD_FSCANF '(' expr ',' yaSTRING commaVRDListE ')' { $$ = new AstFScanF($1,*$5,$3,$6); }
| yD_SSCANF '(' expr ',' yaSTRING commaVRDListE ')' { $$ = new AstSScanF($1,*$5,$3,$6); }
| 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); }
@ -1136,6 +1141,14 @@ commaEListE: /* empty */ { $$ = NULL; }
| ',' exprList { $$ = $2; } | ',' exprList { $$ = $2; }
; ;
vrdList: varRefDotBit { $$ = $1; }
| vrdList ',' varRefDotBit { $$ = $1;$1->addNext($3); }
;
commaVRDListE: /* empty */ { $$ = NULL; }
| ',' vrdList { $$ = $2; }
;
//************************************************ //************************************************
// Gate declarations // Gate declarations

View File

@ -12,6 +12,13 @@ module t;
reg [1*8:1] letterl; reg [1*8:1] letterl;
reg [8*8:1] letterq; reg [8*8:1] letterq;
reg [16*8:1] letterw; reg [16*8:1] letterw;
reg [16*8:1] letterz;
`ifdef TEST_VERBOSE
`define verbose 1'b1
`else
`define verbose 1'b0
`endif
initial begin initial begin
// Display formatting // Display formatting
@ -55,29 +62,124 @@ module t;
if ($fgetc(file) != "h") $stop; if ($fgetc(file) != "h") $stop;
if ($fgetc(file) != "i") $stop; if ($fgetc(file) != "i") $stop;
if ($fgetc(file) != "\n") $stop; if ($fgetc(file) != "\n") $stop;
// $fgets // $fgets
chars = $fgets(letterl, file); chars = $fgets(letterl, file);
$write("c=%0d l=%s\n", chars, letterl); if (`verbose) $write("c=%0d l=%s\n", chars, letterl);
if (chars != 1) $stop; if (chars != 1) $stop;
if (letterl != "l") $stop; if (letterl != "l") $stop;
chars = $fgets(letterq, file); chars = $fgets(letterq, file);
$write("c=%0d q=%x=%s", chars, letterq, letterq); // Output includes newline if (`verbose) $write("c=%0d q=%x=%s", chars, letterq, letterq); // Output includes newline
if (chars != 5) $stop; if (chars != 5) $stop;
if (letterq != "\0\0\0quad\n") $stop; if (letterq != "\0\0\0quad\n") $stop;
letterw = "5432109876543210"; letterw = "5432109876543210";
chars = $fgets(letterw, file); chars = $fgets(letterw, file);
$write("c=%0d w=%s", chars, letterw); // Output includes newline if (`verbose) $write("c=%0d w=%s", chars, letterw); // Output includes newline
if (chars != 10) $stop; if (chars != 10) $stop;
if (letterw != "\0\0\0\0\0\0widestuff\n") $stop; if (letterw != "\0\0\0\0\0\0widestuff\n") $stop;
// $sscanf
if ($sscanf("x","")!=0) $stop;
if ($sscanf("z","z")!=0) $stop;
chars = $sscanf("blabcdefghijklmnop",
"%s", letterq);
if (`verbose) $write("c=%0d sa=%s\n", chars, letterq);
if (chars != 1) $stop;
if (letterq != "ijklmnop") $stop;
chars = $sscanf("xa=1f xb=12898971238912389712783490823_237904689_02348923",
"xa=%x xb=%x", letterq, letterw);
if (`verbose) $write("c=%0d xa=%x xb=%x\n", chars, letterq, letterw);
if (chars != 2) $stop;
if (letterq != 64'h1f) $stop;
if (letterw != 128'h38971278349082323790468902348923) $stop;
chars = $sscanf("ba=10 bb=110100101010010101012 note_the_two ",
"ba=%b bb=%b%s", letterq, letterw, letterz);
if (`verbose) $write("c=%0d xa=%x xb=%x z=%0s\n", chars, letterq, letterw, letterz);
if (chars != 3) $stop;
if (letterq != 64'h2) $stop;
if (letterw != 128'hd2a55) $stop;
if (letterz != {"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0","2"}) $stop;
chars = $sscanf("oa=23 ob=125634123615234123681236",
"oa=%o ob=%o", letterq, letterw);
if (`verbose) $write("c=%0d oa=%x ob=%x\n", chars, letterq, letterw);
if (chars != 2) $stop;
if (letterq != 64'h13) $stop;
if (letterw != 128'h55ce14f1a9c29e) $stop;
chars = $sscanf("d=-236123",
"d=%d", letterq);
if (`verbose) $write("c=%0d d=%d\n", chars, letterq);
if (chars != 1) $stop;
if (letterq != 64'hfffffffffffc65a5) $stop;
// $fscanf
if ($fscanf(file,"")!=0) $stop;
if (!sync("*")) $stop;
chars = $fscanf(file, "xa=%x xb=%x", letterq, letterw);
if (`verbose) $write("c=%0d xa=%0x xb=%0x\n", chars, letterq, letterw);
if (chars != 2) $stop;
if (letterq != 64'h1f) $stop;
if (letterw != 128'h23790468902348923) $stop;
if (!sync("\n")) $stop;
if (!sync("*")) $stop;
chars = $fscanf(file, "ba=%b bb=%b %s", letterq, letterw, letterz);
if (`verbose) $write("c=%0d ba=%0x bb=%0x z=%0s\n", chars, letterq, letterw, letterz);
if (chars != 3) $stop;
if (letterq != 64'h2) $stop;
if (letterw != 128'hd2a55) $stop;
if (letterz != "\0\0\0\0note_the_two") $stop;
if (!sync("\n")) $stop;
if (!sync("*")) $stop;
chars = $fscanf(file, "oa=%o ob=%o", letterq, letterw);
if (`verbose) $write("c=%0d oa=%0x ob=%0x\n", chars, letterq, letterw);
if (chars != 2) $stop;
if (letterq != 64'h13) $stop;
if (letterw != 128'h1573) $stop;
if (!sync("\n")) $stop;
if (!sync("*")) $stop;
chars = $fscanf(file, "d=%d", letterq);
if (`verbose) $write("c=%0d d=%0x\n", chars, letterq);
if (chars != 1) $stop;
if (letterq != 64'hfffffffffffc65a5) $stop;
if (!sync("\n")) $stop;
if (!sync("*")) $stop;
chars = $fscanf(file, "%c%s", letterl, letterw);
if (`verbose) $write("c=%0d q=%c s=%s\n", chars, letterl, letterw);
if (chars != 2) $stop;
if (letterl != "f") $stop;
if (letterw != "\0\0\0\0\0redfishblah") $stop;
chars = $fscanf(file, "%c", letterl);
if (`verbose) $write("c=%0d l=%x\n", chars, letterl);
if (chars != 1) $stop;
if (letterl != "\n") $stop;
$fclose(file); $fclose(file);
end end
$write("*-* All Finished *-*\n"); $write("*-* All Finished *-*\n");
$finish(0); // Test arguments to finish $finish(0); // Test arguments to finish
end end
function sync;
input [7:0] cexp;
reg [7:0] cgot;
begin
cgot = $fgetc(file);
if (`verbose) $write("sync=%x='%c'\n", cgot,cgot);
sync = (cgot == cexp);
end
endfunction
endmodule endmodule

View File

@ -1,3 +1,8 @@
hi hi
lquad lquad
widestuff widestuff
*xa=1f xb=237904689_02348923
*ba=10 bb=11010010101001010101 note_the_two
*oa=23 ob=12563
*d=-236123
*fredfishblah