Support
This commit is contained in:
parent
4cf2e4024f
commit
fc48008c1c
2
Changes
2
Changes
|
|
@ -10,6 +10,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
||||||
|
|
||||||
*** Support assert properties, bug785, bug1290. [John Coiner, et al]
|
*** Support assert properties, bug785, bug1290. [John Coiner, et al]
|
||||||
|
|
||||||
|
*** Support $writememh. [John Coiner]
|
||||||
|
|
||||||
*** Add --no-debug-leak to reduce memory use under debug. [John Coiner]
|
*** Add --no-debug-leak to reduce memory use under debug. [John Coiner]
|
||||||
|
|
||||||
**** On convergence errors, show activity. [John Coiner]
|
**** On convergence errors, show activity. [John Coiner]
|
||||||
|
|
|
||||||
|
|
@ -1205,6 +1205,130 @@ IData VL_SSCANF_INX(int, const std::string& ld, const char* formatp, ...) VL_MT_
|
||||||
return got;
|
return got;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VL_WRITEMEM_Q(bool hex, int width, int depth, int array_lsb, int,
|
||||||
|
QData ofilename, const void* memp, IData start,
|
||||||
|
IData end) VL_MT_SAFE {
|
||||||
|
WData fnw[2]; VL_SET_WQ(fnw, ofilename);
|
||||||
|
return VL_WRITEMEM_W(hex, width,depth,array_lsb,2,fnw,memp,start,end);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VL_WRITEMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||||
|
WDataInP ofilenamep, const void* memp, IData start,
|
||||||
|
IData end) VL_MT_SAFE {
|
||||||
|
char ofilenamez[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1];
|
||||||
|
_VL_VINT_TO_STRING(fnwords*VL_WORDSIZE, ofilenamez, ofilenamep);
|
||||||
|
std::string ofilenames(ofilenamez);
|
||||||
|
return VL_WRITEMEM_N(hex, width,depth,array_lsb,ofilenames,memp,start,end);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* memhFormat(int nBits) {
|
||||||
|
assert((nBits >= 1) && (nBits <= 32));
|
||||||
|
|
||||||
|
static char buf[32];
|
||||||
|
switch ((nBits - 1) / 4) {
|
||||||
|
case 0: VL_SNPRINTF(buf, 32, "%%01x"); break;
|
||||||
|
case 1: VL_SNPRINTF(buf, 32, "%%02x"); break;
|
||||||
|
case 2: VL_SNPRINTF(buf, 32, "%%03x"); break;
|
||||||
|
case 3: VL_SNPRINTF(buf, 32, "%%04x"); break;
|
||||||
|
case 4: VL_SNPRINTF(buf, 32, "%%05x"); break;
|
||||||
|
case 5: VL_SNPRINTF(buf, 32, "%%06x"); break;
|
||||||
|
case 6: VL_SNPRINTF(buf, 32, "%%07x"); break;
|
||||||
|
case 7: VL_SNPRINTF(buf, 32, "%%08x"); break;
|
||||||
|
default: assert(false); break;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VL_WRITEMEM_N(
|
||||||
|
bool hex, // Hex format, else binary
|
||||||
|
int width, // Width of each array row
|
||||||
|
int depth, // Number of rows
|
||||||
|
int array_lsb, // Index of first row. Valid row addresses
|
||||||
|
// // range from array_lsb up to (array_lsb + depth - 1)
|
||||||
|
const std::string& ofilenamep, // Output file name
|
||||||
|
const void* memp, // Array state
|
||||||
|
IData start, // First array row address to write
|
||||||
|
IData end // Last address to write
|
||||||
|
) VL_MT_SAFE {
|
||||||
|
if (VL_UNLIKELY(!hex)) {
|
||||||
|
VL_FATAL_MT(ofilenamep.c_str(), 0, "",
|
||||||
|
"VL_WRITEMEM_N only supports hex format for now, sorry!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FILE* fp = fopen(ofilenamep.c_str(), "w");
|
||||||
|
if (VL_UNLIKELY(!fp)) {
|
||||||
|
VL_FATAL_MT(ofilenamep.c_str(), 0, "", "$writemem file not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int row_addr = start; row_addr <= end; ++row_addr) {
|
||||||
|
if ((row_addr < array_lsb)
|
||||||
|
|| (row_addr > array_lsb + depth - 1)) {
|
||||||
|
vluint32_t endmax = ~0;
|
||||||
|
if (end != endmax) {
|
||||||
|
VL_FATAL_MT(ofilenamep.c_str(), 0, "",
|
||||||
|
"$writemem specified address out-of-bounds");
|
||||||
|
}
|
||||||
|
// else, it's not an error to overflow due to end == endmax,
|
||||||
|
// just return cleanly.
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the offset into the memp array.
|
||||||
|
int row_offset = row_addr - array_lsb;
|
||||||
|
|
||||||
|
if (width <= 8) {
|
||||||
|
const CData* datap
|
||||||
|
= &(reinterpret_cast<const CData*>(memp))[row_offset];
|
||||||
|
fprintf(fp, memhFormat(width), VL_MASK_I(width) & *datap);
|
||||||
|
fprintf(fp, "\n");
|
||||||
|
} else if (width <= 16) {
|
||||||
|
const SData* datap
|
||||||
|
= &(reinterpret_cast<const SData*>(memp))[row_offset];
|
||||||
|
fprintf(fp, memhFormat(width), VL_MASK_I(width) & *datap);
|
||||||
|
fprintf(fp, "\n");
|
||||||
|
} else if (width <= 32) {
|
||||||
|
const IData* datap
|
||||||
|
= &(reinterpret_cast<const IData*>(memp))[row_offset];
|
||||||
|
fprintf(fp, memhFormat(width), VL_MASK_I(width) & *datap);
|
||||||
|
fprintf(fp, "\n");
|
||||||
|
} else if (width <= 64) {
|
||||||
|
const QData* datap
|
||||||
|
= &(reinterpret_cast<const QData*>(memp))[row_offset];
|
||||||
|
vluint64_t value = VL_MASK_Q(width) & *datap;
|
||||||
|
vluint32_t lo = value & 0xffffffff;
|
||||||
|
vluint32_t hi = value >> 32;
|
||||||
|
fprintf(fp, memhFormat(width - 32), hi);
|
||||||
|
fprintf(fp, "%08x\n", lo);
|
||||||
|
} else {
|
||||||
|
WDataInP memDatap = reinterpret_cast<WDataInP>(memp);
|
||||||
|
WDataInP datap = &memDatap[row_offset * VL_WORDS_I(width)];
|
||||||
|
// output as a sequence of VL_WORDSIZE'd words
|
||||||
|
// from MSB to LSB. Mask off the MSB word which could
|
||||||
|
// contain junk above the top of valid data.
|
||||||
|
int word_idx = ((width - 1) / VL_WORDSIZE);
|
||||||
|
bool first = true;
|
||||||
|
while (word_idx >= 0) {
|
||||||
|
IData data = datap[word_idx];
|
||||||
|
if (first) {
|
||||||
|
data &= VL_MASK_I(width);
|
||||||
|
int top_word_nbits = ((width - 1) & 0x1f) + 1;
|
||||||
|
fprintf(fp, memhFormat(top_word_nbits), data);
|
||||||
|
} else {
|
||||||
|
fprintf(fp, "%08x", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
word_idx--;
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
fprintf(fp, "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
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) VL_MT_SAFE {
|
QData ofilename, void* memp, IData start, IData end) VL_MT_SAFE {
|
||||||
WData fnw[2]; VL_SET_WQ(fnw, ofilename);
|
WData fnw[2]; VL_SET_WQ(fnw, ofilename);
|
||||||
|
|
@ -1216,12 +1340,20 @@ void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||||
char ofilenamez[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1];
|
char ofilenamez[VL_TO_STRING_MAX_WORDS*VL_WORDSIZE+1];
|
||||||
_VL_VINT_TO_STRING(fnwords*VL_WORDSIZE, ofilenamez, ofilenamep);
|
_VL_VINT_TO_STRING(fnwords*VL_WORDSIZE, ofilenamez, ofilenamep);
|
||||||
std::string ofilenames(ofilenamez);
|
std::string ofilenames(ofilenamez);
|
||||||
return VL_READMEM_N(hex,width,depth,array_lsb,fnwords,ofilenames,memp,start,end);
|
return VL_READMEM_N(hex,width,depth,array_lsb,ofilenames,memp,start,end);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VL_READMEM_N(bool hex, int width, int depth, int array_lsb, int fnwords,
|
void VL_READMEM_N(
|
||||||
const std::string& ofilenamep, void* memp, IData start, IData end) VL_MT_SAFE {
|
bool hex, // Hex format, else binary
|
||||||
if (fnwords) {}
|
int width, // Width of each array row
|
||||||
|
int depth, // Number of rows
|
||||||
|
int array_lsb, // Index of first row. Valid row addresses
|
||||||
|
// // range from array_lsb up to (array_lsb + depth - 1)
|
||||||
|
const std::string& ofilenamep, // Input file name
|
||||||
|
void* memp, // Array state
|
||||||
|
IData start, // First array row address to read
|
||||||
|
IData end // Last row address to read
|
||||||
|
) VL_MT_SAFE {
|
||||||
FILE* fp = fopen(ofilenamep.c_str(), "r");
|
FILE* fp = fopen(ofilenamep.c_str(), "r");
|
||||||
if (VL_UNLIKELY(!fp)) {
|
if (VL_UNLIKELY(!fp)) {
|
||||||
// We don't report the Verilog source filename as it slow to have to pass it down
|
// We don't report the Verilog source filename as it slow to have to pass it down
|
||||||
|
|
|
||||||
|
|
@ -549,6 +549,14 @@ inline void VL_READMEM_I(bool hex, int width, int depth, int array_lsb, int fnwo
|
||||||
IData ofilename, void* memp, IData start, IData end) VL_MT_SAFE {
|
IData ofilename, void* memp, IData start, IData end) VL_MT_SAFE {
|
||||||
VL_READMEM_Q(hex, width,depth,array_lsb,fnwords, ofilename,memp,start,end); }
|
VL_READMEM_Q(hex, width,depth,array_lsb,fnwords, ofilename,memp,start,end); }
|
||||||
|
|
||||||
|
extern void VL_WRITEMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||||
|
WDataInP ofilename, const void* memp, IData start, IData end);
|
||||||
|
extern void VL_WRITEMEM_Q(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||||
|
QData ofilename, const void* memp, IData start, IData end);
|
||||||
|
inline void VL_WRITEMEM_I(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||||
|
IData ofilename, const void* memp, IData start, IData end) VL_MT_SAFE {
|
||||||
|
VL_WRITEMEM_Q(hex, width,depth,array_lsb,fnwords, ofilename,memp,start,end); }
|
||||||
|
|
||||||
extern void VL_WRITEF(const char* formatp, ...);
|
extern void VL_WRITEF(const char* formatp, ...);
|
||||||
extern void VL_FWRITEF(IData fpi, const char* formatp, ...);
|
extern void VL_FWRITEF(IData fpi, const char* formatp, ...);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,12 @@ inline std::string VL_REPLICATEN_NNI(int obits,int lbits,int rbits,
|
||||||
inline IData VL_LEN_IN(const std::string& ld) { return ld.length(); }
|
inline IData VL_LEN_IN(const std::string& ld) { return ld.length(); }
|
||||||
|
|
||||||
extern IData VL_FOPEN_NI(const std::string& filename, IData mode) VL_MT_SAFE;
|
extern IData VL_FOPEN_NI(const std::string& filename, IData mode) VL_MT_SAFE;
|
||||||
extern void VL_READMEM_N(bool hex, int width, int depth, int array_lsb, int fnwords,
|
extern void VL_READMEM_N(bool hex, int width, int depth, int array_lsb,
|
||||||
const std::string& ofilename, void* memp, IData start, IData end) VL_MT_SAFE;
|
const std::string& ofilename,
|
||||||
|
void* memp, IData start, IData end) VL_MT_SAFE;
|
||||||
|
extern void VL_WRITEMEM_N(bool hex, int width, int depth, int array_lsb,
|
||||||
|
const std::string& ofilename,
|
||||||
|
const void* memp, IData start, IData end) VL_MT_SAFE;
|
||||||
extern IData VL_SSCANF_INX(int lbits, const std::string& ld, const char* formatp, ...) VL_MT_SAFE;
|
extern IData VL_SSCANF_INX(int lbits, const std::string& ld, const char* formatp, ...) VL_MT_SAFE;
|
||||||
extern void VL_SFORMAT_X(int obits_ignored, std::string& output, const char* formatp, ...) VL_MT_SAFE;
|
extern void VL_SFORMAT_X(int obits_ignored, std::string& output, const char* formatp, ...) VL_MT_SAFE;
|
||||||
extern std::string VL_SFORMATF_NX(const char* formatp, ...) VL_MT_SAFE;
|
extern std::string VL_SFORMATF_NX(const char* formatp, ...) VL_MT_SAFE;
|
||||||
|
|
|
||||||
|
|
@ -2773,17 +2773,16 @@ public:
|
||||||
void fromp(AstNode* nodep) { setOp2p(nodep); }
|
void fromp(AstNode* nodep) { setOp2p(nodep); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class AstReadMem : public AstNodeStmt {
|
class AstNodeReadWriteMem : public AstNodeStmt {
|
||||||
private:
|
private:
|
||||||
bool m_isHex; // readmemh, not readmemb
|
bool m_isHex; // readmemh, not readmemb
|
||||||
public:
|
public:
|
||||||
AstReadMem(FileLine* fileline, bool hex,
|
AstNodeReadWriteMem(FileLine* fileline, bool hex,
|
||||||
AstNode* filenamep, AstNode* memp, AstNode* lsbp, AstNode* msbp)
|
AstNode* filenamep, AstNode* memp,
|
||||||
|
AstNode* lsbp, AstNode* msbp)
|
||||||
: AstNodeStmt (fileline), m_isHex(hex) {
|
: AstNodeStmt (fileline), m_isHex(hex) {
|
||||||
setOp1p(filenamep); setOp2p(memp); setNOp3p(lsbp); setNOp4p(msbp);
|
setOp1p(filenamep); setOp2p(memp); setNOp3p(lsbp); setNOp4p(msbp);
|
||||||
}
|
}
|
||||||
ASTNODE_NODE_FUNCS(ReadMem)
|
|
||||||
virtual string verilogKwd() const { return (isHex()?"$readmemh":"$readmemb"); }
|
|
||||||
virtual bool isGateOptimizable() const { return false; }
|
virtual bool isGateOptimizable() const { return false; }
|
||||||
virtual bool isPredictOptimizable() const { return false; }
|
virtual bool isPredictOptimizable() const { return false; }
|
||||||
virtual bool isPure() const { return false; }
|
virtual bool isPure() const { return false; }
|
||||||
|
|
@ -2791,12 +2790,35 @@ public:
|
||||||
virtual bool isUnlikely() const { return true; }
|
virtual bool isUnlikely() const { return true; }
|
||||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||||
virtual bool same(const AstNode* samep) const {
|
virtual bool same(const AstNode* samep) const {
|
||||||
return isHex()==static_cast<const AstReadMem*>(samep)->isHex(); }
|
return isHex()==static_cast<const AstNodeReadWriteMem*>(samep)->isHex();
|
||||||
|
}
|
||||||
bool isHex() const { return m_isHex; }
|
bool isHex() const { return m_isHex; }
|
||||||
AstNode* filenamep() const { return op1p(); }
|
AstNode* filenamep() const { return op1p(); }
|
||||||
AstNode* memp() const { return op2p(); }
|
AstNode* memp() const { return op2p(); }
|
||||||
AstNode* lsbp() const { return op3p(); }
|
AstNode* lsbp() const { return op3p(); }
|
||||||
AstNode* msbp() const { return op4p(); }
|
AstNode* msbp() const { return op4p(); }
|
||||||
|
virtual const char* cFuncPrefixp() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AstReadMem : public AstNodeReadWriteMem {
|
||||||
|
public:
|
||||||
|
AstReadMem(FileLine* fileline, bool hex,
|
||||||
|
AstNode* filenamep, AstNode* memp, AstNode* lsbp, AstNode* msbp)
|
||||||
|
: AstNodeReadWriteMem(fileline, hex, filenamep, memp, lsbp, msbp)
|
||||||
|
{ }
|
||||||
|
ASTNODE_NODE_FUNCS(ReadMem);
|
||||||
|
virtual string verilogKwd() const { return (isHex()?"$readmemh":"$readmemb"); }
|
||||||
|
virtual const char* cFuncPrefixp() const { return "VL_READMEM_"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class AstWriteMem : public AstNodeReadWriteMem {
|
||||||
|
public:
|
||||||
|
AstWriteMem(FileLine* fileline,
|
||||||
|
AstNode* filenamep, AstNode* memp, AstNode* lsbp, AstNode* msbp)
|
||||||
|
: AstNodeReadWriteMem(fileline, true, filenamep, memp, lsbp, msbp) { }
|
||||||
|
ASTNODE_NODE_FUNCS(WriteMem)
|
||||||
|
virtual string verilogKwd() const { return (isHex()?"$writememh":"$writememb"); }
|
||||||
|
virtual const char* cFuncPrefixp() const { return "VL_WRITEMEM_"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class AstSystemT : public AstNodeStmt {
|
class AstSystemT : public AstNodeStmt {
|
||||||
|
|
|
||||||
|
|
@ -322,8 +322,8 @@ public:
|
||||||
nodep->modep()->iterateAndNext(*this);
|
nodep->modep()->iterateAndNext(*this);
|
||||||
puts(");\n");
|
puts(");\n");
|
||||||
}
|
}
|
||||||
virtual void visit(AstReadMem* nodep) {
|
virtual void visit(AstNodeReadWriteMem* nodep) {
|
||||||
puts("VL_READMEM_");
|
puts(nodep->cFuncPrefixp());
|
||||||
emitIQW(nodep->filenamep());
|
emitIQW(nodep->filenamep());
|
||||||
puts(" ("); // We take a void* rather than emitIQW(nodep->memp());
|
puts(" ("); // We take a void* rather than emitIQW(nodep->memp());
|
||||||
puts(nodep->isHex()?"true":"false");
|
puts(nodep->isHex()?"true":"false");
|
||||||
|
|
@ -333,21 +333,26 @@ public:
|
||||||
uint32_t array_lsb = 0;
|
uint32_t array_lsb = 0;
|
||||||
{
|
{
|
||||||
AstVarRef* varrefp = nodep->memp()->castVarRef();
|
AstVarRef* varrefp = nodep->memp()->castVarRef();
|
||||||
if (!varrefp) { nodep->v3error("Readmem loading non-variable"); }
|
if (!varrefp) {
|
||||||
|
nodep->v3error(nodep->verilogKwd() << " loading non-variable");
|
||||||
|
}
|
||||||
else if (AstUnpackArrayDType* adtypep = varrefp->varp()->dtypeSkipRefp()->castUnpackArrayDType()) {
|
else if (AstUnpackArrayDType* adtypep = varrefp->varp()->dtypeSkipRefp()->castUnpackArrayDType()) {
|
||||||
puts(cvtToStr(varrefp->varp()->dtypep()->arrayUnpackedElements()));
|
puts(cvtToStr(varrefp->varp()->dtypep()->arrayUnpackedElements()));
|
||||||
array_lsb = adtypep->lsb();
|
array_lsb = adtypep->lsb();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
nodep->v3error("Readmem loading other than unpacked-array variable");
|
nodep->v3error(nodep->verilogKwd()
|
||||||
|
<< " loading other than unpacked-array variable");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
putbs(", ");
|
putbs(", ");
|
||||||
puts(cvtToStr(array_lsb));
|
puts(cvtToStr(array_lsb));
|
||||||
putbs(",");
|
putbs(",");
|
||||||
|
if (!nodep->filenamep()->dtypep()->isString()) {
|
||||||
puts(cvtToStr(nodep->filenamep()->widthWords()));
|
puts(cvtToStr(nodep->filenamep()->widthWords()));
|
||||||
checkMaxWords(nodep->filenamep());
|
checkMaxWords(nodep->filenamep());
|
||||||
putbs(", ");
|
putbs(", ");
|
||||||
|
}
|
||||||
nodep->filenamep()->iterateAndNext(*this);
|
nodep->filenamep()->iterateAndNext(*this);
|
||||||
putbs(", ");
|
putbs(", ");
|
||||||
nodep->memp()->iterateAndNext(*this);
|
nodep->memp()->iterateAndNext(*this);
|
||||||
|
|
|
||||||
|
|
@ -268,7 +268,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||||
if (nodep->stmtsp()) nodep->stmtsp()->iterateAndNext(*this);
|
if (nodep->stmtsp()) nodep->stmtsp()->iterateAndNext(*this);
|
||||||
puts("end\n");
|
puts("end\n");
|
||||||
}
|
}
|
||||||
virtual void visit(AstReadMem* nodep) {
|
virtual void visit(AstNodeReadWriteMem* nodep) {
|
||||||
putfs(nodep,nodep->verilogKwd());
|
putfs(nodep,nodep->verilogKwd());
|
||||||
putbs(" (");
|
putbs(" (");
|
||||||
if (nodep->filenamep()) nodep->filenamep()->iterateAndNext(*this);
|
if (nodep->filenamep()) nodep->filenamep()->iterateAndNext(*this);
|
||||||
|
|
|
||||||
|
|
@ -2204,12 +2204,13 @@ private:
|
||||||
assertAtStatement(nodep);
|
assertAtStatement(nodep);
|
||||||
userIterateAndNext(nodep->lhsp(), WidthVP(SELF,BOTH).p());
|
userIterateAndNext(nodep->lhsp(), WidthVP(SELF,BOTH).p());
|
||||||
}
|
}
|
||||||
virtual void visit(AstReadMem* nodep) {
|
virtual void visit(AstNodeReadWriteMem* nodep) {
|
||||||
assertAtStatement(nodep);
|
assertAtStatement(nodep);
|
||||||
userIterateAndNext(nodep->filenamep(), WidthVP(SELF,BOTH).p());
|
userIterateAndNext(nodep->filenamep(), WidthVP(SELF,BOTH).p());
|
||||||
userIterateAndNext(nodep->memp(), WidthVP(SELF,BOTH).p());
|
userIterateAndNext(nodep->memp(), WidthVP(SELF,BOTH).p());
|
||||||
if (!nodep->memp()->dtypep()->skipRefp()->castUnpackArrayDType()) {
|
if (!nodep->memp()->dtypep()->skipRefp()->castUnpackArrayDType()) {
|
||||||
nodep->memp()->v3error("Unsupported: $readmem into other than unpacked array");
|
nodep->memp()->v3error("Unsupported: " << nodep->verilogKwd()
|
||||||
|
<< " into other than unpacked array");
|
||||||
}
|
}
|
||||||
userIterateAndNext(nodep->lsbp(), WidthVP(SELF,BOTH).p());
|
userIterateAndNext(nodep->lsbp(), WidthVP(SELF,BOTH).p());
|
||||||
userIterateAndNext(nodep->msbp(), WidthVP(SELF,BOTH).p());
|
userIterateAndNext(nodep->msbp(), WidthVP(SELF,BOTH).p());
|
||||||
|
|
|
||||||
|
|
@ -269,6 +269,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||||
"$value$plusargs" { FL; return yD_VALUEPLUSARGS; }
|
"$value$plusargs" { FL; return yD_VALUEPLUSARGS; }
|
||||||
"$width" { FL; return yaTIMINGSPEC; }
|
"$width" { FL; return yaTIMINGSPEC; }
|
||||||
"$write" { FL; return yD_WRITE; }
|
"$write" { FL; return yD_WRITE; }
|
||||||
|
"$writememh" { FL; return yD_WRITEMEMH; }
|
||||||
/* Keywords */
|
/* Keywords */
|
||||||
"always" { FL; return yALWAYS; }
|
"always" { FL; return yALWAYS; }
|
||||||
"and" { FL; return yAND; }
|
"and" { FL; return yAND; }
|
||||||
|
|
|
||||||
|
|
@ -515,6 +515,7 @@ class AstSenTree;
|
||||||
%token<fl> yD_VALUEPLUSARGS "$value$plusargs"
|
%token<fl> yD_VALUEPLUSARGS "$value$plusargs"
|
||||||
%token<fl> yD_WARNING "$warning"
|
%token<fl> yD_WARNING "$warning"
|
||||||
%token<fl> yD_WRITE "$write"
|
%token<fl> yD_WRITE "$write"
|
||||||
|
%token<fl> yD_WRITEMEMH "$writememh"
|
||||||
|
|
||||||
%token<fl> yVL_CLOCK "/*verilator sc_clock*/"
|
%token<fl> yVL_CLOCK "/*verilator sc_clock*/"
|
||||||
%token<fl> yVL_CLOCKER "/*verilator clocker*/"
|
%token<fl> yVL_CLOCKER "/*verilator clocker*/"
|
||||||
|
|
@ -2700,6 +2701,10 @@ system_t_call<nodep>: // IEEE: system_tf_call (as task)
|
||||||
| yD_READMEMH '(' expr ',' idClassSel ',' expr ')' { $$ = new AstReadMem($1,true, $3,$5,$7,NULL); }
|
| yD_READMEMH '(' expr ',' idClassSel ',' expr ')' { $$ = new AstReadMem($1,true, $3,$5,$7,NULL); }
|
||||||
| yD_READMEMH '(' expr ',' idClassSel ',' expr ',' expr ')' { $$ = new AstReadMem($1,true, $3,$5,$7,$9); }
|
| yD_READMEMH '(' expr ',' idClassSel ',' expr ',' expr ')' { $$ = new AstReadMem($1,true, $3,$5,$7,$9); }
|
||||||
//
|
//
|
||||||
|
| yD_WRITEMEMH '(' expr ',' idClassSel ')' { $$ = new AstWriteMem($1,$3,$5,NULL,NULL); }
|
||||||
|
| yD_WRITEMEMH '(' expr ',' idClassSel ',' expr ')' { $$ = new AstWriteMem($1,$3,$5,$7,NULL); }
|
||||||
|
| yD_WRITEMEMH '(' expr ',' idClassSel ',' expr ',' expr ')' { $$ = new AstWriteMem($1,$3,$5,$7,$9); }
|
||||||
|
//
|
||||||
// Any system function as a task
|
// Any system function as a task
|
||||||
| system_f_call_or_t { $$ = new AstSysFuncAsTask($<fl>1, $1); }
|
| system_f_call_or_t { $$ = new AstSysFuncAsTask($<fl>1, $1); }
|
||||||
;
|
;
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,59 @@ module t;
|
||||||
reg [5:0] binary_nostart [2:15];
|
reg [5:0] binary_nostart [2:15];
|
||||||
reg [5:0] binary_start [0:15];
|
reg [5:0] binary_start [0:15];
|
||||||
reg [175:0] hex [0:15];
|
reg [175:0] hex [0:15];
|
||||||
|
reg [(32*6)-1:0] hex_align [0:15];
|
||||||
|
string fns;
|
||||||
|
|
||||||
|
`ifdef WRITEMEM_READ_BACK
|
||||||
|
reg [5:0] binary_string_tmp [2:15];
|
||||||
|
reg [5:0] binary_nostart_tmp [2:15];
|
||||||
|
reg [5:0] binary_start_tmp [0:15];
|
||||||
|
reg [175:0] hex_tmp [0:15];
|
||||||
|
reg [(32*6)-1:0] hex_align_tmp [0:15];
|
||||||
|
string fns_tmp;
|
||||||
|
`endif
|
||||||
// verilator lint_on LITENDIAN
|
// verilator lint_on LITENDIAN
|
||||||
|
|
||||||
integer i;
|
integer i;
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
|
begin
|
||||||
|
// Initialize memories to zero,
|
||||||
|
// avoid differences between 2-state and 4-state.
|
||||||
|
for (i=0; i<16; i=i+1) begin
|
||||||
|
binary_start[i] = 6'h0;
|
||||||
|
hex[i] = 176'h0;
|
||||||
|
hex_align[i] = {32*6{1'b0}};
|
||||||
|
`ifdef WRITEMEM_READ_BACK
|
||||||
|
binary_start_tmp[i] = 6'h0;
|
||||||
|
hex_tmp[i] = 176'h0;
|
||||||
|
hex_align_tmp[i] = {32*6{1'b0}};
|
||||||
|
`endif
|
||||||
|
end
|
||||||
|
for (i=2; i<16; i=i+1) begin
|
||||||
|
binary_string[i] = 6'h0;
|
||||||
|
binary_nostart[i] = 6'h0;
|
||||||
|
`ifdef WRITEMEM_READ_BACK
|
||||||
|
binary_string_tmp[i] = 6'h0;
|
||||||
|
binary_nostart_tmp[i] = 6'h0;
|
||||||
|
`endif
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
`ifdef WRITEMEM_READ_BACK
|
||||||
|
$readmemb("t/t_sys_readmem_b.mem", binary_nostart_tmp);
|
||||||
|
// Do a round-trip $writememh and $readmemh cycle.
|
||||||
|
// This covers $writememh and ensures we can read our
|
||||||
|
// own memh output file.
|
||||||
|
`ifdef TEST_VERBOSE
|
||||||
|
$display("-Writing %s", `OUT_TMP1);
|
||||||
|
`endif
|
||||||
|
$writememh(`OUT_TMP1, binary_nostart_tmp);
|
||||||
|
$readmemh(`OUT_TMP1, binary_nostart);
|
||||||
|
`else
|
||||||
$readmemb("t/t_sys_readmem_b.mem", binary_nostart);
|
$readmemb("t/t_sys_readmem_b.mem", binary_nostart);
|
||||||
|
`endif
|
||||||
`ifdef TEST_VERBOSE
|
`ifdef TEST_VERBOSE
|
||||||
for (i=0; i<16; i=i+1) $write(" @%x = %x\n", i, binary_nostart[i]);
|
for (i=0; i<16; i=i+1) $write(" @%x = %x\n", i, binary_nostart[i]);
|
||||||
`endif
|
`endif
|
||||||
|
|
@ -33,7 +78,16 @@ module t;
|
||||||
end
|
end
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
`ifdef WRITEMEM_READ_BACK
|
||||||
|
$readmemb("t/t_sys_readmem_b_8.mem", binary_start_tmp, 4, 4+7);
|
||||||
|
`ifdef TEST_VERBOSE
|
||||||
|
$display("-Writing %s", `OUT_TMP2);
|
||||||
|
`endif
|
||||||
|
$writememh(`OUT_TMP2, binary_start_tmp, 4, 4+7);
|
||||||
|
$readmemh(`OUT_TMP2, binary_start, 4, 4+7);
|
||||||
|
`else
|
||||||
$readmemb("t/t_sys_readmem_b_8.mem", binary_start, 4, 4+7);
|
$readmemb("t/t_sys_readmem_b_8.mem", binary_start, 4, 4+7);
|
||||||
|
`endif
|
||||||
`ifdef TEST_VERBOSE
|
`ifdef TEST_VERBOSE
|
||||||
for (i=0; i<16; i=i+1) $write(" @%x = %x\n", i, binary_start[i]);
|
for (i=0; i<16; i=i+1) $write(" @%x = %x\n", i, binary_start[i]);
|
||||||
`endif
|
`endif
|
||||||
|
|
@ -48,7 +102,18 @@ module t;
|
||||||
end
|
end
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
// The 'hex' array is a non-exact multiple of word size
|
||||||
|
// (possible corner case)
|
||||||
|
`ifdef WRITEMEM_READ_BACK
|
||||||
|
$readmemh("t/t_sys_readmem_h.mem", hex_tmp, 0);
|
||||||
|
`ifdef TEST_VERBOSE
|
||||||
|
$display("-Writing %s", `OUT_TMP3);
|
||||||
|
`endif
|
||||||
|
$writememh(`OUT_TMP3, hex_tmp, 0);
|
||||||
|
$readmemh(`OUT_TMP3, hex, 0);
|
||||||
|
`else
|
||||||
$readmemh("t/t_sys_readmem_h.mem", hex, 0);
|
$readmemh("t/t_sys_readmem_h.mem", hex, 0);
|
||||||
|
`endif
|
||||||
`ifdef TEST_VERBOSE
|
`ifdef TEST_VERBOSE
|
||||||
for (i=0; i<16; i=i+1) $write(" @%x = %x\n", i, hex[i]);
|
for (i=0; i<16; i=i+1) $write(" @%x = %x\n", i, hex[i]);
|
||||||
`endif
|
`endif
|
||||||
|
|
@ -59,8 +124,40 @@ module t;
|
||||||
end
|
end
|
||||||
|
|
||||||
begin
|
begin
|
||||||
string fns = "t/t_sys_readmem_b.mem";
|
// The 'hex align' array is similar to 'hex', but it is an
|
||||||
|
// exact multiple of word size -- another possible corner case.
|
||||||
|
`ifdef WRITEMEM_READ_BACK
|
||||||
|
$readmemh("t/t_sys_readmem_align_h.mem", hex_align_tmp, 0);
|
||||||
|
`ifdef TEST_VERBOSE
|
||||||
|
$display("-Writing %s", `OUT_TMP4);
|
||||||
|
`endif
|
||||||
|
$writememh(`OUT_TMP4, hex_align_tmp, 0);
|
||||||
|
$readmemh(`OUT_TMP4, hex_align, 0);
|
||||||
|
`else
|
||||||
|
$readmemh("t/t_sys_readmem_align_h.mem", hex_align, 0);
|
||||||
|
`endif
|
||||||
|
`ifdef TEST_VERBOSE
|
||||||
|
for (i=0; i<16; i=i+1) $write(" @%x = %x\n", i, hex_align[i]);
|
||||||
|
`endif
|
||||||
|
if (hex_align['h04] != 192'h77554004_37654321_27654321_17654321_07654321_abcdef10) $stop;
|
||||||
|
if (hex_align['h0a] != 192'h7755400a_37654321_27654321_17654321_07654321_abcdef11) $stop;
|
||||||
|
if (hex_align['h0b] != 192'h7755400b_37654321_27654321_17654321_07654321_abcdef12) $stop;
|
||||||
|
if (hex_align['h0c] != 192'h7755400c_37654321_27654321_17654321_07654321_abcdef13) $stop;
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
fns = "t/t_sys_readmem_b.mem";
|
||||||
|
`ifdef WRITEMEM_READ_BACK
|
||||||
|
fns_tmp = `OUT_TMP5;
|
||||||
|
$readmemb(fns, binary_string_tmp);
|
||||||
|
`ifdef TEST_VERBOSE
|
||||||
|
$display("-Writing %s", `OUT_TMP5);
|
||||||
|
`endif
|
||||||
|
$writememh(fns_tmp, binary_string_tmp);
|
||||||
|
$readmemh(fns_tmp, binary_string);
|
||||||
|
`else
|
||||||
$readmemb(fns, binary_string);
|
$readmemb(fns, binary_string);
|
||||||
|
`endif
|
||||||
`ifdef TEST_VERBOSE
|
`ifdef TEST_VERBOSE
|
||||||
for (i=0; i<16; i=i+1) $write(" @%x = %x\n", i, binary_string[i]);
|
for (i=0; i<16; i=i+1) $write(" @%x = %x\n", i, binary_string[i]);
|
||||||
`endif
|
`endif
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// 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
|
||||||
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
// Version 2.0.
|
||||||
|
|
||||||
|
@4
|
||||||
|
77554004_37654321_27654321_17654321_07654321_abcdef10
|
||||||
|
@a
|
||||||
|
7755400a_37654321_27654321_17654321_07654321_abcdef11
|
||||||
|
7755400b_37654321_27654321_17654321_07654321_abcdef12
|
||||||
|
7755400c_37654321_27654321_17654321_07654321_abcdef13
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
02
|
||||||
|
03
|
||||||
|
04
|
||||||
|
05
|
||||||
|
06
|
||||||
|
07
|
||||||
|
10
|
||||||
|
00
|
||||||
|
00
|
||||||
|
00
|
||||||
|
14
|
||||||
|
15
|
||||||
|
00
|
||||||
|
00
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
10
|
||||||
|
11
|
||||||
|
12
|
||||||
|
13
|
||||||
|
14
|
||||||
|
15
|
||||||
|
16
|
||||||
|
17
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
00000000000000000000000000000000000000000000
|
||||||
|
00000000000000000000000000000000000000000000
|
||||||
|
00000000000000000000000000000000000000000000
|
||||||
|
00000000000000000000000000000000000000000000
|
||||||
|
400437654321276543211765432107654321abcdef10
|
||||||
|
00000000000000000000000000000000000000000000
|
||||||
|
00000000000000000000000000000000000000000000
|
||||||
|
00000000000000000000000000000000000000000000
|
||||||
|
00000000000000000000000000000000000000000000
|
||||||
|
00000000000000000000000000000000000000000000
|
||||||
|
400a37654321276543211765432107654321abcdef11
|
||||||
|
400b37654321276543211765432107654321abcdef12
|
||||||
|
400c37654321276543211765432107654321abcdef13
|
||||||
|
00000000000000000000000000000000000000000000
|
||||||
|
00000000000000000000000000000000000000000000
|
||||||
|
00000000000000000000000000000000000000000000
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
000000000000000000000000000000000000000000000000
|
||||||
|
000000000000000000000000000000000000000000000000
|
||||||
|
000000000000000000000000000000000000000000000000
|
||||||
|
000000000000000000000000000000000000000000000000
|
||||||
|
7755400437654321276543211765432107654321abcdef10
|
||||||
|
000000000000000000000000000000000000000000000000
|
||||||
|
000000000000000000000000000000000000000000000000
|
||||||
|
000000000000000000000000000000000000000000000000
|
||||||
|
000000000000000000000000000000000000000000000000
|
||||||
|
000000000000000000000000000000000000000000000000
|
||||||
|
7755400a37654321276543211765432107654321abcdef11
|
||||||
|
7755400b37654321276543211765432107654321abcdef12
|
||||||
|
7755400c37654321276543211765432107654321abcdef13
|
||||||
|
000000000000000000000000000000000000000000000000
|
||||||
|
000000000000000000000000000000000000000000000000
|
||||||
|
000000000000000000000000000000000000000000000000
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
02
|
||||||
|
03
|
||||||
|
04
|
||||||
|
05
|
||||||
|
06
|
||||||
|
07
|
||||||
|
10
|
||||||
|
00
|
||||||
|
00
|
||||||
|
00
|
||||||
|
14
|
||||||
|
15
|
||||||
|
00
|
||||||
|
00
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# 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
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
|
||||||
|
top_filename("t/t_sys_readmem.v");
|
||||||
|
|
||||||
|
# Use random reset to ensure we're fully initializing arrays before
|
||||||
|
# $writememh, to avoid miscompares with X's on 4-state simulators.
|
||||||
|
$Self->{verilated_randReset} = 2; # 2 == truly random
|
||||||
|
|
||||||
|
compile(v_flags2 => [
|
||||||
|
"+define+WRITEMEM_READ_BACK=1",
|
||||||
|
"+define+OUT_TMP1=\\\"$Self->{obj_dir}/tmp1.mem\\\"",
|
||||||
|
"+define+OUT_TMP2=\\\"$Self->{obj_dir}/tmp2.mem\\\"",
|
||||||
|
"+define+OUT_TMP3=\\\"$Self->{obj_dir}/tmp3.mem\\\"",
|
||||||
|
"+define+OUT_TMP4=\\\"$Self->{obj_dir}/tmp4.mem\\\"",
|
||||||
|
"+define+OUT_TMP5=\\\"$Self->{obj_dir}/tmp5.mem\\\"",
|
||||||
|
]);
|
||||||
|
|
||||||
|
execute (
|
||||||
|
check_finished=>1,
|
||||||
|
);
|
||||||
|
|
||||||
|
for (my $i = 1; $i <= 5; $i++) {
|
||||||
|
my $gold = "$Self->{t_dir}/t_sys_writemem.gold${i}.mem";
|
||||||
|
my $out = "$Self->{obj_dir}/tmp${i}.mem";
|
||||||
|
print "> diff $gold $out\n";
|
||||||
|
my @diffs = `diff $gold $out`;
|
||||||
|
if (0 < scalar @diffs) {
|
||||||
|
print @diffs;
|
||||||
|
$Self->error("Got unexpected diffs against gold.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
Loading…
Reference in New Issue