Add support for , . Bug14.
This commit is contained in:
parent
1a8c8bec0d
commit
701bd38d01
4
Changes
4
Changes
|
|
@ -5,9 +5,9 @@ indicates the contributor was also the author of the fix; Thanks!
|
|||
|
||||
* 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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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, $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
|
||||
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
|
||||
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,
|
||||
$setup, $setuphold, $skew, $timeskew, $width
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
// The format must be pre-processed (and lower cased) by Verilator
|
||||
// Arguments are in "width, arg-value (or WDataIn* if wide)" form
|
||||
//
|
||||
// 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 widthSet = false;
|
||||
int width = 0;
|
||||
|
|
@ -184,12 +187,12 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
|
|||
}
|
||||
default: {
|
||||
// Deal with all read-and-print somethings
|
||||
int bits = va_arg(ap, int);
|
||||
const int lbits = va_arg(ap, int);
|
||||
QData ld = 0;
|
||||
WDataInP lwp;
|
||||
if (bits <= VL_QUADSIZE) {
|
||||
if (lbits <= VL_QUADSIZE) {
|
||||
WData qlwp[2];
|
||||
ld = _VL_VA_ARG_Q(ap, bits);
|
||||
ld = _VL_VA_ARG_Q(ap, lbits);
|
||||
VL_SET_WQ(qlwp,ld);
|
||||
lwp = qlwp;
|
||||
} else {
|
||||
|
|
@ -197,38 +200,14 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
|
|||
ld = lwp[0];
|
||||
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--;
|
||||
switch (fmt) {
|
||||
case 'b':
|
||||
for (; lsb>=0; lsb--) {
|
||||
output += ((lwp[VL_BITWORD_I(lsb)]>>VL_BITBIT_I(lsb)) & 1) + '0';
|
||||
}
|
||||
break;
|
||||
case 'c': {
|
||||
IData charval = ld & 0xff;
|
||||
output += charval;
|
||||
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':
|
||||
for (; lsb>=0; lsb--) {
|
||||
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;
|
||||
}
|
||||
break;
|
||||
case 'u': { // Unsigned decimal
|
||||
int digits=sprintf(str,"%llu",ld);
|
||||
case 'd': { // Signed decimal
|
||||
int digits=sprintf(tmp,"%lld",(vlsint64_t)(VL_EXTENDS_QQ(lbits,lbits,ld)));
|
||||
int needmore = width-digits;
|
||||
if (needmore>0) output.append(needmore,' '); // Pre-pad spaces
|
||||
output += str;
|
||||
output += tmp;
|
||||
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':
|
||||
for (; lsb>=0; lsb--) {
|
||||
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
|
||||
|
||||
|
|
@ -327,7 +551,6 @@ QData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode) {
|
|||
}
|
||||
|
||||
void VL_WRITEF(const char* formatp, ...) {
|
||||
|
||||
va_list ap;
|
||||
va_start(ap,formatp);
|
||||
string output;
|
||||
|
|
@ -351,6 +574,43 @@ void VL_FWRITEF(QData fpq, const char* formatp, ...) {
|
|||
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,
|
||||
QData ofilename, void* memp, IData start, IData end) {
|
||||
IData fnw[2]; VL_SET_WQ(fnw, ofilename);
|
||||
|
|
|
|||
|
|
@ -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_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
|
||||
|
||||
|
|
@ -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)))
|
||||
|
||||
/// 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
|
||||
/// Return FILE* from QData
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
|||
// Integer size macros
|
||||
|
||||
#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_QUADSIZE 64 ///< Bits in a quadword
|
||||
#define VL_WORDSIZE_LOG2 5 ///< log2(VL_WORDSIZE)
|
||||
|
|
|
|||
|
|
@ -1349,6 +1349,78 @@ struct AstFFlush : public AstNodeStmt {
|
|||
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 {
|
||||
private:
|
||||
bool m_isHex; // readmemh, not readmemb
|
||||
|
|
|
|||
119
src/V3EmitC.cpp
119
src/V3EmitC.cpp
|
|
@ -78,8 +78,10 @@ public:
|
|||
//int debug() { return 9; }
|
||||
|
||||
// METHODS
|
||||
void displayEmit(AstDisplay* nodep);
|
||||
void displayArg(AstDisplay* dispp, AstNode** elistp, string vfmt, char fmtLetter);
|
||||
void displayNode(AstNode* nodep, const string& vformat, AstNode* exprsp, bool isScan);
|
||||
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);
|
||||
typedef enum {EVL_IO, EVL_SIG, EVL_TEMP, EVL_STATIC, EVL_ALL} EisWhich;
|
||||
|
|
@ -229,7 +231,23 @@ public:
|
|||
nodep->lhsp()->iterateAndNext(*this);
|
||||
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*) {
|
||||
nodep->filep()->iterateAndNext(*this);
|
||||
puts(" = VL_FOPEN_");
|
||||
|
|
@ -241,9 +259,7 @@ public:
|
|||
puts(cvtToStr(nodep->filenamep()->widthWords()));
|
||||
putbs(", ");
|
||||
}
|
||||
if (nodep->filenamep()->widthWords() > VL_TO_STRING_MAX_WORDS) {
|
||||
nodep->v3error("String of "<<nodep->filenamep()->width()<<" bits exceeds hardcoded limit VL_TO_STRING_MAX_WORDS in verilatedos.h\n");
|
||||
}
|
||||
checkMaxWords(nodep->filenamep());
|
||||
nodep->filenamep()->iterateAndNext(*this);
|
||||
putbs(", ");
|
||||
nodep->modep()->iterateAndNext(*this);
|
||||
|
|
@ -270,9 +286,7 @@ public:
|
|||
puts(cvtToStr(array_lsb));
|
||||
putbs(",");
|
||||
puts(cvtToStr(nodep->filenamep()->widthWords()));
|
||||
if (nodep->filenamep()->widthWords() > VL_TO_STRING_MAX_WORDS) {
|
||||
nodep->v3error("String of "<<nodep->filenamep()->width()<<" bits exceeds hardcoded limit VL_TO_STRING_MAX_WORDS in verilatedos.h\n");
|
||||
}
|
||||
checkMaxWords(nodep->filenamep());
|
||||
putbs(", ");
|
||||
nodep->filenamep()->iterateAndNext(*this);
|
||||
putbs(", ");
|
||||
|
|
@ -950,16 +964,40 @@ struct EmitDispState {
|
|||
}
|
||||
} emitDispState;
|
||||
|
||||
void EmitCStmts::displayEmit(AstDisplay* nodep) {
|
||||
if (emitDispState.m_format != "") {
|
||||
void EmitCStmts::displayEmit(AstNode* nodep, bool isScan) {
|
||||
if (emitDispState.m_format == ""
|
||||
&& nodep->castDisplay()) { // not fscanf etc, as they need to return value
|
||||
// NOP
|
||||
} else {
|
||||
// Format
|
||||
if (nodep->filep()) {
|
||||
puts("VL_FWRITEF(");
|
||||
nodep->filep()->iterate(*this);
|
||||
puts(",\"");
|
||||
bool isStmt;
|
||||
if (AstFScanF* dispp = nodep->castFScanF()) {
|
||||
isStmt = false;
|
||||
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 {
|
||||
puts("VL_WRITEF(\"");
|
||||
isStmt = true;
|
||||
nodep->v3fatalSrc("Unknown displayEmit node type");
|
||||
}
|
||||
puts("\"");
|
||||
ofp()->putsNoTracking(emitDispState.m_format);
|
||||
puts("\"");
|
||||
// Arguments
|
||||
|
|
@ -970,17 +1008,24 @@ void EmitCStmts::displayEmit(AstDisplay* nodep) {
|
|||
ofp()->indentInc();
|
||||
ofp()->putbs("");
|
||||
if (func!="") puts(func);
|
||||
if (argp) argp->iterate(*this);
|
||||
if (argp) {
|
||||
if (isScan) puts("&(");
|
||||
argp->iterate(*this);
|
||||
if (isScan) puts(")");
|
||||
}
|
||||
ofp()->indentDec();
|
||||
}
|
||||
// End
|
||||
puts(");\n");
|
||||
puts(")");
|
||||
if (isStmt) puts(";\n");
|
||||
else puts(" ");
|
||||
// Prep for next
|
||||
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
|
||||
AstNode* argp = *elistp;
|
||||
if (!argp) {
|
||||
|
|
@ -993,16 +1038,17 @@ void EmitCStmts::displayArg(AstDisplay* dispp, AstNode** elistp, string vfmt, ch
|
|||
}
|
||||
if (argp && argp->isWide()
|
||||
&& (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') {
|
||||
// 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;
|
||||
if ((fmtLetter=='u' || fmtLetter=='d')
|
||||
&& !isScan
|
||||
&& vfmt == "") { // Size decimal output. Spec says leading spaces, not zeros
|
||||
double mantissabits = argp->widthMin() - ((fmtLetter=='d')?1:0);
|
||||
double maxval = pow(2.0, mantissabits);
|
||||
|
|
@ -1021,15 +1067,15 @@ void EmitCStmts::displayArg(AstDisplay* dispp, AstNode** elistp, string vfmt, ch
|
|||
*elistp = (*elistp)->nextp();
|
||||
}
|
||||
|
||||
void EmitCStmts::visit(AstDisplay* nodep, AstNUser*) {
|
||||
string vformat = nodep->text();
|
||||
AstNode* elistp = nodep->exprsp();
|
||||
void EmitCStmts::displayNode(AstNode* nodep, const string& vformat, AstNode* exprsp,
|
||||
bool isScan) {
|
||||
AstNode* elistp = exprsp;
|
||||
|
||||
// Convert Verilog display to C printf formats
|
||||
// "%0t" becomes "%d"
|
||||
emitDispState.clear();
|
||||
string vfmt = "";
|
||||
string::iterator pos = vformat.begin();
|
||||
string::const_iterator pos = vformat.begin();
|
||||
bool inPct = false;
|
||||
for (; pos != vformat.end(); ++pos) {
|
||||
//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 %
|
||||
break;
|
||||
// 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
|
||||
case 'b': displayArg(nodep,&elistp,vfmt,'b'); break;
|
||||
case 'c': displayArg(nodep,&elistp,vfmt,'c'); break;
|
||||
case 'b': displayArg(nodep,&elistp,isScan, vfmt,'b'); break;
|
||||
case 'c': displayArg(nodep,&elistp,isScan, vfmt,'c'); break;
|
||||
case 't':
|
||||
case 'd': displayArg(nodep,&elistp,vfmt,'u'); break; // Unsigned decimal
|
||||
case 'o': displayArg(nodep,&elistp,vfmt,'o'); break;
|
||||
case 'd': displayArg(nodep,&elistp,isScan, vfmt,'u'); break; // Unsigned decimal
|
||||
case 'o': displayArg(nodep,&elistp,isScan, vfmt,'o'); break;
|
||||
case 'h':
|
||||
case 'x': displayArg(nodep,&elistp,vfmt,'x'); break;
|
||||
case 's': displayArg(nodep,&elistp,vfmt,'s'); break;
|
||||
case 'x': displayArg(nodep,&elistp,isScan, vfmt,'x'); break;
|
||||
case 's': displayArg(nodep,&elistp,isScan, vfmt,'s'); break;
|
||||
case 'm': {
|
||||
emitDispState.pushFormat("%S");
|
||||
emitDispState.pushArg(NULL, "vlSymsp->name()");
|
||||
if (!nodep->scopeNamep()) nodep->v3fatalSrc("Display with %m but no AstScopeName");
|
||||
for (AstText* textp=nodep->scopeNamep()->scopeAttrp(); textp; textp=textp->nextp()->castText()) {
|
||||
if (!nodep->castDisplay()) nodep->v3fatalSrc("Non-Display with %m");
|
||||
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());
|
||||
}
|
||||
break;
|
||||
|
|
@ -1086,8 +1134,7 @@ void EmitCStmts::visit(AstDisplay* nodep, AstNUser*) {
|
|||
// expectFormat also checks this, and should have found it first, so internal
|
||||
elistp->v3error("Internal: Extra arguments for $display format\n");
|
||||
}
|
||||
if (nodep->addNewline()) emitDispState.pushFormat("\\n");
|
||||
displayEmit(nodep);
|
||||
displayEmit(nodep, isScan);
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
|
|
|||
|
|
@ -163,19 +163,30 @@ public:
|
|||
virtual void visit(AstCoverInc*, AstNUser*) {
|
||||
// N/A
|
||||
}
|
||||
virtual void visit(AstDisplay* nodep, AstNUser*) {
|
||||
|
||||
void visitNodeDisplay(AstNode* nodep, AstNode* filep, const string& text, AstNode* exprsp) {
|
||||
putbs(nodep->verilogKwd());
|
||||
putbs(" (");
|
||||
if (nodep->filep()) { nodep->filep()->iterateAndNext(*this); putbs(","); }
|
||||
if (filep) { filep->iterateAndNext(*this); putbs(","); }
|
||||
puts("\"");
|
||||
ofp()->putsNoTracking(nodep->text());
|
||||
ofp()->putsNoTracking(text);
|
||||
puts("\"");
|
||||
for (AstNode* expp=nodep->exprsp(); expp; expp = expp->nextp()) {
|
||||
for (AstNode* expp=exprsp; expp; expp = expp->nextp()) {
|
||||
puts(",");
|
||||
expp->iterateAndNext(*this);
|
||||
}
|
||||
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*) {
|
||||
putbs(nodep->verilogKwd());
|
||||
putbs(" (");
|
||||
|
|
|
|||
|
|
@ -133,6 +133,23 @@ private:
|
|||
}
|
||||
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*) {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
bool inPct = false;
|
||||
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=='%') {
|
||||
inPct = true;
|
||||
} else if (inPct) {
|
||||
inPct = false;
|
||||
switch (tolower(ch)) {
|
||||
switch (ch) {
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
inPct = true;
|
||||
break;
|
||||
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
|
||||
if (!V3Number::displayedFmtLegal(ch)) {
|
||||
nodep->v3error("Unknown $display format code: %"<<ch);
|
||||
|
|
@ -376,10 +378,19 @@ private:
|
|||
nodep->iterateChildren(*this);
|
||||
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*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->filep()) expectDescriptor(nodep, nodep->filep()->castNodeVarRef());
|
||||
expectFormat(nodep, nodep->name(), nodep->exprsp());
|
||||
expectFormat(nodep, nodep->text(), nodep->exprsp(), false);
|
||||
if (!m_assertp
|
||||
&& (nodep->displayType() == AstDisplayType::INFO
|
||||
|| nodep->displayType() == AstDisplayType::WARNING
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ private:
|
|||
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(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(AstReplicate* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
|
||||
|
|
|
|||
|
|
@ -595,6 +595,20 @@ private:
|
|||
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*) {
|
||||
nodep->filenamep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
nodep->memp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
|
|
|
|||
|
|
@ -138,6 +138,7 @@ escid \\[^ \t\f\r\n]+
|
|||
"$fgets" {yylval.fileline = CRELINE(); return yD_FGETS;}
|
||||
"$finish" {yylval.fileline = CRELINE(); return yD_FINISH;}
|
||||
"$fopen" {yylval.fileline = CRELINE(); return yD_FOPEN;}
|
||||
"$fscanf" {yylval.fileline = CRELINE(); return yD_FSCANF;}
|
||||
"$fullskew" {yylval.fileline = CRELINE(); return yaTIMINGSPEC;}
|
||||
"$fwrite" {yylval.fileline = CRELINE(); return yD_FWRITE;}
|
||||
"$hold" {yylval.fileline = CRELINE(); return yaTIMINGSPEC;}
|
||||
|
|
@ -153,6 +154,7 @@ escid \\[^ \t\f\r\n]+
|
|||
"$setup" {yylval.fileline = CRELINE(); return yaTIMINGSPEC;}
|
||||
"$setuphold" {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;}
|
||||
"$time" {yylval.fileline = CRELINE(); return yD_TIME;}
|
||||
"$timeskew" {yylval.fileline = CRELINE(); return yaTIMINGSPEC;}
|
||||
|
|
|
|||
|
|
@ -232,6 +232,7 @@ class AstSenTree;
|
|||
%token<fileline> yD_FGETS "$fgets"
|
||||
%token<fileline> yD_FINISH "$finish"
|
||||
%token<fileline> yD_FOPEN "$fopen"
|
||||
%token<fileline> yD_FSCANF "$fscanf"
|
||||
%token<fileline> yD_FWRITE "$fwrite"
|
||||
%token<fileline> yD_INFO "$info"
|
||||
%token<fileline> yD_ISUNKNOWN "$isunknown"
|
||||
|
|
@ -241,6 +242,7 @@ class AstSenTree;
|
|||
%token<fileline> yD_READMEMB "$readmemb"
|
||||
%token<fileline> yD_READMEMH "$readmemh"
|
||||
%token<fileline> yD_SIGNED "$signed"
|
||||
%token<fileline> yD_SSCANF "$sscanf"
|
||||
%token<fileline> yD_STOP "$stop"
|
||||
%token<fileline> yD_TIME "$time"
|
||||
%token<fileline> yD_UNSIGNED "$unsigned"
|
||||
|
|
@ -429,6 +431,7 @@ class AstSenTree;
|
|||
%type<assignwp> gateBuf gateNot gateAnd gateNand gateOr gateNor gateXor gateXnor
|
||||
%type<nodep> gateAndPinList gateOrPinList gateXorPinList
|
||||
%type<nodep> commaEListE
|
||||
%type<nodep> commaVRDListE vrdList
|
||||
|
||||
%type<nodep> pslStmt pslDir pslDirOne pslProp
|
||||
%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_FGETC '(' expr ')' { $$ = new AstFGetC($1,$3); }
|
||||
| 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_ONEHOT '(' expr ')' { $$ = new AstOneHot($1,$3); }
|
||||
| yD_ONEHOT0 '(' expr ')' { $$ = new AstOneHot0($1,$3); }
|
||||
|
|
@ -1136,6 +1141,14 @@ commaEListE: /* empty */ { $$ = NULL; }
|
|||
| ',' exprList { $$ = $2; }
|
||||
;
|
||||
|
||||
vrdList: varRefDotBit { $$ = $1; }
|
||||
| vrdList ',' varRefDotBit { $$ = $1;$1->addNext($3); }
|
||||
;
|
||||
|
||||
commaVRDListE: /* empty */ { $$ = NULL; }
|
||||
| ',' vrdList { $$ = $2; }
|
||||
;
|
||||
|
||||
//************************************************
|
||||
// Gate declarations
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,13 @@ module t;
|
|||
reg [1*8:1] letterl;
|
||||
reg [8*8:1] letterq;
|
||||
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
|
||||
// Display formatting
|
||||
|
|
@ -55,29 +62,124 @@ module t;
|
|||
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 (`verbose) $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 (`verbose) $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 (`verbose) $write("c=%0d w=%s", chars, letterw); // Output includes newline
|
||||
if (chars != 10) $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);
|
||||
end
|
||||
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish(0); // Test arguments to finish
|
||||
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
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
hi
|
||||
lquad
|
||||
widestuff
|
||||
*xa=1f xb=237904689_02348923
|
||||
*ba=10 bb=11010010101001010101 note_the_two
|
||||
*oa=23 ob=12563
|
||||
*d=-236123
|
||||
*fredfishblah
|
||||
|
|
|
|||
Loading…
Reference in New Issue