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*
|
* 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.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
119
src/V3EmitC.cpp
119
src/V3EmitC.cpp
|
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|
|
||||||
|
|
@ -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(" (");
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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); }
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
|
|
|
||||||
|
|
@ -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;}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue