Add support.
git-svn-id: file://localhost/svn/verilator/trunk/verilator@846 77ca24e4-aefa-0310-84f0-b9a241c72d87
This commit is contained in:
parent
a599fbea18
commit
699563c9bd
2
Changes
2
Changes
|
|
@ -5,6 +5,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
|||
|
||||
* Verilator 3.62***
|
||||
|
||||
** Support $readmemb and $readmemh. [Eugene Weber, Arthur Kahlich]
|
||||
|
||||
*** Fixed configure and compiling under Solaris. [Bob Farrell]
|
||||
|
||||
*** When dotted signal lookup fails, help the user by showing known scopes.
|
||||
|
|
|
|||
|
|
@ -996,16 +996,6 @@ Verilog standard, %x prints a number with the natural width, %0x prints a
|
|||
number with minimum width, however %5x prints 5 digits per the C standard
|
||||
(it's unspecified in Verilog).
|
||||
|
||||
=item $fopen, $fclose, $fdisplay, $fwrite
|
||||
|
||||
File descriptors passed to the file PLI calls must be file descriptors, not
|
||||
MCDs, which includes the mode parameter to $fopen being mandatory.
|
||||
Verilator will convert the integer used to hold the file descriptor into a
|
||||
internal FILE*. To prevent core dumps due to mis-use, and because integers
|
||||
are 32 bits while FILE*s may be 64 bits, the descriptor must be stored in a
|
||||
reg [63:0] rather then an integer. The define `verilator_file_descriptor in
|
||||
verilated.v can be used to hide this difference.
|
||||
|
||||
=item `coverage_block_off
|
||||
|
||||
Specifies the entire begin/end block should be ignored for coverage analysis.
|
||||
|
|
@ -1316,6 +1306,27 @@ appropriate width.
|
|||
$display and friends must have a constant format string as the first
|
||||
argument (as with C's printf), you cannot simply list variables standalone.
|
||||
|
||||
=item $displayb, $displayh, $displayo, $writeb, $writeh, $writeo, etc
|
||||
|
||||
The sized display functions are rarely used and so not supported. Replace
|
||||
them with a $write with the appropriate format specifier.
|
||||
|
||||
=item $fopen, $fclose, $fdisplay, $fwrite
|
||||
|
||||
File descriptors passed to the file PLI calls must be file descriptors, not
|
||||
MCDs, which includes the mode parameter to $fopen being mandatory.
|
||||
Verilator will convert the integer used to hold the file descriptor into a
|
||||
internal FILE*. To prevent core dumps due to mis-use, and because integers
|
||||
are 32 bits while FILE*s may be 64 bits, the descriptor must be stored in a
|
||||
reg [63:0] rather then an integer. The define `verilator_file_descriptor in
|
||||
verilated.v can be used to hide this difference.
|
||||
|
||||
=item $readmemb, $readmemh
|
||||
|
||||
Read memory commands should work properly. Note Verilator and the Verilog
|
||||
specification does not include support for readmem to multi-dimensional
|
||||
arrays.
|
||||
|
||||
=head1 ERRORS AND WARNINGS
|
||||
|
||||
Warnings may be disabled in two ways. First, when the warning is
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "verilated.h"
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#define VL_VALUE_STRING_MAX_WIDTH 1024 ///< Max static char array for VL_VALUE_STRING
|
||||
|
||||
|
|
@ -238,6 +239,113 @@ QData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode) {
|
|||
return VL_CVT_FP_Q(fopen(filenamez,modez));
|
||||
}
|
||||
|
||||
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);
|
||||
return VL_READMEM_W(hex,2,width,depth,array_lsb, fnw,memp,start,end);
|
||||
}
|
||||
|
||||
void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
WDataInP ofilenamep, void* memp, IData start, IData end) {
|
||||
char ofilenamez[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1];
|
||||
_VL_VINT_TO_STRING(fnwords*VL_WORDSIZE, ofilenamez, ofilenamep);
|
||||
FILE* fp = fopen(ofilenamez, "r");
|
||||
if (!fp) {
|
||||
// We don't report the Verilog source filename as it slow to have to pass it down
|
||||
vl_fatal (ofilenamez, 0, "", "$readmem file not found");
|
||||
return;
|
||||
}
|
||||
// Prep for reading
|
||||
IData addr = start;
|
||||
int linenum = 0;
|
||||
bool innum = false;
|
||||
bool ignore_to_eol = false;
|
||||
bool ignore_to_cmt = false;
|
||||
bool needinc = false;
|
||||
bool reading_addr = false;
|
||||
int lastc = ' ';
|
||||
// Read the data
|
||||
// We process a character at a time, as then we don't need to deal
|
||||
// with changing buffer sizes dynamically, etc.
|
||||
while (1) {
|
||||
int c = fgetc(fp);
|
||||
if (c==EOF) break;
|
||||
//printf("%d: Got '%c' Addr%x IN%d IgE%d IgC%d ninc%d\n", linenum, c, addr, innum, ignore_to_eol, ignore_to_cmt, needinc);
|
||||
if (c=='\n') { linenum++; ignore_to_eol=false; if (innum) reading_addr=false; innum=false; }
|
||||
else if (c=='\t' || c==' ' || c=='\r' || c=='\f') { if (innum) reading_addr=false; innum=false; }
|
||||
// Skip // comments and detect /* comments
|
||||
else if (ignore_to_cmt && lastc=='*' && c=='/') {
|
||||
ignore_to_cmt = false; if (innum) reading_addr=false; innum=false;
|
||||
} else if (!ignore_to_eol && !ignore_to_cmt) {
|
||||
if (lastc=='/' && c=='*') { ignore_to_cmt = true; }
|
||||
else if (lastc=='/' && c=='/') { ignore_to_eol = true; }
|
||||
else if (c=='/') {} // Part of /* or //
|
||||
else if (c=='_') {}
|
||||
else if (c=='@') { reading_addr = true; innum=false; needinc=false; }
|
||||
// Check for hex or binary digits as file format requests
|
||||
else if (isxdigit(c)) {
|
||||
c = tolower(c);
|
||||
int value = (c >= 'a' ? (c-'a'+10) : (c-'0'));
|
||||
if (!innum) { // Prep for next number
|
||||
if (needinc) { addr++; needinc=false; }
|
||||
}
|
||||
if (reading_addr) {
|
||||
// Decode @ addresses
|
||||
if (!innum) addr=0;
|
||||
addr = (addr<<4) + value;
|
||||
} else {
|
||||
needinc = true;
|
||||
//printf(" Value width=%d @%x = %c\n", width, addr, c);
|
||||
if (addr >= (IData)(depth+array_lsb) || addr < (IData)(array_lsb)) {
|
||||
vl_fatal (ofilenamez, linenum, "", "$readmem file address beyond bounds of array");
|
||||
} else {
|
||||
int entry = addr - array_lsb;
|
||||
QData shift = hex ? VL_ULL(4) : VL_ULL(1);
|
||||
// Shift value in
|
||||
if (width<=8) {
|
||||
CData* datap = &((CData*)(memp))[entry];
|
||||
if (!innum) { *datap = 0; }
|
||||
*datap = ((*datap << shift) + value) & VL_MASK_I(width);
|
||||
} else if (width<=16) {
|
||||
SData* datap = &((SData*)(memp))[entry];
|
||||
if (!innum) { *datap = 0; }
|
||||
*datap = ((*datap << shift) + value) & VL_MASK_I(width);
|
||||
} else if (width<=VL_WORDSIZE) {
|
||||
IData* datap = &((IData*)(memp))[entry];
|
||||
if (!innum) { *datap = 0; }
|
||||
*datap = ((*datap << shift) + value) & VL_MASK_I(width);
|
||||
} else if (width<=VL_QUADSIZE) {
|
||||
QData* datap = &((QData*)(memp))[entry];
|
||||
if (!innum) { *datap = 0; }
|
||||
*datap = ((*datap << (QData)(shift)) + (QData)(value)) & VL_MASK_Q(width);
|
||||
} else {
|
||||
WDataOutP datap = &((WDataOutP)(memp))[ entry*VL_WORDS_I(width) ];
|
||||
if (!innum) { VL_ZERO_RESET_W(width, datap); }
|
||||
_VL_SHIFTL_INPLACE_W(width, datap, shift);
|
||||
datap[0] |= value;
|
||||
}
|
||||
if (value>=(1<<shift)) {
|
||||
vl_fatal (ofilenamez, linenum, "", "$readmemb (binary) file contains hex characters");
|
||||
}
|
||||
}
|
||||
}
|
||||
innum = true;
|
||||
}
|
||||
else {
|
||||
vl_fatal (ofilenamez, linenum, "", "$readmem file syntax error");
|
||||
}
|
||||
}
|
||||
lastc = c;
|
||||
}
|
||||
if (needinc) { addr++; needinc=false; }
|
||||
|
||||
// Final checks
|
||||
fclose(fp);
|
||||
if (end != (IData)(~ VL_ULL(0)) && addr != (end+1)) {
|
||||
vl_fatal (ofilenamez, linenum, "", "$readmem file ended before specified ending-address");
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
// Verilated:: Methods
|
||||
|
||||
|
|
|
|||
|
|
@ -194,9 +194,17 @@ inline const char* VL_VALUE_FORMATTED_I(int obits, char fmt, bool drop0, IData l
|
|||
}
|
||||
|
||||
/// File I/O
|
||||
extern QData VL_FOPEN_WI(int fnwords, WDataInP filename, IData mode);
|
||||
extern QData VL_FOPEN_QI(QData filename, IData mode);
|
||||
inline QData VL_FOPEN_II(IData filename, IData mode) { return VL_FOPEN_QI(filename,mode); }
|
||||
extern QData VL_FOPEN_WI(int fnwords, WDataInP ofilename, IData mode);
|
||||
extern QData VL_FOPEN_QI(QData ofilename, IData mode);
|
||||
inline QData VL_FOPEN_II(IData ofilename, IData mode) { return VL_FOPEN_QI(ofilename,mode); }
|
||||
|
||||
extern void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
WDataInP ofilename, void* memp, IData start, IData end);
|
||||
extern void VL_READMEM_Q(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
QData ofilename, void* memp, IData start, IData end);
|
||||
inline void VL_READMEM_I(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
IData ofilename, void* memp, IData start, IData end) {
|
||||
VL_READMEM_Q(hex, width,depth,array_lsb,fnwords, ofilename,memp,start,end); }
|
||||
|
||||
//=========================================================================
|
||||
// Base macros
|
||||
|
|
@ -226,6 +234,13 @@ static inline QData VL_CVT_FP_Q(FILE* fp) { union { FILE* fp; QData q; } u; u.q
|
|||
static inline IData VL_EXTENDSIGN_I(int lbits, IData lhs) { return (-((lhs)&(1UL<<(lbits-1)))); }
|
||||
static inline QData VL_EXTENDSIGN_Q(int lbits, QData lhs) { return (-((lhs)&(VL_ULL(1)<<(lbits-1)))); }
|
||||
|
||||
// Debugging prints
|
||||
static inline void _VL_DEBUG_PRINT_W(int lbits, WDataInP iwp) {
|
||||
printf(" Data: w%d: ", lbits);
|
||||
for (int i=VL_WORDS_I(lbits)-1; i>=0; i--) { printf("%08x ",iwp[i]); }
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Pli macros
|
||||
|
||||
|
|
@ -1035,6 +1050,18 @@ static inline WDataOutP VL_CONCAT_WWW(int obits,int lbits,int rbits,WDataOutP ow
|
|||
//===================================================================
|
||||
// Shifts
|
||||
|
||||
// Static shift, used by internal functions
|
||||
// The output is the same as the input - it overlaps!
|
||||
static inline void _VL_SHIFTL_INPLACE_W(int obits,WDataOutP iowp,IData rd/*1 or 4*/) {
|
||||
int words = VL_WORDS_I(obits);
|
||||
IData linsmask = VL_MASK_I(rd);
|
||||
for (int i=words-1; i>=1; i--) {
|
||||
iowp[i] = ((iowp[i]<<rd) & ~linsmask) | ((iowp[i-1] >> (32-rd)) & linsmask);
|
||||
}
|
||||
iowp[0] = ((iowp[0]<<rd) & ~linsmask);
|
||||
iowp[VL_WORDS_I(obits)-1] &= VL_MASK_I(obits);
|
||||
}
|
||||
|
||||
// EMIT_RULE: VL_SHIFTL: oclean=lclean; rclean==clean;
|
||||
// Important: Unlike most other funcs, the shift might well be a computed
|
||||
// expression. Thus consider this when optimizing. (And perhaps have 2 funcs?)
|
||||
|
|
|
|||
|
|
@ -1251,6 +1251,34 @@ struct AstFOpen : public AstNodeStmt {
|
|||
AstNode* modep() const { return op3p(); }
|
||||
};
|
||||
|
||||
struct AstReadMem : public AstNodeStmt {
|
||||
private:
|
||||
bool m_isHex; // readmemh, not readmemb
|
||||
public:
|
||||
AstReadMem(FileLine* fileline, bool hex,
|
||||
AstNode* filenamep, AstNode* memp, AstNode* lsbp, AstNode* msbp)
|
||||
: AstNodeStmt (fileline), m_isHex(hex) {
|
||||
setOp1p(filenamep); setOp2p(memp); setNOp3p(lsbp); setNOp4p(msbp);
|
||||
}
|
||||
virtual ~AstReadMem() {}
|
||||
virtual AstType type() const { return AstType::READMEM;}
|
||||
virtual AstNode* clone() { return new AstReadMem(*this); }
|
||||
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) { v.visit(this,vup); }
|
||||
virtual string verilogKwd() const { return (isHex()?"$readmemh":"$readmemb"); };
|
||||
virtual bool isGateOptimizable() const { return false; }
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
virtual bool isSplittable() const { return false; }
|
||||
virtual bool isOutputter() const { return true; }
|
||||
virtual bool isUnlikely() const { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return isHex()==samep->castReadMem()->isHex(); }
|
||||
bool isHex() const { return m_isHex; }
|
||||
AstNode* filenamep() const { return op1p()->castNode(); }
|
||||
AstNode* memp() const { return op2p()->castNode(); }
|
||||
AstNode* lsbp() const { return op3p()->castNode(); }
|
||||
AstNode* msbp() const { return op4p()->castNode(); }
|
||||
};
|
||||
|
||||
struct AstGenFor : public AstNodeFor {
|
||||
AstGenFor(FileLine* fileline, AstNode* initsp, AstNode* condp,
|
||||
AstNode* incsp, AstNode* bodysp)
|
||||
|
|
|
|||
|
|
@ -249,6 +249,39 @@ public:
|
|||
nodep->modep()->iterateAndNext(*this);
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstReadMem* nodep, AstNUser*) {
|
||||
puts("VL_READMEM_");
|
||||
emitIQW(nodep->filenamep());
|
||||
puts(" ("); // We take a void* rather then emitIQW(nodep->memp());
|
||||
puts(nodep->isHex()?"true":"false");
|
||||
putbs(",");
|
||||
puts(cvtToStr(nodep->memp()->widthMin())); // Need real storage width
|
||||
putbs(",");
|
||||
uint32_t array_lsb = 0;
|
||||
{
|
||||
AstVarRef* varrefp = nodep->memp()->castVarRef();
|
||||
if (!varrefp || !varrefp->varp()->arrayp(0)) { nodep->v3error("Readmem loading non-arrayed variable"); }
|
||||
else {
|
||||
puts(cvtToStr(varrefp->varp()->arrayElements()));
|
||||
array_lsb = varrefp->varp()->arrayp(0)->lsbConst();
|
||||
}
|
||||
}
|
||||
putbs(", ");
|
||||
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");
|
||||
}
|
||||
putbs(", ");
|
||||
nodep->filenamep()->iterateAndNext(*this);
|
||||
putbs(", ");
|
||||
nodep->memp()->iterateAndNext(*this);
|
||||
putbs(","); if (nodep->lsbp()) { nodep->lsbp()->iterateAndNext(*this); }
|
||||
else puts(cvtToStr(array_lsb));
|
||||
putbs(","); if (nodep->msbp()) { nodep->msbp()->iterateAndNext(*this); } else puts("~0");
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstFClose* nodep, AstNUser*) {
|
||||
puts("if (");
|
||||
nodep->filep()->iterateAndNext(*this);
|
||||
|
|
|
|||
|
|
@ -193,6 +193,16 @@ public:
|
|||
if (nodep->filep()) nodep->filep()->iterateChildren(*this);
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstReadMem* nodep, AstNUser*) {
|
||||
putbs(nodep->verilogKwd());
|
||||
putbs(" (");
|
||||
if (nodep->filenamep()) nodep->filenamep()->iterateChildren(*this);
|
||||
putbs(",");
|
||||
if (nodep->memp()) nodep->memp()->iterateChildren(*this);
|
||||
if (nodep->lsbp()) { putbs(","); nodep->lsbp()->iterateChildren(*this); }
|
||||
if (nodep->msbp()) { putbs(","); nodep->msbp()->iterateChildren(*this); }
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstNodeFor* nodep, AstNUser*) {
|
||||
puts("for (");
|
||||
m_suppressSemi = true;
|
||||
|
|
|
|||
|
|
@ -554,6 +554,12 @@ private:
|
|||
virtual void visit(AstFClose* nodep, AstNUser*) {
|
||||
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p());
|
||||
}
|
||||
virtual void visit(AstReadMem* nodep, AstNUser*) {
|
||||
nodep->filenamep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
nodep->memp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
nodep->lsbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
nodep->msbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
}
|
||||
virtual void visit(AstUCStmt* nodep, AstNUser*) {
|
||||
// TOP LEVEL NODE
|
||||
// Just let all arguments seek their natural sizes
|
||||
|
|
|
|||
|
|
@ -174,6 +174,8 @@ escid \\[^ \t\f\r\n]+
|
|||
<VLG,PSL>"$onehot0" {yylval.fileline = CRELINE(); return yD_ONEHOT0;}
|
||||
<VLG,PSL>"$period" {yylval.fileline = CRELINE(); return yTIMINGSPEC;}
|
||||
<VLG,PSL>"$realtime" {yylval.fileline = CRELINE(); return yD_TIME;}
|
||||
<VLG,PSL>"$readmemb" {yylval.fileline = CRELINE(); return yD_READMEMB;}
|
||||
<VLG,PSL>"$readmemh" {yylval.fileline = CRELINE(); return yD_READMEMH;}
|
||||
<VLG,PSL>"$recovery" {yylval.fileline = CRELINE(); return yTIMINGSPEC;}
|
||||
<VLG,PSL>"$recrem" {yylval.fileline = CRELINE(); return yTIMINGSPEC;}
|
||||
<VLG,PSL>"$removal" {yylval.fileline = CRELINE(); return yTIMINGSPEC;}
|
||||
|
|
|
|||
|
|
@ -136,31 +136,33 @@ class AstSenTree;
|
|||
%token<fileline> yBUF yNOT yAND yNAND yNOR yXOR yXNOR
|
||||
%token<fileline> ySCALARED yVECTORED
|
||||
|
||||
%token<fileline> yASSERT "assert"
|
||||
%token<fileline> yCLOCK "clock"
|
||||
%token<fileline> yCOVER "cover"
|
||||
%token<fileline> yFINAL "final"
|
||||
%token<fileline> yPSL "psl"
|
||||
%token<fileline> yREPORT "report"
|
||||
%token<fileline> yTRUE "true"
|
||||
%token<fileline> yASSERT "assert"
|
||||
%token<fileline> yCLOCK "clock"
|
||||
%token<fileline> yCOVER "cover"
|
||||
%token<fileline> yFINAL "final"
|
||||
%token<fileline> yPSL "psl"
|
||||
%token<fileline> yREPORT "report"
|
||||
%token<fileline> yTRUE "true"
|
||||
|
||||
%token<fileline> yD_BITS "$bits"
|
||||
%token<fileline> yD_C "$c"
|
||||
%token<fileline> yD_COUNTONES "$countones"
|
||||
%token<fileline> yD_DISPLAY "$display"
|
||||
%token<fileline> yD_FCLOSE "$fclose"
|
||||
%token<fileline> yD_FDISPLAY "$fdisplay"
|
||||
%token<fileline> yD_FINISH "$finish"
|
||||
%token<fileline> yD_FOPEN "$fopen"
|
||||
%token<fileline> yD_FWRITE "$fwrite"
|
||||
%token<fileline> yD_ISUNKNOWN "$isunknown"
|
||||
%token<fileline> yD_ONEHOT "$onehot"
|
||||
%token<fileline> yD_ONEHOT0 "$onehot0"
|
||||
%token<fileline> yD_SIGNED "$signed"
|
||||
%token<fileline> yD_STOP "$stop"
|
||||
%token<fileline> yD_TIME "$time"
|
||||
%token<fileline> yD_UNSIGNED "$unsigned"
|
||||
%token<fileline> yD_WRITE "$write"
|
||||
%token<fileline> yD_BITS "$bits"
|
||||
%token<fileline> yD_C "$c"
|
||||
%token<fileline> yD_COUNTONES "$countones"
|
||||
%token<fileline> yD_DISPLAY "$display"
|
||||
%token<fileline> yD_FCLOSE "$fclose"
|
||||
%token<fileline> yD_FDISPLAY "$fdisplay"
|
||||
%token<fileline> yD_FINISH "$finish"
|
||||
%token<fileline> yD_FOPEN "$fopen"
|
||||
%token<fileline> yD_FWRITE "$fwrite"
|
||||
%token<fileline> yD_ISUNKNOWN "$isunknown"
|
||||
%token<fileline> yD_ONEHOT "$onehot"
|
||||
%token<fileline> yD_ONEHOT0 "$onehot0"
|
||||
%token<fileline> yD_READMEMB "$readmemb"
|
||||
%token<fileline> yD_READMEMH "$readmemh"
|
||||
%token<fileline> yD_SIGNED "$signed"
|
||||
%token<fileline> yD_STOP "$stop"
|
||||
%token<fileline> yD_TIME "$time"
|
||||
%token<fileline> yD_UNSIGNED "$unsigned"
|
||||
%token<fileline> yD_WRITE "$write"
|
||||
|
||||
%token<fileline> yVL_CLOCK "/*verilator sc_clock*/"
|
||||
%token<fileline> yVL_CLOCK_ENABLE "/*verilator clock_enable*/"
|
||||
|
|
@ -670,15 +672,21 @@ stmt: ';' { $$ = NULL; }
|
|||
| stateCaseForIf { $$ = $1; }
|
||||
| taskRef ';' { $$ = $1; }
|
||||
|
||||
| yD_DISPLAY ';' { $$ = new AstDisplay($1,'\n',"",NULL,NULL); }
|
||||
| yD_DISPLAY '(' ySTRING ')' ';' { $$ = new AstDisplay($1,'\n',*$3,NULL,NULL); }
|
||||
| yD_DISPLAY '(' ySTRING ',' eList ')' ';' { $$ = new AstDisplay($1,'\n',*$3,NULL,$5); }
|
||||
| yD_WRITE '(' ySTRING ')' ';' { $$ = new AstDisplay($1,'\0',*$3,NULL,NULL); }
|
||||
| yD_DISPLAY ';' { $$ = new AstDisplay($1,'\n',"",NULL,NULL); }
|
||||
| yD_DISPLAY '(' ySTRING ')' ';' { $$ = new AstDisplay($1,'\n',*$3,NULL,NULL); }
|
||||
| yD_DISPLAY '(' ySTRING ',' eList ')' ';' { $$ = new AstDisplay($1,'\n',*$3,NULL,$5); }
|
||||
| yD_WRITE '(' ySTRING ')' ';' { $$ = new AstDisplay($1,'\0',*$3,NULL,NULL); }
|
||||
| yD_WRITE '(' ySTRING ',' eList ')' ';' { $$ = new AstDisplay($1,'\0',*$3,NULL,$5); }
|
||||
| yD_FDISPLAY '(' idVarXRef ',' ySTRING ')' ';' { $$ = new AstDisplay($1,'\n',*$5,$3,NULL); }
|
||||
| yD_FDISPLAY '(' idVarXRef ',' ySTRING ',' eList ')' ';' { $$ = new AstDisplay($1,'\n',*$5,$3,$7); }
|
||||
| yD_FDISPLAY '(' idVarXRef ',' ySTRING ',' eList ')' ';' { $$ = new AstDisplay($1,'\n',*$5,$3,$7); }
|
||||
| yD_FWRITE '(' idVarXRef ',' ySTRING ')' ';' { $$ = new AstDisplay($1,'\0',*$5,$3,NULL); }
|
||||
| yD_FWRITE '(' idVarXRef ',' ySTRING ',' eList ')' ';' { $$ = new AstDisplay($1,'\0',*$5,$3,$7); }
|
||||
| yD_FWRITE '(' idVarXRef ',' ySTRING ',' eList ')' ';' { $$ = new AstDisplay($1,'\0',*$5,$3,$7); }
|
||||
| yD_READMEMB '(' expr ',' lhIdArrayed ')' ';' { $$ = new AstReadMem($1,false,$3,$5,NULL,NULL); }
|
||||
| yD_READMEMB '(' expr ',' lhIdArrayed ',' expr ')' ';' { $$ = new AstReadMem($1,false,$3,$5,$7,NULL); }
|
||||
| yD_READMEMB '(' expr ',' lhIdArrayed ',' expr ',' expr ')' ';' { $$ = new AstReadMem($1,false,$3,$5,$7,$9); }
|
||||
| yD_READMEMH '(' expr ',' lhIdArrayed ')' ';' { $$ = new AstReadMem($1,true, $3,$5,NULL,NULL); }
|
||||
| yD_READMEMH '(' expr ',' lhIdArrayed ',' expr ')' ';' { $$ = new AstReadMem($1,true, $3,$5,$7,NULL); }
|
||||
| yD_READMEMH '(' expr ',' lhIdArrayed ',' expr ',' expr ')' ';' { $$ = new AstReadMem($1,true, $3,$5,$7,$9); }
|
||||
;
|
||||
|
||||
stateCaseForIf: caseStmt caseAttrE caseList yENDCASE { $$ = $1; $1->addItemsp($3); }
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ my $opt_stop;
|
|||
my $opt_optimize;
|
||||
my $opt_gdb;
|
||||
my $opt_jobs = 1;
|
||||
my $opt_verbose;
|
||||
my $Opt_Verilated_Debug;
|
||||
if (! GetOptions (
|
||||
"help" => \&usage,
|
||||
|
|
@ -69,6 +70,7 @@ if (! GetOptions (
|
|||
"gdb!" => \$opt_gdb,
|
||||
"stop!" => \$opt_stop,
|
||||
"optimize:s" => \$opt_optimize,
|
||||
"verbose!" => \$opt_verbose,
|
||||
"<>" => \¶meter,
|
||||
)) {
|
||||
usage();
|
||||
|
|
@ -187,7 +189,9 @@ sub new {
|
|||
make_top_shell => 1, # Make a default __top.v file
|
||||
make_main => 1, # Make __main.cpp
|
||||
# All compilers
|
||||
v_flags => [split(/\s+/," -f input.vc --debug-check")],
|
||||
v_flags => [split(/\s+/,(" -f input.vc --debug-check"
|
||||
.($opt_verbose ? " +define+TEST_VERBOSE+1":"")
|
||||
))],
|
||||
v_flags2 => [], # Overridden in some sim files
|
||||
v_other_filenames => [], # After the filename so we can spec multiple files
|
||||
# VCS
|
||||
|
|
@ -827,6 +831,10 @@ Stop on the first error
|
|||
|
||||
Run using VCS.
|
||||
|
||||
=item --verbose
|
||||
|
||||
Enable test verbose messages.
|
||||
|
||||
=item --v3
|
||||
|
||||
Run using Verilator.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// $Id:$
|
||||
// $Id$
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
|
|
@ -83,7 +83,9 @@ module t (/*AUTOARG*/
|
|||
|
||||
always @ (posedge fastclk) begin
|
||||
cyc <= cyc+1;
|
||||
`ifdef TEST_VERBOSE
|
||||
$write("%d %x %x %x %x %x %x\n",cyc,data_a,data_a_a,data_b_a,data_b,data_a_b,data_b_b);
|
||||
`endif
|
||||
if (cyc>=19 && cyc<36) begin
|
||||
if (compare !== check[cyc]) begin
|
||||
$write("[%0t] Mismatch, got=%x, exp=%x\n", $time, compare, check[cyc]);
|
||||
|
|
|
|||
|
|
@ -7,16 +7,16 @@ if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
|
|||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# General Public License or the Perl Artistic License.
|
||||
|
||||
unlink("obj_dir/t_sys_file_test.log");
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
unlink("obj_dir/t_file_test.log");
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
file_grep ("obj_dir/t_file_test.log",
|
||||
file_grep ("obj_dir/t_sys_file_test.log",
|
||||
qr/\[0\] hello v=12345667
|
||||
\[0\] Hello2
|
||||
/);
|
||||
|
|
@ -16,7 +16,7 @@ module t;
|
|||
$fwrite(file, "Never printed, file closed\n");
|
||||
`endif
|
||||
|
||||
file = $fopen("obj_dir/t_file_test.log","w"); // The "w" is required so we get a FD not a MFD
|
||||
file = $fopen("obj_dir/t_sys_file_test.log","w"); // The "w" is required so we get a FD not a MFD
|
||||
|
||||
$fdisplay(file, "[%0t] hello v=%x", $time, 32'h12345667);
|
||||
$fwrite(file, "[%0t] %s\n", $time, "Hello2");
|
||||
|
|
@ -27,6 +27,11 @@ module t;
|
|||
$fwrite(file, "Never printed, file closed\n");
|
||||
`endif
|
||||
|
||||
begin
|
||||
file = $fopen("obj_dir/DOES_NOT_EXIST","r"); // The "r" is required so we get a FD not a MFD
|
||||
if (|file) $stop; // Should not exist, IE must return 0
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
|
||||
# $Id$
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# General Public License or the Perl Artistic License.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
// $Id$
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2003 by Wilson Snyder.
|
||||
|
||||
module t;
|
||||
|
||||
reg [5:0] binary_nostart [2:15];
|
||||
reg [5:0] binary_start [0:15];
|
||||
reg [175:0] hex [0:15];
|
||||
|
||||
integer i;
|
||||
|
||||
initial begin
|
||||
|
||||
begin
|
||||
$readmemb("t/t_sys_readmem_b.mem", binary_nostart);
|
||||
`ifdef TEST_VERBOSE
|
||||
for (i=0; i<16; i=i+1) $write(" @%x = %x\n", i, binary_nostart[i]);
|
||||
`endif
|
||||
if (binary_nostart['h2] != 6'h02) $stop;
|
||||
if (binary_nostart['h3] != 6'h03) $stop;
|
||||
if (binary_nostart['h4] != 6'h04) $stop;
|
||||
if (binary_nostart['h5] != 6'h05) $stop;
|
||||
if (binary_nostart['h6] != 6'h06) $stop;
|
||||
if (binary_nostart['h7] != 6'h07) $stop;
|
||||
if (binary_nostart['h8] != 6'h10) $stop;
|
||||
if (binary_nostart['hc] != 6'h14) $stop;
|
||||
if (binary_nostart['hd] != 6'h15) $stop;
|
||||
end
|
||||
|
||||
begin
|
||||
$readmemb("t/t_sys_readmem_b_8.mem", binary_start, 4, 4+7);
|
||||
`ifdef TEST_VERBOSE
|
||||
for (i=0; i<16; i=i+1) $write(" @%x = %x\n", i, binary_start[i]);
|
||||
`endif
|
||||
if (binary_start['h04] != 6'h10) $stop;
|
||||
if (binary_start['h05] != 6'h11) $stop;
|
||||
if (binary_start['h06] != 6'h12) $stop;
|
||||
if (binary_start['h07] != 6'h13) $stop;
|
||||
if (binary_start['h08] != 6'h14) $stop;
|
||||
if (binary_start['h09] != 6'h15) $stop;
|
||||
if (binary_start['h0a] != 6'h16) $stop;
|
||||
if (binary_start['h0b] != 6'h17) $stop;
|
||||
end
|
||||
|
||||
begin
|
||||
$readmemh("t/t_sys_readmem_h.mem", hex, 0);
|
||||
`ifdef TEST_VERBOSE
|
||||
for (i=0; i<16; i=i+1) $write(" @%x = %x\n", i, hex[i]);
|
||||
`endif
|
||||
if (hex['h04] != 176'h400437654321276543211765432107654321abcdef10) $stop;
|
||||
if (hex['h0a] != 176'h400a37654321276543211765432107654321abcdef11) $stop;
|
||||
if (hex['h0b] != 176'h400b37654321276543211765432107654321abcdef12) $stop;
|
||||
if (hex['h0c] != 176'h400c37654321276543211765432107654321abcdef13) $stop;
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// $Id$
|
||||
// DESCRIPTION: Verilator: Verilog Test data file
|
||||
//
|
||||
// Copyright 2006 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// General Public License or the Perl Artistic License.
|
||||
|
||||
010
|
||||
0_1_1
|
||||
100/*Space*/101// Space
|
||||
110 111
|
||||
|
||||
@00_0_8
|
||||
10000
|
||||
|
||||
@c
|
||||
10100
|
||||
10101
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// $Id$
|
||||
// DESCRIPTION: Verilator: Verilog Test data file
|
||||
//
|
||||
// Copyright 2006 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// General Public License or the Perl Artistic License.
|
||||
|
||||
10000
|
||||
10001
|
||||
10010
|
||||
10011
|
||||
/*
|
||||
multi line
|
||||
ignored
|
||||
*/
|
||||
10100
|
||||
10101
|
||||
10110
|
||||
10111
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// $Id$
|
||||
// DESCRIPTION: Verilator: Verilog Test data file
|
||||
//
|
||||
// Copyright 2006 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// General Public License or the Perl Artistic License.
|
||||
|
||||
@121212
|
||||
10
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
|
||||
# $Id$
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# General Public License or the Perl Artistic License.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
fails=>$Last_Self->{v3},
|
||||
expect=>
|
||||
'%Error: t/t_sys_readmem_bad_addr.mem:\d+: \$readmem file address beyond bounds of array',
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
// $Id$
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2003 by Wilson Snyder.
|
||||
|
||||
module t;
|
||||
reg [175:0] hex [0:15];
|
||||
|
||||
initial begin
|
||||
$readmemh("t/t_sys_readmem_bad_addr.mem", hex);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// $Id$
|
||||
// DESCRIPTION: Verilator: Verilog Test data file
|
||||
//
|
||||
// Copyright 2006 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// General Public License or the Perl Artistic License.
|
||||
|
||||
a0
|
||||
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
|
||||
# $Id$
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# General Public License or the Perl Artistic License.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
fails=>$Last_Self->{v3},
|
||||
expect=>
|
||||
'%Error: t/t_sys_readmem_bad_digit.mem:\d+: \$readmemb \(binary\) file contains hex characters',
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// $Id$
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2003 by Wilson Snyder.
|
||||
|
||||
module t;
|
||||
|
||||
reg [175:0] hex [0:15];
|
||||
|
||||
initial begin
|
||||
$readmemb("t/t_sys_readmem_bad_digit.mem", hex);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// $Id$
|
||||
// DESCRIPTION: Verilator: Verilog Test data file
|
||||
//
|
||||
// Copyright 2006 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// General Public License or the Perl Artistic License.
|
||||
|
||||
00
|
||||
01
|
||||
10
|
||||
// Missing additional data
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
|
||||
# $Id$
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# General Public License or the Perl Artistic License.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
fails=>$Last_Self->{v3},
|
||||
expect=>
|
||||
'%Error: t/t_sys_readmem_bad_end.mem:\d+: \$readmem file ended before specified ending-address',
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// $Id$
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2003 by Wilson Snyder.
|
||||
|
||||
module t;
|
||||
|
||||
reg [175:0] hex [0:15];
|
||||
|
||||
integer i;
|
||||
|
||||
initial begin
|
||||
$readmemh("t/t_sys_readmem_bad_end.mem", hex, 0, 15);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
|
||||
# $Id$
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# General Public License or the Perl Artistic License.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
fails=>$Last_Self->{v3},
|
||||
expect=>
|
||||
'%Error: t/t_sys_readmem_bad_NOTFOUND.mem:\d+: \$readmem file not found',
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
// $Id$
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2003 by Wilson Snyder.
|
||||
|
||||
module t;
|
||||
|
||||
reg [175:0] hex [0:15];
|
||||
|
||||
initial begin
|
||||
$readmemh("t/t_sys_readmem_bad_NOTFOUND.mem", hex);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// $Id$
|
||||
// DESCRIPTION: Verilator: Verilog Test data file
|
||||
//
|
||||
// Copyright 2006 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// General Public License or the Perl Artistic License.
|
||||
|
||||
@4
|
||||
4004_37654321_27654321_17654321_07654321_abcdef10
|
||||
@a
|
||||
400a_37654321_27654321_17654321_07654321_abcdef11
|
||||
400b_37654321_27654321_17654321_07654321_abcdef12
|
||||
400c_37654321_27654321_17654321_07654321_abcdef13
|
||||
Loading…
Reference in New Issue