mirror of
https://github.com/verilator/verilator.git
synced 2026-10-04 00:53:42 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02530172e7 | ||
|
|
447d803800 | ||
|
|
6b04901c4d | ||
|
|
7fb29621c3 | ||
|
|
b032fce962 | ||
|
|
ce879122bb | ||
|
|
2fa16708b7 | ||
|
|
54bc8608e3 | ||
|
|
706a7802cc | ||
|
|
9dc01cf540 | ||
|
|
8943ad5966 | ||
|
|
deb7a1c9c0 | ||
|
|
96a5445d44 | ||
|
|
d693065afb | ||
|
|
bdeee35669 | ||
|
|
62b3deb90d | ||
|
|
9df9ff59e0 | ||
|
|
23a3271c06 |
@@ -3,6 +3,29 @@ Revision history for Verilator
|
||||
The contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
|
||||
* Verilator 3.904 2017-05-30
|
||||
|
||||
*** Fix non-cutable ordering loops on clock arrays, bug1009. [Todd Strader]
|
||||
|
||||
*** Support ports of array of reals, bug1154. [J Briquet]
|
||||
|
||||
*** Support arrayed parameter overrides, bug1153. [John Stevenson]
|
||||
|
||||
*** Support $value$plusargs with variables, bug1165. [Wesley Terpstra]
|
||||
|
||||
**** Support modport access to un-modport objects, bug1161. [Todd Strader]
|
||||
|
||||
**** Add stack trace when can't optimize function, bug1158. [Todd Strader]
|
||||
|
||||
**** Add warning on mis-sized literal, bug1156. [Todd Strader]
|
||||
|
||||
**** Fix interface functions returning wrong parameters, bug996. [Todd Strader]
|
||||
|
||||
**** Fix non-arrayed cells with interface arrays, bug1153. [John Stevenson]
|
||||
|
||||
**** Fix --assert with complex case statements, bug1164. [Enzo Chi]
|
||||
|
||||
|
||||
* Verilator 3.902 2017-04-02
|
||||
|
||||
** Add -FI option to force includes,msg2146. [Amir Gonnen]
|
||||
|
||||
+47
-26
@@ -495,6 +495,10 @@ If the signal is the input to top-module, the directly the signal name. If you
|
||||
find it difficult to find the exact name, try to use C</*verilator clocker*/> in
|
||||
RTL file to mark the signal directly.
|
||||
|
||||
If clock signals are assigned to vectors and then later used individually,
|
||||
Verilator will attempt to decompose the vector and connect the single-bit
|
||||
clock signals directly. This should be transparent to the user.
|
||||
|
||||
=item --compiler I<compiler-name>
|
||||
|
||||
Enables tunings and workarounds for the specified C++ compiler.
|
||||
@@ -1913,54 +1917,71 @@ documented below.
|
||||
Verilator has an important difference from an event based simulator; signal
|
||||
values that are changed by the VPI will not immediately propagate their
|
||||
values, instead the top level header file's eval() method must be called.
|
||||
Normally this would be part of the normal evaluation (IE the next clock
|
||||
Normally this would be part of the normal evaluation (i.e. the next clock
|
||||
edge), not as part of the value change. This makes the performance of VPI
|
||||
routines extremely fast compared to event based simulators, but can confuse
|
||||
some test-benches that expect immediate propagation.
|
||||
|
||||
Note the VPI by it's specified implementation will always be much slower
|
||||
Note the VPI by its specified implementation will always be much slower
|
||||
than accessing the Verilator values by direct reference
|
||||
(structure->module->signame), as the VPI accessors perform lookup in
|
||||
functions at runtime requiring at best hundreds of instructions, while the
|
||||
direct references are evaluated by the compiler and result in only a couple
|
||||
of instructions.
|
||||
|
||||
For signal callbacks to work the main loop of the program must call
|
||||
VerilatedVpi::callValueCbs().
|
||||
|
||||
=head2 VPI Example
|
||||
|
||||
In the below example, we have readme marked read-only, and writeme which if
|
||||
written from outside the model will have the same semantics as if it
|
||||
changed on the specified clock edge.
|
||||
|
||||
module t;
|
||||
reg readme /*verilator public_flat_rd*/;
|
||||
reg writeme /*verilator public_flat_rw @(posedge clk) */;
|
||||
endmodule
|
||||
cat <<EOF >our.v
|
||||
module our (input clk);
|
||||
reg readme /*verilator public_flat_rd*/;
|
||||
reg writeme /*verilator public_flat_rw @(posedge clk) */;
|
||||
initial $finish;
|
||||
endmodule
|
||||
EOF
|
||||
|
||||
There are many online tutorials and books on the VPI, but an example that
|
||||
accesses the above would be:
|
||||
accesses the above signal "readme" would be:
|
||||
|
||||
void read_and_check() {
|
||||
vpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)"t.readme", NULL);
|
||||
if (!vh1) { error... }
|
||||
const char* name = vpi_get_str(vpiName, vh1);
|
||||
printf("Module name: %s\n"); // Prints "readme"
|
||||
cat <<EOF >sim_main.cpp
|
||||
#include "Vour.h"
|
||||
#include "verilated.h"
|
||||
#include "verilated_vpi.h" // Required to get definitions
|
||||
|
||||
s_vpi_value v;
|
||||
v.format = vpiIntVal;
|
||||
vpi_get_value(vh1, &v);
|
||||
printf("Value of v: %d\n", v.value.integer); // Prints "readme"
|
||||
}
|
||||
vluint64_t main_time = 0; // See comments in first example
|
||||
double sc_time_stamp () { return main_time; }
|
||||
|
||||
For signal callbacks to work the main loop of the program must call
|
||||
VerilatedVpi::callValueCbs().
|
||||
void read_and_check() {
|
||||
vpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)"TOP.our.readme", NULL);
|
||||
if (!vh1) { vl_fatal(__FILE__, __LINE__, "sim_main", "No handle found"); }
|
||||
const char* name = vpi_get_str(vpiName, vh1);
|
||||
printf("Module name: %s\n", name); // Prints "readme"
|
||||
|
||||
#include "verilated_vpi.h" // Required to get definitions
|
||||
...
|
||||
while (time passes) {
|
||||
...
|
||||
topp->eval();
|
||||
VerilatedVpi::callValueCbs();
|
||||
}
|
||||
s_vpi_value v;
|
||||
v.format = vpiIntVal;
|
||||
vpi_get_value(vh1, &v);
|
||||
printf("Value of v: %d\n", v.value.integer); // Prints "readme"
|
||||
}
|
||||
|
||||
int main(int argc, char **argv, char **env) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
Vour* top = new Vour;
|
||||
Verilated::internalsDump(); // See scopes to help debug
|
||||
while (!Verilated::gotFinish()) {
|
||||
top->eval();
|
||||
VerilatedVpi::callValueCbs(); // For signal callbacks
|
||||
read_and_check();
|
||||
}
|
||||
delete top;
|
||||
exit(0);
|
||||
}
|
||||
EOF
|
||||
|
||||
|
||||
=head1 CROSS COMPILATION
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
|
||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||
#AC_INIT([Verilator],[#.### devel])
|
||||
AC_INIT([Verilator],[3.902 2017-04-02])
|
||||
AC_INIT([Verilator],[3.904 2017-05-30])
|
||||
# When releasing, also update header of Changes file
|
||||
|
||||
AC_CONFIG_HEADER(src/config_build.h)
|
||||
|
||||
+62
-20
@@ -302,8 +302,7 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
|
||||
bool inPct = false;
|
||||
bool widthSet = false;
|
||||
int width = 0;
|
||||
const char* pos = formatp;
|
||||
for (; *pos; ++pos) {
|
||||
for (const char* pos = formatp; *pos; ++pos) {
|
||||
if (!inPct && pos[0]=='%') {
|
||||
pctp = pos;
|
||||
inPct = true;
|
||||
@@ -1077,22 +1076,36 @@ IData VL_TESTPLUSARGS_I(const char* formatp) {
|
||||
else return 1;
|
||||
}
|
||||
|
||||
IData VL_VALUEPLUSARGS_IN(int, const char* prefixp, char, string& ldr) {
|
||||
const string& match = VerilatedImp::argPlusMatch(prefixp);
|
||||
const char* dp = match.c_str() + 1 /*leading + */ + strlen(prefixp);
|
||||
if (match == "") return 0;
|
||||
ldr = string(dp);
|
||||
return 1;
|
||||
}
|
||||
IData VL_VALUEPLUSARGS_INW(int rbits, const string& ld, WDataOutP rwp) {
|
||||
string prefix;
|
||||
bool inPct = false;
|
||||
bool done = false;
|
||||
char fmt = ' ';
|
||||
for (const char* posp = ld.c_str(); !done && *posp; ++posp) {
|
||||
if (!inPct && posp[0]=='%') {
|
||||
inPct = true;
|
||||
} else if (!inPct) { // Normal text
|
||||
prefix += *posp;
|
||||
} else { // Format character
|
||||
switch (tolower(*posp)) {
|
||||
case '%':
|
||||
prefix += *posp;
|
||||
inPct = false;
|
||||
break;
|
||||
default:
|
||||
fmt = *posp;
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IData VL_VALUEPLUSARGS_IW(int rbits, const char* prefixp, char fmt, WDataOutP rwp) {
|
||||
const string& match = VerilatedImp::argPlusMatch(prefixp);
|
||||
const char* dp = match.c_str() + 1 /*leading + */ + strlen(prefixp);
|
||||
const string& match = VerilatedImp::argPlusMatch(prefix.c_str());
|
||||
const char* dp = match.c_str() + 1 /*leading + */ + prefix.length();
|
||||
if (match == "") return 0;
|
||||
|
||||
VL_ZERO_RESET_W(rbits, rwp);
|
||||
switch (tolower(fmt)) {
|
||||
case '%':
|
||||
break;
|
||||
case 'd':
|
||||
vlsint64_t ld;
|
||||
sscanf(dp,"%30" VL_PRI64 "d",&ld);
|
||||
@@ -1108,18 +1121,47 @@ IData VL_VALUEPLUSARGS_IW(int rbits, const char* prefixp, char fmt, WDataOutP rw
|
||||
case 'x':
|
||||
_vl_vsss_based(rwp,rbits, 4, dp, 0, (int)strlen(dp));
|
||||
break;
|
||||
case 's':
|
||||
for (int i=0, lsb=0, pos=((int)strlen(dp))-1; i<rbits && pos>=0; pos--) {
|
||||
_vl_vsss_setbit(rwp,rbits,lsb, 8, dp[pos]); lsb+=8;
|
||||
case 's': // string/no conversion
|
||||
for (int i=0, lsb=0, posp=((int)strlen(dp))-1; i<rbits && posp>=0; posp--) {
|
||||
_vl_vsss_setbit(rwp,rbits,lsb, 8, dp[posp]); lsb+=8;
|
||||
}
|
||||
break;
|
||||
default: // Compile time should have found all errors before this
|
||||
vl_fatal (__FILE__, __LINE__, "", "$value$plusargs format error");
|
||||
break;
|
||||
case 'e': //FALLTHRU - Unsupported
|
||||
case 'f': //FALLTHRU - Unsupported
|
||||
case 'g': //FALLTHRU - Unsupported
|
||||
default: // Other simulators simply return 0 in these cases and don't error out
|
||||
return 0;
|
||||
}
|
||||
_VL_CLEAN_INPLACE_W(rbits,rwp);
|
||||
return 1;
|
||||
}
|
||||
IData VL_VALUEPLUSARGS_INN(int, const string& ld, string& rdr) {
|
||||
string prefix;
|
||||
bool inPct = false;
|
||||
bool done = false;
|
||||
for (const char* posp = ld.c_str(); !done && *posp; ++posp) {
|
||||
if (!inPct && posp[0]=='%') {
|
||||
inPct = true;
|
||||
} else if (!inPct) { // Normal text
|
||||
prefix += *posp;
|
||||
} else { // Format character
|
||||
switch (tolower(*posp)) {
|
||||
case '%':
|
||||
prefix += *posp;
|
||||
inPct = false;
|
||||
break;
|
||||
default:
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
const string& match = VerilatedImp::argPlusMatch(prefix.c_str());
|
||||
const char* dp = match.c_str() + 1 /*leading + */ + prefix.length();
|
||||
if (match == "") return 0;
|
||||
rdr = string(dp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* vl_mc_scan_plusargs(const char* prefixp) {
|
||||
const string& match = VerilatedImp::argPlusMatch(prefixp);
|
||||
|
||||
@@ -1077,7 +1077,9 @@ static inline QData VL_MULS_QQQ(int,int lbits,int, QData lhs,QData rhs) {
|
||||
|
||||
static inline WDataOutP VL_MULS_WWW(int,int lbits,int, WDataOutP owp,WDataInP lwp,WDataInP rwp){
|
||||
int words = VL_WORDS_I(lbits);
|
||||
// cppcheck-suppress variableScope
|
||||
IData lwstore[VL_MULS_MAX_WORDS]; // Fixed size, as MSVC++ doesn't allow [words] here
|
||||
// cppcheck-suppress variableScope
|
||||
IData rwstore[VL_MULS_MAX_WORDS];
|
||||
WDataInP lwusp = lwp;
|
||||
WDataInP rwusp = rwp;
|
||||
|
||||
@@ -66,6 +66,19 @@ extern void VL_READMEM_N(bool hex, int width, int depth, int array_lsb, int fnwo
|
||||
extern IData VL_SSCANF_INX(int lbits, const string& ld, const char* formatp, ...);
|
||||
extern void VL_SFORMAT_X(int obits_ignored, string &output, const char* formatp, ...);
|
||||
extern string VL_SFORMATF_NX(const char* formatp, ...);
|
||||
extern IData VL_VALUEPLUSARGS_IN(int rbits, const char* prefixp, char fmt, string& ldr);
|
||||
extern IData VL_VALUEPLUSARGS_INW(int rbits, const string& ld, WDataOutP rdp);
|
||||
inline IData VL_VALUEPLUSARGS_INI(int rbits, const string& ld, IData& rdr) {
|
||||
IData rwp[1];
|
||||
IData got = VL_VALUEPLUSARGS_INW(rbits,ld,rwp);
|
||||
if (got) rdr = rwp[0];
|
||||
return got;
|
||||
}
|
||||
inline IData VL_VALUEPLUSARGS_INQ(int rbits, const string& ld, QData& rdr) {
|
||||
IData rwp[2];
|
||||
IData got = VL_VALUEPLUSARGS_INW(rbits,ld,rwp);
|
||||
if (got) rdr = VL_SET_QW(rwp);
|
||||
return got;
|
||||
}
|
||||
extern IData VL_VALUEPLUSARGS_INN(int, const string& ld, string& rdr);
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+1
-1
@@ -108,7 +108,7 @@ private:
|
||||
// Move the active's contents to the other active
|
||||
UINFO(4," merge active "<<sensesp<<" into "<<wantp<<endl);
|
||||
if (nodep->sensesStorep()) {
|
||||
if (sensesp != nodep->sensesStorep()) nodep->v3fatalSrc("sensesStore should have been deleted earlier if different\n");
|
||||
if (sensesp != nodep->sensesStorep()) nodep->v3fatalSrc("sensesStore should have been deleted earlier if different");
|
||||
sensesp->unlinkFrBack();
|
||||
// There may be other references to same sense tree,
|
||||
// we'll be removing all references when we get to them,
|
||||
|
||||
+4
-14
@@ -246,20 +246,10 @@ private:
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
|
||||
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
|
||||
AstNode* onep;
|
||||
AstConst* iconstp = icondp->castConst();
|
||||
if (iconstp && iconstp->num().isFourState()
|
||||
&& (nodep->casex() || nodep->casez() || nodep->caseInside())) {
|
||||
V3Number nummask (itemp->fileline(), iconstp->width());
|
||||
nummask.opBitsNonX(iconstp->num());
|
||||
V3Number numval (itemp->fileline(), iconstp->width());
|
||||
numval.opBitsOne(iconstp->num());
|
||||
AstNode* and1p = new AstAnd(itemp->fileline(), nodep->exprp()->cloneTree(false),
|
||||
new AstConst(itemp->fileline(), nummask));
|
||||
AstNode* and2p = new AstAnd(itemp->fileline(),
|
||||
new AstConst(itemp->fileline(), numval),
|
||||
new AstConst(itemp->fileline(), nummask));
|
||||
onep = AstEq::newTyped(itemp->fileline(), and1p, and2p);
|
||||
|
||||
if (nodep->casex() || nodep->casez() || nodep->caseInside()) {
|
||||
onep = AstEqWild::newTyped(itemp->fileline(),
|
||||
nodep->exprp()->cloneTree(false),
|
||||
icondp->cloneTree(false));
|
||||
} else {
|
||||
onep = AstEq::newTyped(icondp->fileline(),
|
||||
nodep->exprp()->cloneTree(false),
|
||||
|
||||
+13
-1
@@ -1675,6 +1675,7 @@ public:
|
||||
virtual bool maybePointedTo() const { return true; }
|
||||
virtual AstNodeDType* virtRefDTypep() const { return NULL; } // Iff has a non-null refDTypep(), as generic node function
|
||||
virtual void virtRefDTypep(AstNodeDType* nodep) { } // Iff has refDTypep(), set as generic node function
|
||||
virtual bool similarDType(AstNodeDType* samep) const = 0; // Assignable equivalence. Call skipRefp() on this and samep before calling
|
||||
//
|
||||
// Changing the width may confuse the data type resolution, so must clear TypeTable cache after use.
|
||||
void widthForce(int width, int sized) { m_width=width; m_widthMin=sized; }
|
||||
@@ -1724,6 +1725,9 @@ public:
|
||||
virtual int widthAlignBytes() const; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
|
||||
virtual int widthTotalBytes() const; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
|
||||
// op1 = members
|
||||
virtual bool similarDType(AstNodeDType* samep) const {
|
||||
return this==samep; // We don't compare members, require exact equivalence
|
||||
}
|
||||
AstMemberDType* membersp() const { return op1p()->castMemberDType(); } // op1 = AstMember list
|
||||
void addMembersp(AstNode* nodep) { addNOp1p(nodep); }
|
||||
bool packed() const { return m_packed; }
|
||||
@@ -1754,7 +1758,7 @@ public:
|
||||
virtual void dump(ostream& str);
|
||||
virtual void dumpSmall(ostream& str);
|
||||
virtual const char* broken() const { BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|
||||
|| (!m_refDTypep && childDTypep()))); return NULL; }
|
||||
|| (!m_refDTypep && childDTypep()))); return NULL; }
|
||||
virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) {
|
||||
m_refDTypep = m_refDTypep->clonep();
|
||||
}}
|
||||
@@ -1763,6 +1767,14 @@ public:
|
||||
return (msb()==sp->msb()
|
||||
&& subDTypep()==sp->subDTypep()
|
||||
&& rangenp()->sameTree(sp->rangenp())); } // HashedDT doesn't recurse, so need to check children
|
||||
virtual bool similarDType(AstNodeDType* samep) const {
|
||||
AstNodeArrayDType* sp = samep->castNodeArrayDType();
|
||||
return (sp
|
||||
&& type() == samep->type()
|
||||
&& msb() == sp->msb()
|
||||
&& rangenp()->sameTree(sp->rangenp())
|
||||
&& subDTypep()->skipRefp()->similarDType(sp->subDTypep()->skipRefp()));
|
||||
}
|
||||
virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_refDTypep),V3Hash(msb()),V3Hash(lsb())); }
|
||||
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
||||
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
|
||||
|
||||
@@ -140,6 +140,13 @@ AstNodeBiop* AstLte::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
|
||||
}
|
||||
}
|
||||
|
||||
AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
|
||||
if (lhsp->isDouble() && rhsp->isDouble()) {
|
||||
return new AstEqD(fl, lhsp, rhsp);
|
||||
} else {
|
||||
return new AstEqWild(fl, lhsp, rhsp);
|
||||
}
|
||||
}
|
||||
|
||||
bool AstVar::isSigPublic() const {
|
||||
return (m_sigPublic || (v3Global.opt.allPublic() && !isTemp() && !isGenVar()));
|
||||
|
||||
+29
-16
@@ -180,6 +180,10 @@ public:
|
||||
virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); }
|
||||
virtual AstNodeDType* skipRefToConstp() const { return subDTypep()->skipRefToConstp(); }
|
||||
virtual AstNodeDType* skipRefToEnump() const { return subDTypep()->skipRefToEnump(); }
|
||||
virtual bool similarDType(AstNodeDType* samep) const {
|
||||
AstParamTypeDType* sp = samep->castParamTypeDType();
|
||||
return (sp && this->subDTypep()->skipRefp()->similarDType(sp->subDTypep()->skipRefp()));
|
||||
}
|
||||
virtual int widthAlignBytes() const { return dtypep()->widthAlignBytes(); }
|
||||
virtual int widthTotalBytes() const { return dtypep()->widthTotalBytes(); }
|
||||
// METHODS
|
||||
@@ -250,7 +254,9 @@ public:
|
||||
m_uniqueNum = uniqueNumInc();
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(DefImplicitDType)
|
||||
virtual bool same(AstNode* samep) const { return m_uniqueNum==samep->castDefImplicitDType()->m_uniqueNum; }
|
||||
virtual bool same(AstNode* samep) const { return m_uniqueNum==samep->castDefImplicitDType()->m_uniqueNum; }
|
||||
virtual bool similarDType(AstNodeDType* samep) const {
|
||||
return type()==samep->type() && same(samep); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(m_uniqueNum); }
|
||||
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
||||
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
|
||||
@@ -392,6 +398,8 @@ public:
|
||||
virtual V3Hash sameHash() const { return V3Hash(V3Hash(m.m_keyword), V3Hash(m.m_nrange.hi())); }
|
||||
virtual bool same(AstNode* samep) const { // width/widthMin/numeric compared elsewhere
|
||||
return samep->castBasicDType()->m == m; }
|
||||
virtual bool similarDType(AstNodeDType* samep) const {
|
||||
return type()==samep->type() && same(samep); }
|
||||
virtual string name() const { return m.m_keyword.ascii(); }
|
||||
virtual const char* broken() const { BROKEN_RTN(dtypep()!=this); return NULL; }
|
||||
AstRange* rangep() const { return op1p()->castRange(); } // op1 = Range of variable
|
||||
@@ -456,6 +464,8 @@ public:
|
||||
}}
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return (m_refDTypep==samep->castConstDType()->m_refDTypep); }
|
||||
virtual bool similarDType(AstNodeDType* samep) const {
|
||||
return skipRefp()->similarDType(samep->skipRefp()); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); } // node's type() included elsewhere
|
||||
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
||||
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
|
||||
@@ -499,6 +509,7 @@ public:
|
||||
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
|
||||
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
|
||||
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
|
||||
virtual bool similarDType(AstNodeDType* samep) const { return this==samep; }
|
||||
virtual int widthAlignBytes() const { return 1; }
|
||||
virtual int widthTotalBytes() const { return 1; }
|
||||
string cellName() const { return m_cellName; }
|
||||
@@ -540,6 +551,8 @@ public:
|
||||
return (m_refDTypep==samep->castRefDType()->m_refDTypep
|
||||
&& m_name==samep->castRefDType()->m_name
|
||||
&& m_packagep==samep->castRefDType()->m_packagep); }
|
||||
virtual bool similarDType(AstNodeDType* samep) const {
|
||||
return skipRefp()->similarDType(samep->skipRefp()); }
|
||||
virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_refDTypep),V3Hash(m_packagep)); }
|
||||
virtual void dump(ostream& str=cout);
|
||||
virtual string name() const { return m_name; }
|
||||
@@ -623,6 +636,7 @@ public:
|
||||
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
|
||||
virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; }
|
||||
virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); }
|
||||
virtual bool similarDType(AstNodeDType* samep) const { return this==samep; }
|
||||
//
|
||||
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type (Note don't need virtual - AstVar isn't a NodeDType)
|
||||
AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType)
|
||||
@@ -704,6 +718,7 @@ public:
|
||||
m_refDTypep = m_refDTypep->clonep();
|
||||
}}
|
||||
virtual bool same(AstNode* samep) const { return m_uniqueNum==samep->castEnumDType()->m_uniqueNum; }
|
||||
virtual bool similarDType(AstNodeDType* samep) const { return this==samep; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(m_uniqueNum); }
|
||||
AstNodeDType* getChildDTypep() const { return childDTypep(); }
|
||||
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Data type
|
||||
@@ -733,6 +748,7 @@ public:
|
||||
ASTNODE_NODE_FUNCS(ParseTypeDType)
|
||||
AstNodeDType* dtypep() const { return NULL; }
|
||||
// METHODS
|
||||
virtual bool similarDType(AstNodeDType* samep) const { return this==samep; }
|
||||
virtual AstBasicDType* basicp() const { return NULL; }
|
||||
virtual AstNodeDType* skipRefp() const { return NULL; }
|
||||
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
|
||||
@@ -2642,28 +2658,24 @@ public:
|
||||
class AstValuePlusArgs : public AstNodeMath {
|
||||
// Parents: expr
|
||||
// Child: variable to set. If NULL then this is a $test$plusargs instead of $value$plusargs
|
||||
private:
|
||||
string m_text;
|
||||
public:
|
||||
AstValuePlusArgs(FileLine* fileline, const string& text, AstNode* exprsp)
|
||||
: AstNodeMath (fileline), m_text(text) {
|
||||
setOp1p(exprsp);
|
||||
AstValuePlusArgs(FileLine* fileline, AstNode* searchp, AstNode* outp)
|
||||
: AstNodeMath (fileline) {
|
||||
setOp1p(searchp); setOp2p(outp);
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(ValuePlusArgs)
|
||||
virtual string name() const { return m_text; }
|
||||
virtual string verilogKwd() const { return "$value$plusargs"; }
|
||||
virtual string emitVerilog() { return verilogKwd(); }
|
||||
virtual string emitC() { return "VL_VALUEPLUSARGS_%nq(%lw, %P, NULL)"; }
|
||||
virtual string emitVerilog() { return "%f$value$plusargs(%l, %k%r)"; }
|
||||
virtual string emitC() { V3ERROR_NA; return ""; }
|
||||
virtual bool isGateOptimizable() const { return false; }
|
||||
virtual bool isPredictOptimizable() const { return false; }
|
||||
virtual bool cleanOut() { return true; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(text()); }
|
||||
virtual bool same(AstNode* samep) const {
|
||||
return text()==samep->castValuePlusArgs()->text(); }
|
||||
AstNode* exprsp() const { return op1p(); } // op1 = Expressions to output
|
||||
void exprsp(AstNode* nodep) { setOp1p(nodep); } // op1 = Expressions to output
|
||||
string text() const { return m_text; } // * = Text to display
|
||||
void text(const string& text) { m_text=text; }
|
||||
virtual V3Hash sameHash() const { return V3Hash(); }
|
||||
virtual bool same(AstNode* samep) const { return true; }
|
||||
AstNode* searchp() const { return op1p(); } // op1 = Search expression
|
||||
void searchp(AstNode* nodep) { setOp1p(nodep); }
|
||||
AstNode* outp() const { return op2p(); } // op2 = Expressions to output
|
||||
void outp(AstNode* nodep) { setOp2p(nodep); }
|
||||
};
|
||||
|
||||
class AstTestPlusArgs : public AstNodeMath {
|
||||
@@ -4657,6 +4669,7 @@ public:
|
||||
dtypeSetLogicBool(); }
|
||||
ASTNODE_NODE_FUNCS(EqWild)
|
||||
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstEqWild(this->fileline(), lhsp, rhsp); }
|
||||
static AstNodeBiop* newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp); // Return AstEqWild/AstEqD
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opWildEq(lhs,rhs); }
|
||||
virtual string emitVerilog() { return "%k(%l %f==? %r)"; }
|
||||
virtual string emitC() { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; }
|
||||
|
||||
+5
-5
@@ -62,7 +62,7 @@ public:
|
||||
if (debug()>=9) cout<<"-nodeDel: "<<(void*)(nodep)<<endl;
|
||||
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||
if (iter==s_nodes.end() || !(iter->second & FLAG_ALLOCATED)) {
|
||||
((AstNode*)(nodep))->v3fatalSrc("Deleting AstNode object that was never tracked or already deleted\n");
|
||||
((AstNode*)(nodep))->v3fatalSrc("Deleting AstNode object that was never tracked or already deleted");
|
||||
}
|
||||
if (iter!=s_nodes.end()) s_nodes.erase(iter);
|
||||
}
|
||||
@@ -71,7 +71,7 @@ public:
|
||||
if (debug()>=9) cout<<"-nodeNew: "<<(void*)(nodep)<<endl;
|
||||
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||
if (iter!=s_nodes.end() || (iter->second & FLAG_ALLOCATED)) {
|
||||
((AstNode*)(nodep))->v3fatalSrc("Newing AstNode object that is already allocated\n");
|
||||
((AstNode*)(nodep))->v3fatalSrc("Newing AstNode object that is already allocated");
|
||||
}
|
||||
if (iter == s_nodes.end()) {
|
||||
int flags = FLAG_ALLOCATED; // This int needed to appease GCC 4.1.2
|
||||
@@ -94,16 +94,16 @@ public:
|
||||
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||
if (iter == s_nodes.end()) {
|
||||
#ifdef VL_LEAK_CHECKS
|
||||
nodep->v3fatalSrc("AstNode is in tree, but not allocated\n");
|
||||
nodep->v3fatalSrc("AstNode is in tree, but not allocated");
|
||||
#endif
|
||||
} else {
|
||||
if (!(iter->second & FLAG_ALLOCATED)) {
|
||||
#ifdef VL_LEAK_CHECKS
|
||||
nodep->v3fatalSrc("AstNode is in tree, but not allocated\n");
|
||||
nodep->v3fatalSrc("AstNode is in tree, but not allocated");
|
||||
#endif
|
||||
}
|
||||
if (iter->second & FLAG_IN_TREE) {
|
||||
nodep->v3fatalSrc("AstNode is already in tree at another location\n");
|
||||
nodep->v3fatalSrc("AstNode is already in tree at another location");
|
||||
}
|
||||
}
|
||||
int or_flags = FLAG_IN_TREE | (linkable?FLAG_LINKABLE:0);
|
||||
|
||||
+7
-2
@@ -75,7 +75,8 @@ public:
|
||||
m_numStmts += 1;
|
||||
}
|
||||
|
||||
V3CCtorsVisitor(AstNodeModule* nodep, string basename, string argsp="", string callargsp="") {
|
||||
V3CCtorsVisitor(AstNodeModule* nodep, string basename, string argsp="", string callargsp="",
|
||||
const string& stmt="") {
|
||||
m_basename = basename;
|
||||
m_argsp = argsp;
|
||||
m_callargsp = callargsp;
|
||||
@@ -87,6 +88,9 @@ public:
|
||||
m_tlFuncp->isStatic(false);
|
||||
m_tlFuncp->slow(true);
|
||||
m_tlFuncp->argTypes(m_argsp);
|
||||
if (stmt != "") {
|
||||
m_tlFuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
|
||||
}
|
||||
m_funcp = m_tlFuncp;
|
||||
m_modp->addStmtp(m_tlFuncp);
|
||||
}
|
||||
@@ -100,7 +104,8 @@ void V3CCtors::cctorsAll() {
|
||||
// Process each module in turn
|
||||
V3CCtorsVisitor var_reset (modp, "_ctor_var_reset");
|
||||
V3CCtorsVisitor configure_coverage (modp, "_configure_coverage",
|
||||
EmitCBaseVisitor::symClassVar()+ ", bool first", "vlSymsp, first");
|
||||
EmitCBaseVisitor::symClassVar()+ ", bool first", "vlSymsp, first",
|
||||
"if (0 && vlSymsp && first) {} // Prevent unused\n");
|
||||
|
||||
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
|
||||
AstVar* varp = np->castVar();
|
||||
|
||||
+1
-1
@@ -174,7 +174,7 @@ private:
|
||||
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
|
||||
//if (debug()>=9) icondp->dumpTree(cout," caseitem: ");
|
||||
AstConst* iconstp = icondp->castConst();
|
||||
if (!iconstp) nodep->v3fatalSrc("above 'can't parse' should have caught this\n");
|
||||
if (!iconstp) nodep->v3fatalSrc("above 'can't parse' should have caught this");
|
||||
if (neverItem(nodep, iconstp)) {
|
||||
// X in casez can't ever be executed
|
||||
} else {
|
||||
|
||||
+2
-2
@@ -629,9 +629,9 @@ private:
|
||||
}
|
||||
virtual void visit(AstNodeVarRef* nodep) {
|
||||
if (m_scopep) {
|
||||
if (!m_logicVertexp) nodep->v3fatalSrc("Var ref not under a logic block\n");
|
||||
if (!m_logicVertexp) nodep->v3fatalSrc("Var ref not under a logic block");
|
||||
AstVarScope* varscp = nodep->varScopep();
|
||||
if (!varscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp\n");
|
||||
if (!varscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp");
|
||||
CdcVarVertex* varvertexp = makeVarVertex(varscp);
|
||||
UINFO(5," VARREF to "<<varscp<<endl);
|
||||
// We use weight of one for normal edges,
|
||||
|
||||
+1
-1
@@ -253,7 +253,7 @@ private:
|
||||
AstNode::user1ClearTree();
|
||||
// Create the change detection function
|
||||
AstScope* scopep = nodep->scopep();
|
||||
if (!scopep) nodep->v3fatalSrc("No scope found on top level, perhaps you have no statements?\n");
|
||||
if (!scopep) nodep->v3fatalSrc("No scope found on top level, perhaps you have no statements?");
|
||||
m_statep->m_scopetopp = scopep;
|
||||
|
||||
// Create a wrapper change detection function that calls each change detection function
|
||||
|
||||
+1
-1
@@ -559,7 +559,7 @@ class GaterVisitor : public GaterBaseVisitor {
|
||||
if (!vVxp->inBeginp()) {
|
||||
// At this point, any variable not linked is an error
|
||||
// (It should have at least landed under the Head node)
|
||||
vVxp->nodep()->v3fatalSrc("Variable became stranded in clk gate detection\n");
|
||||
vVxp->nodep()->v3fatalSrc("Variable became stranded in clk gate detection");
|
||||
}
|
||||
if (!lastVxp || vVxp->sortCmp(lastVxp)) {
|
||||
// Different sources for this new node
|
||||
|
||||
+1
-1
@@ -192,7 +192,7 @@ private:
|
||||
UINFO(4," TOPSCOPE "<<nodep<<endl);
|
||||
m_topScopep=nodep;
|
||||
m_scopep = nodep->scopep();
|
||||
if (!m_scopep) nodep->v3fatalSrc("No scope found on top level, perhaps you have no statements?\n");
|
||||
if (!m_scopep) nodep->v3fatalSrc("No scope found on top level, perhaps you have no statements?");
|
||||
//VV***** We reset all user1p()
|
||||
AstNode::user1ClearTree();
|
||||
// Make top functions
|
||||
|
||||
+1
-1
@@ -239,7 +239,7 @@ private:
|
||||
V3Hash hashval = it->first;
|
||||
AstNode* node1p = it->second;
|
||||
if (!node1p->castCFunc()) continue;
|
||||
if (hashval.isIllegal()) node1p->v3fatalSrc("Illegal (unhashed) nodes\n");
|
||||
if (hashval.isIllegal()) node1p->v3fatalSrc("Illegal (unhashed) nodes");
|
||||
for (V3Hashed::iterator eqit = it; eqit != m_hashed.end(); ++eqit) {
|
||||
AstNode* node2p = eqit->second;
|
||||
if (!(eqit->first == hashval)) break;
|
||||
|
||||
+9
-1
@@ -555,7 +555,7 @@ private:
|
||||
// Replace oldp node with a constant set to specified value
|
||||
UASSERT (oldp, "Null old\n");
|
||||
if (oldp->castConst() && !oldp->castConst()->num().isFourState()) {
|
||||
oldp->v3fatalSrc("Already constant??\n");
|
||||
oldp->v3fatalSrc("Already constant??");
|
||||
}
|
||||
AstNode* newp = new AstConst(oldp->fileline(), num);
|
||||
newp->dtypeFrom(oldp);
|
||||
@@ -1491,6 +1491,14 @@ private:
|
||||
did=true;
|
||||
}
|
||||
}
|
||||
else if (m_params && valuep->castInitArray() && nodep->backp()->castPin()) {
|
||||
// Allow parameters to pass arrays
|
||||
// Earlier recursion of InitArray made sure each array value is constant
|
||||
// This exception is fairly fragile, i.e. doesn't support arrays of arrays or other stuff
|
||||
AstNode* newp = valuep->cloneTree(false);
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
did = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!did && m_required) {
|
||||
|
||||
+4
-4
@@ -207,8 +207,8 @@ private:
|
||||
dimvalp.push_front(valp);
|
||||
}
|
||||
AstVarRef* varrefp = dimselp->castVarRef();
|
||||
if (!varrefp) nodep->v3fatalSrc("No var underneath arraysels\n");
|
||||
if (!varrefp->varScopep()) varrefp->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp\n");
|
||||
if (!varrefp) nodep->v3fatalSrc("No var underneath arraysels");
|
||||
if (!varrefp->varScopep()) varrefp->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp");
|
||||
varrefp->unlinkFrBack();
|
||||
AstVar* oldvarp = varrefp->varp();
|
||||
int modVecNum = oldvarp->user4(); oldvarp->user4(modVecNum+1);
|
||||
@@ -393,7 +393,7 @@ private:
|
||||
if (!m_activep) nodep->v3fatalSrc("<= not under sensitivity block");
|
||||
if (!m_activep->hasClocked()) nodep->v3error("Internal: Blocking <= assignment in non-clocked block, should have converted in V3Active");
|
||||
AstVarScope* oldvscp = nodep->varScopep();
|
||||
if (!oldvscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp\n");
|
||||
if (!oldvscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp");
|
||||
AstVarScope* dlyvscp = oldvscp->user1p()->castVarScope();
|
||||
if (dlyvscp) { // Multiple use of delayed variable
|
||||
AstActive* oldactivep = dlyvscp->user2p()->castActive();
|
||||
@@ -433,7 +433,7 @@ private:
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeFor* nodep) {
|
||||
nodep->v3fatalSrc("For statements should have been converted to while statements in V3Begin\n");
|
||||
nodep->v3fatalSrc("For statements should have been converted to while statements in V3Begin");
|
||||
}
|
||||
virtual void visit(AstWhile* nodep) {
|
||||
bool oldloop = m_inLoop;
|
||||
|
||||
+25
-47
@@ -217,7 +217,7 @@ public:
|
||||
}
|
||||
virtual void visit(AstNodeCase* nodep) {
|
||||
// In V3Case...
|
||||
nodep->v3fatalSrc("Case statements should have been reduced out\n");
|
||||
nodep->v3fatalSrc("Case statements should have been reduced out");
|
||||
}
|
||||
virtual void visit(AstComment* nodep) {
|
||||
putsDecoration((string)"// "+nodep->name()+" at "+nodep->fileline()->ascii()+"\n");
|
||||
@@ -277,54 +277,15 @@ public:
|
||||
displayNode(nodep, NULL, nodep->text(), nodep->exprsp(), true);
|
||||
}
|
||||
virtual void visit(AstValuePlusArgs* nodep) {
|
||||
string prefix;
|
||||
char format = '?';
|
||||
bool pct=false;
|
||||
int got=0;
|
||||
string txt = nodep->text();
|
||||
for (string::const_iterator it=txt.begin(); it!=txt.end(); ++it) {
|
||||
char ch = *it;
|
||||
if (pct) {
|
||||
pct = false;
|
||||
switch (tolower(ch)) {
|
||||
case '%':
|
||||
prefix += ch;
|
||||
break;
|
||||
case 'd': // FALLTHRU
|
||||
case 'o': // FALLTHRU
|
||||
case 'h': // FALLTHRU
|
||||
case 'x': // FALLTHRU
|
||||
case 'b': // FALLTHRU
|
||||
case 'v': // FALLTHRU
|
||||
case 's':
|
||||
got++; format = tolower(ch);
|
||||
break;
|
||||
case 'e': // FALLTHRU
|
||||
case 'f': // FALLTHRU
|
||||
case 'g':
|
||||
got++; format = tolower(ch);
|
||||
nodep->v3error("Unsupported $value$plusargs format qualifier: '"<<ch<<"'"<<endl);
|
||||
break;
|
||||
default:
|
||||
got++;
|
||||
nodep->v3error("Illegal $value$plusargs format qualifier: '"<<ch<<"'"<<endl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (ch == '%') pct = true;
|
||||
else prefix += ch;
|
||||
}
|
||||
if (got!=1) nodep->v3error("Missing or extra $value$plusargs format qualifier: '"<<nodep->text()<<"'"<<endl);
|
||||
puts("VL_VALUEPLUSARGS_I");
|
||||
emitIQW(nodep->exprsp());
|
||||
puts("VL_VALUEPLUSARGS_IN");
|
||||
emitIQW(nodep->outp());
|
||||
puts("(");
|
||||
puts(cvtToStr(nodep->exprsp()->widthMin())); // Note argument width, not node width (which is always 32)
|
||||
putbs(",");
|
||||
putsQuoted(prefix);
|
||||
putbs(",");
|
||||
puts("'"); puts(cvtToStr(format)); puts("'");
|
||||
puts(cvtToStr(nodep->outp()->widthMin()));
|
||||
puts(",");
|
||||
nodep->exprsp()->iterateAndNext(*this);
|
||||
emitCvtPackStr(nodep->searchp());
|
||||
puts(",");
|
||||
putbs("");
|
||||
nodep->outp()->iterateAndNext(*this);
|
||||
puts(")");
|
||||
}
|
||||
virtual void visit(AstTestPlusArgs* nodep) {
|
||||
@@ -618,6 +579,23 @@ public:
|
||||
puts(nodep->hiername());
|
||||
puts(nodep->varp()->name());
|
||||
}
|
||||
void emitCvtPackStr(AstNode* nodep) {
|
||||
if (AstConst* constp = nodep->castConst()) {
|
||||
putbs("string(");
|
||||
putsQuoted(constp->num().toString());
|
||||
puts(")");
|
||||
} else {
|
||||
putbs("VL_CVT_PACK_STR_N");
|
||||
emitIQW(nodep);
|
||||
puts("(");
|
||||
if (nodep->isWide()) {
|
||||
puts(cvtToStr(nodep->widthWords())); // Note argument width, not node width (which is always 32)
|
||||
puts(",");
|
||||
}
|
||||
nodep->iterateAndNext(*this);
|
||||
puts(")");
|
||||
}
|
||||
}
|
||||
void emitConstant(AstConst* nodep, AstVarRef* assigntop, const string& assignString) {
|
||||
// Put out constant set to the specified variable, or given variable in a string
|
||||
if (nodep->num().isFourState()) {
|
||||
|
||||
@@ -238,10 +238,6 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
virtual void visit(AstSFormatF* nodep) {
|
||||
visitNodeDisplay(nodep, NULL, nodep->text(), nodep->exprsp());
|
||||
}
|
||||
virtual void visit(AstValuePlusArgs* nodep) {
|
||||
visitNodeDisplay(nodep, NULL, nodep->text(), nodep->exprsp());
|
||||
}
|
||||
|
||||
virtual void visit(AstFOpen* nodep) {
|
||||
putfs(nodep,nodep->verilogKwd());
|
||||
putbs(" (");
|
||||
|
||||
+1
-1
@@ -270,7 +270,7 @@ void FileLine::operator delete(void* objp, size_t size) {
|
||||
if (it != fileLineLeakChecks.end()) {
|
||||
fileLineLeakChecks.erase(it);
|
||||
} else {
|
||||
flp->v3fatalSrc("Deleting FileLine object that was never tracked\n");
|
||||
flp->v3fatalSrc("Deleting FileLine object that was never tracked");
|
||||
}
|
||||
::operator delete(objp);
|
||||
}
|
||||
|
||||
+216
-4
@@ -113,6 +113,20 @@ public:
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
// Returns only the result from the LAST vertex iterated over
|
||||
// Note: This behaves differently than iterateInEdges() in that it will traverse
|
||||
// all edges that exist when it is initially called, whereas
|
||||
// iterateInEdges() will stop traversing edges if one is deleted
|
||||
VNUser iterateCurrentOutEdges(GateGraphBaseVisitor& v, VNUser vu=VNUser(0)) {
|
||||
VNUser ret = VNUser(0);
|
||||
V3GraphEdge* next_edgep = NULL;
|
||||
for (V3GraphEdge* edgep = outBeginp(); edgep; edgep = next_edgep) {
|
||||
// Need to find the next edge before visiting in case the edge is deleted
|
||||
next_edgep = edgep->outNextp();
|
||||
ret = dynamic_cast<GateEitherVertex*>(edgep->top())->accept(v, vu);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
class GateVarVertex : public GateEitherVertex {
|
||||
@@ -291,6 +305,7 @@ private:
|
||||
// {statement}Node::user1p -> GateLogicVertex* for this statement
|
||||
// AstVarScope::user2 -> bool: Signal used in SenItem in *this* always statement
|
||||
// AstVar::user2 -> bool: Warned about SYNCASYNCNET
|
||||
// AstVarNodeRef::user2 -> bool: ConcatOffset visited
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
|
||||
@@ -358,6 +373,7 @@ private:
|
||||
void replaceAssigns();
|
||||
void dedupe();
|
||||
void mergeAssigns();
|
||||
void decomposeClkVectors();
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) {
|
||||
@@ -365,6 +381,8 @@ private:
|
||||
//if (debug()>6) m_graph.dump();
|
||||
if (debug()>6) m_graph.dumpDotFilePrefixed("gate_pre");
|
||||
warnSignals(); // Before loss of sync/async pointers
|
||||
// Decompose clock vectors -- need to do this before removing redundant edges
|
||||
decomposeClkVectors();
|
||||
m_graph.removeRedundantEdgesSum(&V3GraphEdge::followAlwaysTrue);
|
||||
m_graph.dumpDotFilePrefixed("gate_simp");
|
||||
// Find gate interconnect and optimize
|
||||
@@ -409,9 +427,9 @@ private:
|
||||
}
|
||||
virtual void visit(AstNodeVarRef* nodep) {
|
||||
if (m_scopep) {
|
||||
if (!m_logicVertexp) nodep->v3fatalSrc("Var ref not under a logic block\n");
|
||||
if (!m_logicVertexp) nodep->v3fatalSrc("Var ref not under a logic block");
|
||||
AstVarScope* varscp = nodep->varScopep();
|
||||
if (!varscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp\n");
|
||||
if (!varscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp");
|
||||
GateVarVertex* vvertexp = makeVarVertex(varscp);
|
||||
UINFO(5," VARREF to "<<varscp<<endl);
|
||||
if (m_inSenItem) vvertexp->setIsClock();
|
||||
@@ -484,7 +502,7 @@ private:
|
||||
}
|
||||
virtual void visit(AstConcat* nodep) {
|
||||
if (nodep->backp()->castNodeAssign() && nodep->backp()->castNodeAssign()->lhsp()==nodep) {
|
||||
nodep->v3fatalSrc("Concat on LHS of assignment; V3Const should have deleted it\n");
|
||||
nodep->v3fatalSrc("Concat on LHS of assignment; V3Const should have deleted it");
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
@@ -704,7 +722,7 @@ void GateVisitor::replaceAssigns() {
|
||||
if (!vscp->valuep()->castNodeMath()
|
||||
|| vscp->valuep()->nextp()) {
|
||||
vscp->dumpTree(cerr, "vscStrange: ");
|
||||
vscp->v3fatalSrc("Value of varscope not mathematical\n");
|
||||
vscp->v3fatalSrc("Value of varscope not mathematical");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1238,6 +1256,200 @@ void GateVisitor::mergeAssigns() {
|
||||
m_statAssignMerged += merger.numMergedAssigns();
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// Find a var's offset in a concatenation
|
||||
|
||||
class GateConcatVisitor : public GateBaseVisitor {
|
||||
private:
|
||||
// STATE
|
||||
AstVarScope* m_vscp; // Varscope we're trying to find
|
||||
int m_offset; // Current offset of varscope
|
||||
int m_found_offset; // Found offset of varscope
|
||||
bool m_found; // Offset found
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeVarRef* nodep) {
|
||||
UINFO(9,"CLK DECOMP Concat search var (off = "<<m_offset<<") - "<<nodep<<endl);
|
||||
if (nodep->varScopep() == m_vscp && !nodep->user2() && !m_found) {
|
||||
// A concatenation may use the same var multiple times
|
||||
// But the graph will initially have an edge per instance
|
||||
nodep->user2(true);
|
||||
m_found_offset = m_offset;
|
||||
m_found = true;
|
||||
UINFO(9,"CLK DECOMP Concat found var (off = "<<m_offset<<") - "<<nodep<<endl);
|
||||
}
|
||||
m_offset += nodep->dtypep()->width();
|
||||
}
|
||||
virtual void visit(AstConcat* nodep) {
|
||||
UINFO(9,"CLK DECOMP Concat search (off = "<<m_offset<<") - "<<nodep<<endl);
|
||||
nodep->rhsp()->iterate(*this);
|
||||
nodep->lhsp()->iterate(*this);
|
||||
}
|
||||
//--------------------
|
||||
// Default
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
GateConcatVisitor() {
|
||||
m_vscp = NULL;
|
||||
m_offset = 0;
|
||||
m_found_offset = 0;
|
||||
m_found = false;
|
||||
}
|
||||
virtual ~GateConcatVisitor() {}
|
||||
// PUBLIC METHODS
|
||||
bool concatOffset(AstConcat* concatp, AstVarScope* vscp, int& offsetr) {
|
||||
m_vscp = vscp;
|
||||
m_offset = 0;
|
||||
m_found = false;
|
||||
// Iterate
|
||||
concatp->accept(*this);
|
||||
UINFO(9,"CLK DECOMP Concat Offset (found = "<<m_found<<") ("<<m_found_offset<<") - "<<concatp<<" : "<<vscp<<endl);
|
||||
offsetr = m_found_offset;
|
||||
return m_found;
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Recurse through the graph, looking for clock vectors to bypass
|
||||
|
||||
class GateClkDecompState {
|
||||
public:
|
||||
int m_offset;
|
||||
AstVarScope* m_last_vsp;
|
||||
GateClkDecompState(int offset, AstVarScope* vsp) {
|
||||
m_offset = offset;
|
||||
m_last_vsp = vsp;
|
||||
}
|
||||
virtual ~GateClkDecompState() {}
|
||||
};
|
||||
|
||||
class GateClkDecompGraphVisitor : public GateGraphBaseVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// AstVarScope::user2p -> bool: already visited
|
||||
V3Graph* m_graphp;
|
||||
int m_seen_clk_vectors;
|
||||
AstVarScope* m_clk_vsp;
|
||||
GateVarVertex* m_clk_vvertexp;
|
||||
GateConcatVisitor m_concat_visitor;
|
||||
int m_total_seen_clk_vectors;
|
||||
int m_total_decomposed_clk_vectors;
|
||||
|
||||
virtual VNUser visit(GateVarVertex* vvertexp, VNUser vu) {
|
||||
// Check that we haven't been here before
|
||||
AstVarScope* vsp = vvertexp->varScp();
|
||||
if (vsp->user2SetOnce()) return VNUser(0);
|
||||
UINFO(9,"CLK DECOMP Var - "<<vvertexp<<" : "<<vsp<<endl);
|
||||
if (vsp->varp()->width() > 1) {
|
||||
m_seen_clk_vectors++;
|
||||
m_total_seen_clk_vectors++;
|
||||
}
|
||||
GateClkDecompState* currState = (GateClkDecompState*) vu.c();
|
||||
GateClkDecompState nextState(currState->m_offset, vsp);
|
||||
vvertexp->iterateCurrentOutEdges(*this, VNUser(&nextState));
|
||||
if (vsp->varp()->width() > 1) {
|
||||
m_seen_clk_vectors--;
|
||||
}
|
||||
vsp->user2(false);
|
||||
return VNUser(0);
|
||||
}
|
||||
|
||||
virtual VNUser visit(GateLogicVertex* lvertexp, VNUser vu) {
|
||||
GateClkDecompState* currState = (GateClkDecompState*) vu.c();
|
||||
int clk_offset = currState->m_offset;
|
||||
if (AstAssignW* assignp = lvertexp->nodep()->castAssignW()) {
|
||||
UINFO(9,"CLK DECOMP Logic (off = "<<clk_offset<<") - "<<lvertexp<<" : "<<m_clk_vsp<<endl);
|
||||
if (AstSel* rselp = assignp->rhsp()->castSel()) {
|
||||
if (rselp->lsbp()->castConst() && rselp->widthp()->castConst()) {
|
||||
if (clk_offset < rselp->lsbConst() || clk_offset > rselp->msbConst()) {
|
||||
UINFO(9,"CLK DECOMP Sel [ "<<rselp->msbConst()<<" : "<<rselp->lsbConst()<<" ] dropped clock ("<<clk_offset<<")"<<endl);
|
||||
return VNUser(0);
|
||||
}
|
||||
clk_offset -= rselp->lsbConst();
|
||||
} else {
|
||||
return VNUser(0);
|
||||
}
|
||||
} else if (AstConcat* catp = assignp->rhsp()->castConcat()) {
|
||||
UINFO(9,"CLK DECOMP Concat searching - "<<assignp->lhsp()<<endl);
|
||||
int concat_offset;
|
||||
if (!m_concat_visitor.concatOffset(catp, currState->m_last_vsp, concat_offset)) {
|
||||
return VNUser(0);
|
||||
}
|
||||
clk_offset += concat_offset;
|
||||
}
|
||||
if (AstSel* lselp = assignp->lhsp()->castSel()) {
|
||||
if (lselp->lsbp()->castConst() && lselp->widthp()->castConst()) {
|
||||
clk_offset += lselp->lsbConst();
|
||||
} else {
|
||||
return VNUser(0);
|
||||
}
|
||||
} else if (AstVarRef* vrp = assignp->lhsp()->castVarRef()) {
|
||||
if (vrp->dtypep()->width() == 1 && m_seen_clk_vectors) {
|
||||
if (clk_offset != 0) {
|
||||
UINFO(9,"Should only make it here with clk_offset = 0"<<endl);
|
||||
return VNUser(0);
|
||||
}
|
||||
UINFO(9,"CLK DECOMP Connecting - "<<assignp->lhsp()<<" <-> "<<m_clk_vsp<<endl);
|
||||
AstNode* rhsp = assignp->rhsp();
|
||||
rhsp->replaceWith(new AstVarRef(rhsp->fileline(), m_clk_vsp, false));
|
||||
for (V3GraphEdge* edgep = lvertexp->inBeginp(); edgep; ) {
|
||||
edgep->unlinkDelete(); VL_DANGLING(edgep);
|
||||
}
|
||||
new V3GraphEdge(m_graphp, m_clk_vvertexp, lvertexp, 1);
|
||||
m_total_decomposed_clk_vectors++;
|
||||
}
|
||||
}
|
||||
GateClkDecompState nextState(clk_offset, currState->m_last_vsp);
|
||||
return lvertexp->iterateCurrentOutEdges(*this, VNUser(&nextState));
|
||||
}
|
||||
return VNUser(0);
|
||||
}
|
||||
|
||||
public:
|
||||
GateClkDecompGraphVisitor(V3Graph* graphp) {
|
||||
m_graphp = graphp;
|
||||
m_seen_clk_vectors = 0;
|
||||
m_clk_vsp = NULL;
|
||||
m_clk_vvertexp = NULL;
|
||||
m_total_seen_clk_vectors = 0;
|
||||
m_total_decomposed_clk_vectors = 0;
|
||||
}
|
||||
virtual ~GateClkDecompGraphVisitor() {
|
||||
V3Stats::addStat("Optimizations, Clocker seen vectors", m_total_seen_clk_vectors);
|
||||
V3Stats::addStat("Optimizations, Clocker decomposed vectors", m_total_decomposed_clk_vectors);
|
||||
}
|
||||
void clkDecomp(GateVarVertex* vvertexp) {
|
||||
UINFO(9,"CLK DECOMP Starting Var - "<<vvertexp<<endl);
|
||||
m_seen_clk_vectors = 0;
|
||||
m_clk_vsp = vvertexp->varScp();
|
||||
m_clk_vvertexp = vvertexp;
|
||||
GateClkDecompState nextState(0, m_clk_vsp);
|
||||
vvertexp->accept(*this, VNUser(&nextState));
|
||||
}
|
||||
};
|
||||
|
||||
void GateVisitor::decomposeClkVectors() {
|
||||
UINFO(9,"Starting clock decomposition"<<endl);
|
||||
AstNode::user2ClearTree();
|
||||
GateClkDecompGraphVisitor decomposer(&m_graph);
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
|
||||
if (GateVarVertex* vertp = dynamic_cast<GateVarVertex*>(itp)) {
|
||||
AstVarScope* vsp = vertp->varScp();
|
||||
if (vsp->varp()->attrClocker() == AstVarAttrClocker::CLOCKER_YES) {
|
||||
if (vsp->varp()->width() > 1) {
|
||||
UINFO(9,"Clocker > 1 bit, not decomposing: "<<vsp<<endl);
|
||||
} else {
|
||||
UINFO(9,"CLK DECOMP - "<<vertp<<" : "<<vsp<<endl);
|
||||
decomposer.clkDecomp(vertp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//######################################################################
|
||||
// Convert VARSCOPE(ASSIGN(default, VARREF)) to just VARSCOPE(default)
|
||||
|
||||
+1
-1
@@ -529,7 +529,7 @@ double V3Graph::orderDFSIterate(V3GraphVertex* vertexp) {
|
||||
// Compute fanouts of each node
|
||||
// If forward edge, don't double count that fanout
|
||||
if (vertexp->user() == 2) return vertexp->fanout(); // Already processed it
|
||||
if (vertexp->user() == 1) v3fatalSrc("Loop found, backward edges should be dead\n");
|
||||
if (vertexp->user() == 1) v3fatalSrc("Loop found, backward edges should be dead");
|
||||
vertexp->user(1);
|
||||
double fanout = 0;
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
|
||||
+2
-2
@@ -44,7 +44,7 @@ DfaVertex* DfaGraph::findStart() {
|
||||
startp = vvertexp;
|
||||
}
|
||||
} else {
|
||||
v3fatalSrc("Non DfaVertex in DfaGraph\n");
|
||||
v3fatalSrc("Non DfaVertex in DfaGraph");
|
||||
}
|
||||
}
|
||||
if (!startp) v3fatalSrc("No start point in NFA graph");
|
||||
@@ -520,7 +520,7 @@ private:
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!acceptp) v3fatalSrc("No accepting vertex in DFA\n");
|
||||
if (!acceptp) v3fatalSrc("No accepting vertex in DFA");
|
||||
|
||||
// Remap edges
|
||||
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
|
||||
+3
-3
@@ -277,7 +277,7 @@ private:
|
||||
AstVarRef* exprvarrefp = nodep->user2p()->castVarRef();
|
||||
UINFO(8,"connectto: "<<nodep->user2p()<<endl);
|
||||
if (!exprconstp && !exprvarrefp) {
|
||||
nodep->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up\n");
|
||||
nodep->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up");
|
||||
}
|
||||
if (exprconstp) {
|
||||
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
|
||||
@@ -362,7 +362,7 @@ private:
|
||||
nodep->varp( exprvarrefp->varp() );
|
||||
}
|
||||
else {
|
||||
nodep->v3fatalSrc("Null connection?\n");
|
||||
nodep->v3fatalSrc("Null connection?");
|
||||
}
|
||||
}
|
||||
nodep->name(nodep->varp()->name());
|
||||
@@ -514,7 +514,7 @@ private:
|
||||
|
||||
AstNode* connectRefp = pinp->exprp();
|
||||
if (!connectRefp->castConst() && !connectRefp->castVarRef()) {
|
||||
pinp->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up\n");
|
||||
pinp->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up");
|
||||
}
|
||||
if (pinNewVarp->isOutOnly() && connectRefp->castConst()) {
|
||||
pinp->v3error("Output port is connected to a constant pin, electrical short");
|
||||
|
||||
+109
-51
@@ -90,7 +90,7 @@ private:
|
||||
// Make a ASSIGNW (expr, pin)
|
||||
AstNode* exprp = nodep->exprp()->cloneTree(false);
|
||||
if (exprp->width() != nodep->modVarp()->width())
|
||||
nodep->v3fatalSrc("Width mismatch, should have been handled in pinReconnectSimple\n");
|
||||
nodep->v3fatalSrc("Width mismatch, should have been handled in pinReconnectSimple");
|
||||
if (nodep->modVarp()->isInout()) {
|
||||
nodep->v3fatalSrc("Unsupported: Verilator is a 2-state simulator");
|
||||
} else if (nodep->modVarp()->isOutput()) {
|
||||
@@ -154,14 +154,10 @@ public:
|
||||
|
||||
//######################################################################
|
||||
|
||||
class InstDeVisitor : public AstNVisitor {
|
||||
// Find all cells with arrays, and convert to non-arrayed
|
||||
class InstDeModVarVisitor : public AstNVisitor {
|
||||
// Expand all module variables, and save names for later reference
|
||||
private:
|
||||
// STATE
|
||||
AstRange* m_cellRangep; // Range for arrayed instantiations, NULL for normal instantiations
|
||||
int m_instNum; // Current instantiation number
|
||||
int m_instLsb; // Current instantiation number
|
||||
|
||||
typedef map<string,AstVar*> VarNameMap;
|
||||
VarNameMap m_modVarNameMap; // Per module, name of cloned variables
|
||||
|
||||
@@ -172,15 +168,109 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
virtual void visit(AstVar* nodep) {
|
||||
if (nodep->dtypep()->castIfaceRefDType()) {
|
||||
UINFO(8," dm-1-VAR "<<nodep<<endl);
|
||||
insert(nodep);
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
// Save some time
|
||||
virtual void visit(AstNodeMath*) {}
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// METHODS
|
||||
void insert(AstVar* nodep) {
|
||||
UINFO(8," dmINSERT "<<nodep<<endl);
|
||||
m_modVarNameMap.insert(make_pair(nodep->name(), nodep));
|
||||
}
|
||||
AstVar* find(const string& name) {
|
||||
VarNameMap::iterator it = m_modVarNameMap.find(name);
|
||||
if (it != m_modVarNameMap.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
void dump() {
|
||||
for (VarNameMap::iterator it=m_modVarNameMap.begin(); it!=m_modVarNameMap.end(); ++it) {
|
||||
cout<<"-namemap: "<<it->first<<" -> "<<it->second<<endl;
|
||||
}
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
explicit InstDeModVarVisitor() {}
|
||||
void accept(AstNodeModule* nodep) {
|
||||
UINFO(8," dmMODULE "<<nodep<<endl);
|
||||
m_modVarNameMap.clear();
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~InstDeModVarVisitor() {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
class InstDeVisitor : public AstNVisitor {
|
||||
// Find all cells with arrays, and convert to non-arrayed
|
||||
private:
|
||||
// STATE
|
||||
AstRange* m_cellRangep; // Range for arrayed instantiations, NULL for normal instantiations
|
||||
int m_instNum; // Current instantiation number
|
||||
int m_instLsb; // Current instantiation number
|
||||
InstDeModVarVisitor m_deModVars; // State of variables for current cell module
|
||||
|
||||
typedef map<string,AstVar*> VarNameMap;
|
||||
|
||||
static int debug() {
|
||||
static int level = -1;
|
||||
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
|
||||
return level;
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstVar* nodep) {
|
||||
if (nodep->dtypep()->castUnpackArrayDType()
|
||||
&& nodep->dtypep()->castUnpackArrayDType()->subDTypep()->castIfaceRefDType()) {
|
||||
UINFO(8," dv-vec-VAR "<<nodep<<endl);
|
||||
AstUnpackArrayDType* arrdtype = nodep->dtypep()->castUnpackArrayDType();
|
||||
AstNode* prevp = NULL;
|
||||
for (int i = arrdtype->lsb(); i <= arrdtype->msb(); ++i) {
|
||||
string varNewName = nodep->name() + "__BRA__" + cvtToStr(i) + "__KET__";
|
||||
UINFO(8,"VAR name insert "<<varNewName<<" "<<nodep<<endl);
|
||||
if (!m_deModVars.find(varNewName)) {
|
||||
AstIfaceRefDType* ifaceRefp = arrdtype->subDTypep()->castIfaceRefDType()->cloneTree(false);
|
||||
arrdtype->addNextHere(ifaceRefp);
|
||||
ifaceRefp->cellp(NULL);
|
||||
|
||||
AstVar* varNewp = nodep->cloneTree(false);
|
||||
varNewp->name(varNewName);
|
||||
varNewp->origName(varNewp->origName() + "__BRA__" + cvtToStr(i) + "__KET__");
|
||||
varNewp->dtypep(ifaceRefp);
|
||||
m_deModVars.insert(varNewp);
|
||||
if (!prevp) {
|
||||
prevp = varNewp;
|
||||
} else {
|
||||
prevp->addNextHere(varNewp);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (prevp) nodep->addNextHere(prevp);
|
||||
if (prevp && debug()==9) { prevp->dumpTree(cout, "newintf: "); cout << endl; }
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
virtual void visit(AstCell* nodep) {
|
||||
UINFO(4," CELL "<<nodep<<endl);
|
||||
// Find submodule vars
|
||||
if (!nodep->modp()) nodep->v3fatalSrc("Unlinked");
|
||||
m_deModVars.accept(nodep->modp());
|
||||
//
|
||||
if (nodep->rangep()) {
|
||||
m_cellRangep = nodep->rangep();
|
||||
UINFO(4," CELL "<<nodep<<endl);
|
||||
|
||||
AstVar* ifaceVarp = nodep->nextp()->castVar();
|
||||
bool isIface = ifaceVarp
|
||||
@@ -199,9 +289,10 @@ private:
|
||||
// The spec says we add [x], but that won't work in C...
|
||||
newp->name(newp->name()+"__BRA__"+cvtToStr(m_instNum)+"__KET__");
|
||||
newp->origName(newp->origName()+"__BRA__"+cvtToStr(m_instNum)+"__KET__");
|
||||
UINFO(8," CELL loop "<<newp<<endl);
|
||||
|
||||
// If this AstCell is actually an interface instantiation, let's ensure we also clone
|
||||
// the IfaceRef.
|
||||
// If this AstCell is actually an interface instantiation, also clone the IfaceRef
|
||||
// within the same parent module as the cell
|
||||
if (isIface) {
|
||||
AstUnpackArrayDType* arrdtype = ifaceVarp->dtypep()->castUnpackArrayDType();
|
||||
AstIfaceRefDType* origIfaceRefp = arrdtype->subDTypep()->castIfaceRefDType();
|
||||
@@ -229,42 +320,11 @@ private:
|
||||
}
|
||||
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
} else {
|
||||
m_cellRangep = NULL;
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstVar* nodep) {
|
||||
bool isIface = nodep->dtypep()->castUnpackArrayDType()
|
||||
&& nodep->dtypep()->castUnpackArrayDType()->subDTypep()->castIfaceRefDType();
|
||||
if (isIface) {
|
||||
AstUnpackArrayDType* arrdtype = nodep->dtypep()->castUnpackArrayDType();
|
||||
AstNode* prev = NULL;
|
||||
for (int i = arrdtype->lsb(); i <= arrdtype->msb(); ++i) {
|
||||
AstIfaceRefDType* ifaceRefp = arrdtype->subDTypep()->castIfaceRefDType()->cloneTree(false);
|
||||
arrdtype->addNextHere(ifaceRefp);
|
||||
ifaceRefp->cellp(NULL);
|
||||
|
||||
string varNewName = nodep->name() + "__BRA__" + cvtToStr(i) + "__KET__";
|
||||
VarNameMap::iterator it = m_modVarNameMap.find(varNewName);
|
||||
if (it == m_modVarNameMap.end()) {
|
||||
AstVar* varNewp = nodep->cloneTree(false);
|
||||
m_modVarNameMap.insert(make_pair(varNewName, varNewp));
|
||||
varNewp->name(varNewName);
|
||||
varNewp->origName(varNewp->origName() + "__BRA__" + cvtToStr(i) + "__KET__");
|
||||
varNewp->dtypep(ifaceRefp);
|
||||
if (!prev) {
|
||||
prev = varNewp;
|
||||
} else {
|
||||
prev->addNextHere(varNewp);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (prev) nodep->addNextHere(prev);
|
||||
if (prev && debug()==9) { prev->dumpTree(cout, "newintf: "); cout << endl; }
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
virtual void visit(AstPin* nodep) {
|
||||
// Any non-direct pins need reconnection with a part-select
|
||||
if (!nodep->exprp()) return; // No-connect
|
||||
@@ -334,30 +394,28 @@ private:
|
||||
// Clone pin varp:
|
||||
for (int i = pinArrp->lsb(); i <= pinArrp->msb(); ++i) {
|
||||
string varNewName = pinVarp->name() + "__BRA__" + cvtToStr(i) + "__KET__";
|
||||
VarNameMap::iterator it = m_modVarNameMap.find(varNewName);
|
||||
AstVar* varNewp = NULL;
|
||||
|
||||
// Only clone the var once for each module
|
||||
// Only clone the var once for all usages of a given child module
|
||||
if (!pinVarp->backp()) {
|
||||
if (it != m_modVarNameMap.end()) {
|
||||
varNewp = it->second;
|
||||
}
|
||||
varNewp = m_deModVars.find(varNewName);
|
||||
} else {
|
||||
AstIfaceRefDType* ifaceRefp = pinArrp->subDTypep()->castIfaceRefDType();
|
||||
ifaceRefp->cellp(NULL);
|
||||
varNewp = pinVarp->cloneTree(false);
|
||||
m_modVarNameMap.insert(make_pair(varNewName, varNewp));
|
||||
varNewp->name(varNewName);
|
||||
varNewp->origName(varNewp->origName() + "__BRA__" + cvtToStr(i) + "__KET__");
|
||||
varNewp->dtypep(ifaceRefp);
|
||||
m_deModVars.insert(varNewp);
|
||||
if (!prevp) {
|
||||
prevp = varNewp;
|
||||
} else {
|
||||
prevp->addNextHere(varNewp);
|
||||
}
|
||||
}
|
||||
if (varNewp == NULL) {
|
||||
nodep->v3fatalSrc("Module dearray failed\n");
|
||||
if (!varNewp) {
|
||||
if (debug()>=9) m_deModVars.dump();
|
||||
nodep->v3fatalSrc("Module dearray failed for "<<AstNode::prettyName(varNewName));
|
||||
}
|
||||
|
||||
// But clone the pin for each module instance
|
||||
|
||||
+10
-6
@@ -445,6 +445,10 @@ public:
|
||||
<<") <- se"<<srcp<<" "<<srcp->nodep()<<endl);
|
||||
// srcp should be an interface reference pointing to the interface we want to import
|
||||
lhsp->importFromIface(symsp(), srcp);
|
||||
// Allow access to objects not permissible to be listed in a modport
|
||||
if (srcp->nodep()->castModport()) {
|
||||
lhsp->importFromIface(symsp(), srcp->parentp(), true);
|
||||
}
|
||||
}
|
||||
//m_scopeAliasMap[samn].clear(); // Done with it, but put into debug file
|
||||
}
|
||||
@@ -839,7 +843,7 @@ class LinkDotFindVisitor : public AstNVisitor {
|
||||
virtual void visit(AstNodeFTask* nodep) {
|
||||
// NodeTask: Remember its name for later resolution
|
||||
UINFO(5," "<<nodep<<endl);
|
||||
if (!m_curSymp || !m_modSymp) nodep->v3fatalSrc("Function/Task not under module??\n");
|
||||
if (!m_curSymp || !m_modSymp) nodep->v3fatalSrc("Function/Task not under module?");
|
||||
// Remember the existing symbol table scope
|
||||
VSymEnt* oldCurSymp = m_curSymp;
|
||||
{
|
||||
@@ -873,7 +877,7 @@ class LinkDotFindVisitor : public AstNVisitor {
|
||||
}
|
||||
virtual void visit(AstVar* nodep) {
|
||||
// Var: Remember its name for later resolution
|
||||
if (!m_curSymp || !m_modSymp) nodep->v3fatalSrc("Var not under module??\n");
|
||||
if (!m_curSymp || !m_modSymp) nodep->v3fatalSrc("Var not under module?");
|
||||
nodep->iterateChildren(*this);
|
||||
if (!m_statep->forScopeCreation()) {
|
||||
// Find under either a task or the module's vars
|
||||
@@ -957,12 +961,12 @@ class LinkDotFindVisitor : public AstNVisitor {
|
||||
}
|
||||
virtual void visit(AstTypedef* nodep) {
|
||||
// Remember its name for later resolution
|
||||
if (!m_curSymp) nodep->v3fatalSrc("Typedef not under module??\n");
|
||||
if (!m_curSymp) nodep->v3fatalSrc("Typedef not under module?");
|
||||
nodep->iterateChildren(*this);
|
||||
m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep);
|
||||
}
|
||||
virtual void visit(AstParamTypeDType* nodep) {
|
||||
if (!m_curSymp) nodep->v3fatalSrc("Parameter type not under module??\n");
|
||||
if (!m_curSymp) nodep->v3fatalSrc("Parameter type not under module?");
|
||||
nodep->iterateChildren(*this);
|
||||
m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep);
|
||||
}
|
||||
@@ -1593,7 +1597,7 @@ private:
|
||||
checkNoDot(nodep);
|
||||
nodep->iterateChildren(*this);
|
||||
if (!nodep->modVarp()) {
|
||||
if (!m_pinSymp) nodep->v3fatalSrc("Pin not under cell?\n");
|
||||
if (!m_pinSymp) nodep->v3fatalSrc("Pin not under cell?");
|
||||
VSymEnt* foundp = m_pinSymp->findIdFlat(nodep->name());
|
||||
const char* whatp = nodep->param() ? "parameter pin" : "pin";
|
||||
if (!foundp) {
|
||||
@@ -1861,7 +1865,7 @@ private:
|
||||
}
|
||||
//
|
||||
if (!ok) {
|
||||
//Cells/interfaces can't be implicit
|
||||
// Cells/interfaces can't be implicit
|
||||
bool isCell = foundp ? foundp->nodep()->castCell() != NULL : false;
|
||||
bool checkImplicit = (!m_ds.m_dotp && m_ds.m_dotText=="" && !isCell);
|
||||
bool err = !(checkImplicit && m_statep->implicitOk(m_modp, nodep->name()));
|
||||
|
||||
@@ -174,8 +174,10 @@ private:
|
||||
virtual void visit(AstValuePlusArgs* nodep) {
|
||||
bool last_setRefLvalue = m_setRefLvalue;
|
||||
{
|
||||
m_setRefLvalue = false;
|
||||
nodep->searchp()->iterateAndNext(*this);
|
||||
m_setRefLvalue = true;
|
||||
nodep->exprsp()->iterateAndNext(*this);
|
||||
nodep->outp()->iterateAndNext(*this);
|
||||
}
|
||||
m_setRefLvalue = last_setRefLvalue;
|
||||
}
|
||||
|
||||
@@ -236,12 +236,12 @@ private:
|
||||
|
||||
virtual void visit(AstPragma* nodep) {
|
||||
if (nodep->pragType() == AstPragmaType::PUBLIC_MODULE) {
|
||||
if (!m_modp) nodep->v3fatalSrc("PUBLIC_MODULE not under a module\n");
|
||||
if (!m_modp) nodep->v3fatalSrc("PUBLIC_MODULE not under a module");
|
||||
m_modp->modPublic(true);
|
||||
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
}
|
||||
else if (nodep->pragType() == AstPragmaType::PUBLIC_TASK) {
|
||||
if (!m_ftaskp) nodep->v3fatalSrc("PUBLIC_TASK not under a task\n");
|
||||
if (!m_ftaskp) nodep->v3fatalSrc("PUBLIC_TASK not under a task");
|
||||
m_ftaskp->taskPublic(true);
|
||||
m_modp->modPublic(true); // Need to get to the task...
|
||||
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
|
||||
+12
-6
@@ -48,7 +48,7 @@ V3Number::V3Number(VerilogStringLiteral, FileLine* fileline, const string& str)
|
||||
}
|
||||
}
|
||||
}
|
||||
opCleanThis();
|
||||
opCleanThis(true);
|
||||
}
|
||||
|
||||
V3Number::V3Number (FileLine* fileline, const char* sourcep) {
|
||||
@@ -254,7 +254,7 @@ V3Number::V3Number (FileLine* fileline, const char* sourcep) {
|
||||
setBit(obit, bitIs(obit-1));
|
||||
obit++;
|
||||
}
|
||||
opCleanThis();
|
||||
opCleanThis(true);
|
||||
|
||||
//printf("Dump \"%s\" CP \"%s\" B '%c' %d W %d\n", sourcep, value_startp, base, width(), m_value[0]);
|
||||
}
|
||||
@@ -1587,10 +1587,16 @@ V3Number& V3Number::opClean (const V3Number& lhs, uint32_t bits) {
|
||||
return opSel(lhs, bits-1, 0);
|
||||
}
|
||||
|
||||
void V3Number::opCleanThis() {
|
||||
// Clean in place number
|
||||
m_value[words()-1] &= hiWordMask();
|
||||
m_valueX[words()-1] &= hiWordMask();
|
||||
void V3Number::opCleanThis(bool warnOnTruncation) {
|
||||
// Clean MSB of number
|
||||
uint32_t newValueMsb = m_value[words()-1] & hiWordMask();
|
||||
uint32_t newValueXMsb = m_valueX[words()-1] & hiWordMask();
|
||||
if (warnOnTruncation && (newValueMsb != m_value[words()-1] || newValueXMsb != m_valueX[words()-1])) {
|
||||
// Displaying in decimal avoids hiWordMask truncation
|
||||
m_fileline->v3warn(WIDTH,"Value too large for "<<width()<<" bit number: "<<displayed(m_fileline, "%d"));
|
||||
}
|
||||
m_value[words()-1] = newValueMsb;
|
||||
m_valueX[words()-1] = newValueXMsb;
|
||||
}
|
||||
|
||||
V3Number& V3Number::opSel (const V3Number& lhs, const V3Number& msb, const V3Number& lsb) {
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ class V3Number {
|
||||
// METHODS
|
||||
V3Number& setSingleBits(char value);
|
||||
V3Number& setString(const string& str) { m_isString=true; m_stringVal=str; return *this; }
|
||||
void opCleanThis();
|
||||
void opCleanThis(bool warnOnTruncation = false);
|
||||
public:
|
||||
FileLine* fileline() const { return m_fileline; }
|
||||
void fileline(FileLine* fl) { m_fileline=fl; }
|
||||
|
||||
@@ -84,7 +84,7 @@ void test(string lhss, string op, string rhss, string exps) {
|
||||
V3Number ok (new FileLine("ck",__LINE__), 1);
|
||||
ok.opCaseEq(expnum,gotnum);
|
||||
if (ok.toUInt()!=1) {
|
||||
v3fatalSrc("%Error:Test FAILED\n");
|
||||
v3fatalSrc("%Error:Test FAILED");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -560,7 +560,7 @@ string V3Options::version() {
|
||||
|
||||
void V3Options::throwSigsegv() {
|
||||
// cppcheck-suppress nullPointer
|
||||
char* zp=NULL; *zp=0;
|
||||
char* zp=NULL; *zp=0; // Intentional core dump, ignore warnings here
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
@@ -607,7 +607,7 @@ bool V3Options::onoff(const char* sw, const char* arg, bool& flag) {
|
||||
// if sw=="-no-arg", then return true (found it), and flag=false
|
||||
// if sw=="-noarg", then return true (found it), and flag=false
|
||||
// else return false
|
||||
if (arg[0]!='-') v3fatalSrc("OnOff switches must have leading dash.\n");
|
||||
if (arg[0]!='-') v3fatalSrc("OnOff switches must have leading dash");
|
||||
if (0==strcmp(sw,arg)) { flag=true; return true; }
|
||||
else if (0==strncmp(sw,"-no",3) && (0==strcmp(sw+3,arg+1))) { flag=false; return true; }
|
||||
else if (0==strncmp(sw,"-no-",4) && (0==strcmp(sw+4,arg+1))) { flag=false; return true; }
|
||||
|
||||
+5
-5
@@ -194,7 +194,7 @@ public:
|
||||
// METHODS
|
||||
OrderVarVertex* newVarUserVertex(V3Graph* graphp, AstScope* scopep,
|
||||
AstVarScope* varscp, WhichVertex type, bool* createdp=NULL) {
|
||||
if (type>=WV_MAX) varscp->v3fatalSrc("Bad Case\n");
|
||||
if (type>=WV_MAX) varscp->v3fatalSrc("Bad case");
|
||||
OrderVarVertex* vertexp = m_vertexp[type];
|
||||
if (!vertexp) {
|
||||
UINFO(6,"New vertex "<<varscp<<endl);
|
||||
@@ -205,7 +205,7 @@ public:
|
||||
case WV_PORD: vertexp = new OrderVarPordVertex (graphp, scopep, varscp); break;
|
||||
case WV_POST: vertexp = new OrderVarPostVertex (graphp, scopep, varscp); break;
|
||||
case WV_SETL: vertexp = new OrderVarSettleVertex(graphp, scopep, varscp); break;
|
||||
default: varscp->v3fatalSrc("Bad Case\n");
|
||||
default: varscp->v3fatalSrc("Bad case");
|
||||
}
|
||||
m_vertexp[type] = vertexp;
|
||||
} else {
|
||||
@@ -806,15 +806,15 @@ private:
|
||||
virtual void visit(AstNodeVarRef* nodep) {
|
||||
if (m_scopep) {
|
||||
AstVarScope* varscp = nodep->varScopep();
|
||||
if (!varscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp\n");
|
||||
if (!varscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp");
|
||||
if (m_inSenTree) {
|
||||
// Add CLOCK dependency... This is a root of the tree we'll trace
|
||||
if (nodep->lvalue()) nodep->v3fatalSrc("How can a sensitivity be setting a var?\n");
|
||||
if (nodep->lvalue()) nodep->v3fatalSrc("How can a sensitivity be setting a var?");
|
||||
OrderVarVertex* varVxp = newVarUserVertex(varscp, WV_STD);
|
||||
varVxp->isClock(true);
|
||||
new OrderEdge(&m_graph, varVxp, m_activeSenVxp, WEIGHT_MEDIUM);
|
||||
} else {
|
||||
if (!m_logicVxp) nodep->v3fatalSrc("Var ref not under a logic block\n");
|
||||
if (!m_logicVxp) nodep->v3fatalSrc("Var ref not under a logic block");
|
||||
// What new directions is this used
|
||||
// We don't want to add extra edges if the logic block has many usages of same var
|
||||
bool gen = false;
|
||||
|
||||
+61
-3
@@ -204,7 +204,7 @@ private:
|
||||
pinp->modPTypep(cloneiter->second->castParamTypeDType());
|
||||
}
|
||||
else {
|
||||
pinp->v3fatalSrc("Not linked?\n");
|
||||
pinp->v3fatalSrc("Not linked?");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -283,7 +283,59 @@ private:
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
if (nodep->varp()) nodep->varp()->iterate(*this);
|
||||
}
|
||||
bool ifaceParamReplace(AstVarXRef* nodep, AstNode* candp) {
|
||||
for (; candp; candp = candp->nextp()) {
|
||||
if (nodep->name() == candp->name()) {
|
||||
if (AstVar* varp = candp->castVar()) {
|
||||
UINFO(9,"Found interface parameter: "<<varp<<endl);
|
||||
nodep->varp(varp);
|
||||
return true;
|
||||
} else if (AstPin* pinp = candp->castPin()) {
|
||||
UINFO(9,"Found interface parameter: "<<pinp<<endl);
|
||||
if (!pinp->exprp()) pinp->v3fatalSrc("Interface parameter pin missing expression");
|
||||
nodep->replaceWith(pinp->exprp()->cloneTree(false)); VL_DANGLING(nodep);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
virtual void visit(AstVarXRef* nodep) {
|
||||
// Check to see if the scope is just an interface because interfaces are special
|
||||
string dotted = nodep->dotted();
|
||||
if (!dotted.empty() && nodep->varp() && nodep->varp()->isParam()) {
|
||||
AstNode* backp = nodep;
|
||||
while ((backp = backp->backp())) {
|
||||
if (backp->castNodeModule()) {
|
||||
UINFO(9,"Hit module boundary, done looking for interface"<<endl);
|
||||
break;
|
||||
}
|
||||
if (backp->castVar()
|
||||
&& backp->castVar()->isIfaceRef()
|
||||
&& backp->castVar()->childDTypep()
|
||||
&& backp->castVar()->childDTypep()->castIfaceRefDType()) {
|
||||
AstIfaceRefDType* ifacerefp = backp->castVar()->childDTypep()->castIfaceRefDType();
|
||||
// Interfaces passed in on the port map have ifaces
|
||||
if (AstIface* ifacep = ifacerefp->ifacep()) {
|
||||
if (dotted == backp->name()) {
|
||||
UINFO(9,"Iface matching scope: "<<ifacep<<endl);
|
||||
if (ifaceParamReplace(nodep, ifacep->stmtsp())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Interfaces declared in this module have cells
|
||||
else if (AstCell* cellp = ifacerefp->cellp()) {
|
||||
if (dotted == cellp->name()) {
|
||||
UINFO(9,"Iface matching scope: "<<cellp<<endl);
|
||||
if (ifaceParamReplace(nodep, cellp->paramsp())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nodep->varp(NULL); // Needs relink, as may remove pointed-to var
|
||||
}
|
||||
|
||||
@@ -493,6 +545,12 @@ void ParamVisitor::visitCell(AstCell* nodep) {
|
||||
if (AstVar* modvarp = pinp->modVarp()) {
|
||||
if (!modvarp->isGParam()) {
|
||||
pinp->v3error("Attempted parameter setting of non-parameter: Param "<<pinp->prettyName()<<" of "<<nodep->prettyName());
|
||||
} else if (pinp->exprp()->castInitArray()
|
||||
&& modvarp->subDTypep()->castUnpackArrayDType()) {
|
||||
// Array assigned to array
|
||||
AstNode* exprp = pinp->exprp();
|
||||
longname += "_" + paramSmallName(nodep->modp(),modvarp)+paramValueNumber(exprp);
|
||||
any_overrides = true;
|
||||
} else {
|
||||
AstConst* exprp = pinp->exprp()->castConst();
|
||||
AstConst* origp = modvarp->valuep()->castConst();
|
||||
@@ -651,11 +709,11 @@ void ParamVisitor::visitCell(AstCell* nodep) {
|
||||
for (AstPin* pinp = nodep->paramsp(); pinp; pinp=pinp->nextp()->castPin()) {
|
||||
if (pinp->exprp()) {
|
||||
if (AstVar* modvarp = pinp->modVarp()) {
|
||||
AstConst* constp = pinp->exprp()->castConst();
|
||||
AstNode* newp = pinp->exprp(); // Const or InitArray
|
||||
// Remove any existing parameter
|
||||
if (modvarp->valuep()) modvarp->valuep()->unlinkFrBack()->deleteTree();
|
||||
// Set this parameter to value requested by cell
|
||||
modvarp->valuep(constp->cloneTree(false));
|
||||
modvarp->valuep(newp->cloneTree(false));
|
||||
}
|
||||
else if (AstParamTypeDType* modptp = pinp->modPTypep()) {
|
||||
AstNodeDType* dtypep = pinp->exprp()->castNodeDType();
|
||||
|
||||
@@ -44,12 +44,25 @@
|
||||
#include "V3Task.h"
|
||||
|
||||
#include <deque>
|
||||
#include <sstream>
|
||||
|
||||
//============================================================================
|
||||
|
||||
//######################################################################
|
||||
// Simulate class functions
|
||||
|
||||
class SimulateStackNode {
|
||||
public:
|
||||
// MEMBERS
|
||||
AstFuncRef* m_funcp;
|
||||
V3TaskConnects* m_tconnects;
|
||||
// CONSTRUCTORS
|
||||
SimulateStackNode(AstFuncRef* funcp, V3TaskConnects* tconnects):
|
||||
m_funcp(funcp),
|
||||
m_tconnects(tconnects) {}
|
||||
~SimulateStackNode() {}
|
||||
};
|
||||
|
||||
class SimulateVisitor : public AstNVisitor {
|
||||
// Simulate a node tree, returning value of variables
|
||||
// Two major operating modes:
|
||||
@@ -90,6 +103,7 @@ private:
|
||||
// Simulating:
|
||||
deque<V3Number*> m_numFreeps; ///< List of all numbers free and not in use
|
||||
deque<V3Number*> m_numAllps; ///< List of all numbers free and in use
|
||||
deque<SimulateStackNode*> m_callStack; ///< Call stack for verbose error messages
|
||||
|
||||
// Cleanup
|
||||
// V3Numbers that represents strings are a bit special and the API for V3Number does not allow changing them.
|
||||
@@ -103,6 +117,54 @@ private:
|
||||
return level;
|
||||
}
|
||||
|
||||
// Potentially very slow, intended for debugging
|
||||
string prettyNumber(V3Number* nump, AstNodeDType* dtypep) {
|
||||
if (AstRefDType* refdtypep = dtypep->castRefDType()) {
|
||||
dtypep = refdtypep->skipRefp();
|
||||
}
|
||||
if (AstStructDType* stp = dtypep->castStructDType()) {
|
||||
if (stp->packed()) {
|
||||
ostringstream out;
|
||||
out<<"'{";
|
||||
for (AstMemberDType* itemp = stp->membersp(); itemp; itemp=itemp->nextp()->castMemberDType()) {
|
||||
int width = itemp->width();
|
||||
int lsb = itemp->lsb();
|
||||
int msb = lsb + width - 1;
|
||||
V3Number fieldNum = V3Number(nump->fileline(), width);
|
||||
fieldNum.opSel(*nump, msb, lsb);
|
||||
out<<itemp->name()<<": ";
|
||||
if (AstNodeDType * childTypep = itemp->subDTypep()) {
|
||||
out<<prettyNumber(&fieldNum, childTypep);
|
||||
} else {
|
||||
out<<fieldNum;
|
||||
}
|
||||
if (itemp->nextp()) out<<", ";
|
||||
}
|
||||
out<<"}";
|
||||
return out.str();
|
||||
}
|
||||
} else if (AstPackArrayDType * arrayp = dtypep->castPackArrayDType()) {
|
||||
if (AstNodeDType * childTypep = arrayp->subDTypep()) {
|
||||
ostringstream out;
|
||||
out<<"[";
|
||||
int arrayElements = arrayp->elementsConst();
|
||||
for (int element = 0; element < arrayElements; ++element) {
|
||||
int width = childTypep->width();
|
||||
int lsb = width * element;
|
||||
int msb = lsb + width - 1;
|
||||
V3Number fieldNum = V3Number(nump->fileline(), width);
|
||||
fieldNum.opSel(*nump, msb, lsb);
|
||||
int arrayElem = arrayp->lsb() + element;
|
||||
out<<arrayElem<<" = "<<prettyNumber(&fieldNum, childTypep);
|
||||
if (element < arrayElements - 1) out<<", ";
|
||||
}
|
||||
out<<"]";
|
||||
return out.str();
|
||||
}
|
||||
}
|
||||
return nump->ascii();
|
||||
}
|
||||
|
||||
// Checking METHODS
|
||||
public:
|
||||
/// Call other-this function on all new *non-constant* var references
|
||||
@@ -119,6 +181,19 @@ public:
|
||||
cout<<endl;
|
||||
}
|
||||
m_whyNotOptimizable = why;
|
||||
ostringstream stack;
|
||||
for (deque<SimulateStackNode*>::iterator it=m_callStack.begin(); it !=m_callStack.end(); ++it) {
|
||||
AstFuncRef* funcp = (*it)->m_funcp;
|
||||
stack<<"\nCalled from:\n"<<funcp->fileline()<<" "<<funcp->prettyName()<<"() with parameters:";
|
||||
V3TaskConnects* tconnects = (*it)->m_tconnects;
|
||||
for (V3TaskConnects::iterator conIt = tconnects->begin(); conIt != tconnects->end(); ++conIt) {
|
||||
AstVar* portp = conIt->first;
|
||||
AstNode* pinp = conIt->second->exprp();
|
||||
AstNodeDType* dtypep = pinp->dtypep();
|
||||
stack<<"\n "<<portp->prettyName()<<" = "<<prettyNumber(fetchNumber(pinp), dtypep);
|
||||
}
|
||||
}
|
||||
m_whyNotOptimizable += stack.str();
|
||||
}
|
||||
}
|
||||
inline bool optimizable() const { return m_whyNotNodep==NULL; }
|
||||
@@ -718,8 +793,11 @@ private:
|
||||
}
|
||||
}
|
||||
}
|
||||
SimulateStackNode stackNode(nodep, &tconnects);
|
||||
m_callStack.push_front(&stackNode);
|
||||
// Evaluate the function
|
||||
funcp->accept(*this);
|
||||
m_callStack.pop_front();
|
||||
if (!m_checkOnly && optimizable()) {
|
||||
// Grab return value from output variable (if it's a function)
|
||||
if (!funcp->fvarp()) nodep->v3fatalSrc("Function reference points at non-function");
|
||||
|
||||
+4
-4
@@ -272,12 +272,12 @@ private:
|
||||
//UINFO(9," push "<<nodep<<endl);
|
||||
SplitLogicVertex* vertexp = new SplitLogicVertex(&m_graph, nodep);
|
||||
m_stmtStackps.push_back(vertexp);
|
||||
if (nodep->user3p()) nodep->v3fatalSrc("user3p should not be used; cleared in processBlock\n");
|
||||
if (nodep->user3p()) nodep->v3fatalSrc("user3p should not be used; cleared in processBlock");
|
||||
nodep->user3p(vertexp);
|
||||
}
|
||||
void scoreboardPopStmt() {
|
||||
//UINFO(9," pop"<<endl);
|
||||
if (m_stmtStackps.empty()) v3fatalSrc("Stack underflow\n");
|
||||
if (m_stmtStackps.empty()) v3fatalSrc("Stack underflow");
|
||||
m_stmtStackps.pop_back();
|
||||
}
|
||||
|
||||
@@ -346,8 +346,8 @@ private:
|
||||
SplitLogicVertex* vvertexp = (SplitLogicVertex*)nextp->user3p();
|
||||
vvertexp->splitColor(vvertexp->color());
|
||||
uint32_t color = vvertexp->splitColor();
|
||||
if (color >= numVertexes) nextp->v3fatalSrc("More colors than vertexes!\n");
|
||||
if (!color) nextp->v3fatalSrc("No node color assigned\n");
|
||||
if (color >= numVertexes) nextp->v3fatalSrc("More colors than vertexes");
|
||||
if (!color) nextp->v3fatalSrc("No node color assigned");
|
||||
if (lastOfColor[color]) {
|
||||
new SplitStrictEdge(&m_graph, lastOfColor[color], vvertexp);
|
||||
}
|
||||
|
||||
+8
-5
@@ -183,16 +183,19 @@ public:
|
||||
}
|
||||
return any;
|
||||
}
|
||||
void importFromIface(VSymGraph* graphp, const VSymEnt* srcp) {
|
||||
void importFromIface(VSymGraph* graphp, const VSymEnt* srcp, bool onlyUnmodportable = false) {
|
||||
// Import interface tokens from source symbol table into this symbol table, recursively
|
||||
UINFO(9, " importIf se"<<(void*)this<<" from se"<<(void*)srcp<<endl);
|
||||
for (IdNameMap::const_iterator it=srcp->m_idNameMap.begin(); it!=srcp->m_idNameMap.end(); ++it) {
|
||||
const string& name = it->first;
|
||||
VSymEnt* subSrcp = it->second;
|
||||
VSymEnt* subSymp = new VSymEnt(graphp, subSrcp);
|
||||
reinsert(name, subSymp);
|
||||
// And recurse to create children
|
||||
subSymp->importFromIface(graphp, subSrcp);
|
||||
AstVar* varp = subSrcp->nodep()->castVar();
|
||||
if (!onlyUnmodportable || (varp && varp->varType() == AstVarType::GPARAM)) {
|
||||
VSymEnt* subSymp = new VSymEnt(graphp, subSrcp);
|
||||
reinsert(name, subSymp);
|
||||
// And recurse to create children
|
||||
subSymp->importFromIface(graphp, subSrcp);
|
||||
}
|
||||
}
|
||||
}
|
||||
void cellErrorScopes(AstNode* lookp, string prettyName="") {
|
||||
|
||||
+2
-2
@@ -263,7 +263,7 @@ private:
|
||||
if (nodep->varp()->user2p()) { // It's being converted to a alias.
|
||||
UINFO(9, " relinkVar "<<(void*)nodep->varp()->user2p()<<" "<<nodep<<endl);
|
||||
AstVarScope* newvscp = nodep->varp()->user2p()->castVarScope();
|
||||
if (!newvscp) nodep->v3fatalSrc("Null?\n");
|
||||
if (!newvscp) nodep->v3fatalSrc("not linked");
|
||||
nodep->varScopep(newvscp);
|
||||
nodep->varp(nodep->varScopep()->varp());
|
||||
nodep->name(nodep->varp()->name());
|
||||
@@ -1147,7 +1147,7 @@ private:
|
||||
m_insStmtp = NULL; // Next thing should be new statement
|
||||
}
|
||||
virtual void visit(AstNodeFor* nodep) {
|
||||
nodep->v3fatalSrc("For statements should have been converted to while statements in V3Begin.cpp\n");
|
||||
nodep->v3fatalSrc("For statements should have been converted to while statements in V3Begin.cpp");
|
||||
}
|
||||
virtual void visit(AstNodeStmt* nodep) {
|
||||
m_insMode = IM_BEFORE;
|
||||
|
||||
+1
-1
@@ -387,7 +387,7 @@ private:
|
||||
} else if (basefromp->castConst()) {
|
||||
// If it's a PARAMETER[bit], then basefromp may be a constant instead of a varrefp
|
||||
} else {
|
||||
nodep->v3fatalSrc("No VarRef or Const under ArraySel\n");
|
||||
nodep->v3fatalSrc("No VarRef or Const under ArraySel");
|
||||
}
|
||||
// Find range of dtype we are selecting from
|
||||
int declElements = -1;
|
||||
|
||||
+20
-15
@@ -2094,8 +2094,9 @@ private:
|
||||
}
|
||||
virtual void visit(AstValuePlusArgs* nodep) {
|
||||
if (m_vup->prelim()) {
|
||||
userIterateAndNext(nodep->exprsp(), WidthVP(SELF,BOTH).p());
|
||||
nodep->dtypeSetSigned32(); // Spec says integer return
|
||||
userIterateAndNext(nodep->searchp(), WidthVP(SELF,BOTH).p());
|
||||
userIterateAndNext(nodep->outp(), WidthVP(SELF,BOTH).p());
|
||||
nodep->dtypeChgWidthSigned(32,1,AstNumeric::SIGNED); // Spec says integer return
|
||||
}
|
||||
}
|
||||
virtual void visit(AstUCStmt* nodep) {
|
||||
@@ -2136,7 +2137,8 @@ private:
|
||||
AstNodeDType* subDTypep = pinDTypep;
|
||||
int pinwidth = pinDTypep->width();
|
||||
int conwidth = conDTypep->width();
|
||||
if (conDTypep == pinDTypep) { // If match, we're golden
|
||||
if (conDTypep == pinDTypep // If match, we're golden
|
||||
|| similarDTypeRecurse(conDTypep, pinDTypep)) {
|
||||
userIterateAndNext(nodep->exprp(), WidthVP(subDTypep,FINAL).p());
|
||||
}
|
||||
else if (m_cellRangep) {
|
||||
@@ -2178,22 +2180,22 @@ private:
|
||||
}
|
||||
|
||||
// TODO Simple dtype checking, should be a more general check
|
||||
AstNodeArrayDType* loArrayp = exprDTypep->skipRefp()->castUnpackArrayDType();
|
||||
AstNodeArrayDType* hiArrayp = modDTypep->skipRefp()->castUnpackArrayDType();
|
||||
if (loArrayp && hiArrayp && loArrayp->subDTypep()->skipRefp()->castIfaceRefDType()
|
||||
&& loArrayp->declRange().elements() != hiArrayp->declRange().elements()) {
|
||||
int loSize = loArrayp->declRange().elements();
|
||||
int hiSize = hiArrayp->declRange().elements();
|
||||
AstNodeArrayDType* exprArrayp = exprDTypep->skipRefp()->castUnpackArrayDType();
|
||||
AstNodeArrayDType* modArrayp = modDTypep->skipRefp()->castUnpackArrayDType();
|
||||
if (exprArrayp && modArrayp && exprArrayp->subDTypep()->skipRefp()->castIfaceRefDType()
|
||||
&& exprArrayp->declRange().elements() != modArrayp->declRange().elements()) {
|
||||
int exprSize = exprArrayp->declRange().elements();
|
||||
int modSize = modArrayp->declRange().elements();
|
||||
nodep->v3error("Illegal "<<nodep->prettyOperatorName()<<","
|
||||
<<" mismatch between port which is an interface array of size "<<loSize<<","
|
||||
<<" and expression which is an interface array of size "<<hiSize<<".");
|
||||
<<" mismatch between port which is an interface array of size "<<modSize<<","
|
||||
<<" and expression which is an interface array of size "<<exprSize<<".");
|
||||
UINFO(1," Related lo: "<<modDTypep->skipRefp()<<endl);
|
||||
UINFO(1," Related hi: "<<exprDTypep->skipRefp()<<endl);
|
||||
} else if ((loArrayp && !hiArrayp && pinwidth != conwidth)
|
||||
|| (!loArrayp && hiArrayp && pinwidth != conwidth)) {
|
||||
} else if ((exprArrayp && !modArrayp && pinwidth != conwidth)
|
||||
|| (!exprArrayp && modArrayp && pinwidth != conwidth)) {
|
||||
nodep->v3error("Illegal "<<nodep->prettyOperatorName()<<","
|
||||
<<" mismatch between port which is"<<(loArrayp?"":" not")<<" an array,"
|
||||
<<" and expression which is"<<(hiArrayp?"":" not")<<" an array.");
|
||||
<<" mismatch between port which is"<<(modArrayp?"":" not")<<" an array,"
|
||||
<<" and expression which is"<<(exprArrayp?"":" not")<<" an array.");
|
||||
UINFO(1," Related lo: "<<modDTypep->skipRefp()<<endl);
|
||||
UINFO(1," Related hi: "<<exprDTypep->skipRefp()<<endl);
|
||||
}
|
||||
@@ -2909,6 +2911,9 @@ private:
|
||||
return false; // No change
|
||||
}
|
||||
|
||||
bool similarDTypeRecurse(AstNodeDType* node1p, AstNodeDType* node2p) {
|
||||
return node1p->skipRefp()->similarDType(node2p->skipRefp());
|
||||
}
|
||||
void iterateCheckFileDesc (AstNode* nodep, AstNode* underp, Stage stage) {
|
||||
if (stage != BOTH) nodep->v3fatalSrc("Bad call");
|
||||
// underp may change as a result of replacement
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ bool VlcOptions::onoff(const char* sw, const char* arg, bool& flag) {
|
||||
// if sw=="-no-arg", then return true (found it), and flag=false
|
||||
// if sw=="-noarg", then return true (found it), and flag=false
|
||||
// else return false
|
||||
if (arg[0]!='-') v3fatalSrc("OnOff switches must have leading dash.\n");
|
||||
if (arg[0]!='-') v3fatalSrc("OnOff switches must have leading dash.");
|
||||
if (0==strcmp(sw,arg)) { flag=true; return true; }
|
||||
else if (0==strncmp(sw,"-no",3) && (0==strcmp(sw+3,arg+1))) { flag=false; return true; }
|
||||
else if (0==strncmp(sw,"-no-",4) && (0==strcmp(sw+4,arg+1))) { flag=false; return true; }
|
||||
|
||||
+1
-1
@@ -873,7 +873,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
/* Attributes */
|
||||
/* Note simulators vary in support for "(* /_*something*_/ foo*)" where _ doesn't exist */
|
||||
<V95,V01,V05,VA5,S05,S09,S12,SAX>{
|
||||
"(*"({ws}|{crnl})*({id}|{escid}) { yymore(); yy_push_state(ATTRMODE); } // Doesn't match (*), but (* attr_spec
|
||||
"(*"({ws}|{crnl})*({id}|{escid}) { yymore(); yy_push_state(ATTRMODE); } /* Doesn't match (*), but (* attr_spec */
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
+2
-2
@@ -2710,12 +2710,12 @@ system_f_call<nodep>: // IEEE: system_tf_call (as func)
|
||||
| yD_SQRT '(' expr ')' { $$ = new AstSqrtD($1,$3); }
|
||||
| yD_SSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstSScanF($1,*$5,$3,$6); }
|
||||
| yD_STIME parenE { $$ = new AstSel($1,new AstTime($1),0,32); }
|
||||
| yD_SYSTEM '(' expr ')' { $$ = new AstSystemF($1,$3); }
|
||||
| yD_SYSTEM '(' expr ')' { $$ = new AstSystemF($1,$3); }
|
||||
| yD_TESTPLUSARGS '(' str ')' { $$ = new AstTestPlusArgs($1,*$3); }
|
||||
| yD_TIME parenE { $$ = new AstTime($1); }
|
||||
| yD_UNPACKED_DIMENSIONS '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_UNPK_DIMENSIONS,$3); }
|
||||
| yD_UNSIGNED '(' expr ')' { $$ = new AstUnsigned($1,$3); }
|
||||
| yD_VALUEPLUSARGS '(' str ',' expr ')' { $$ = new AstValuePlusArgs($1,*$3,$5); }
|
||||
| yD_VALUEPLUSARGS '(' expr ',' expr ')' { $$ = new AstValuePlusArgs($1,$3,$5); }
|
||||
;
|
||||
|
||||
exprOrDataType<nodep>: // expr | data_type: combined to prevent conflicts
|
||||
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003-2009 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.
|
||||
|
||||
compile (
|
||||
verilator_flags2 => ['--assert'],
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,33 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2016 by Wilson Snyder
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Outputs
|
||||
dout,
|
||||
// Inputs
|
||||
clk, sel, a, c
|
||||
);
|
||||
|
||||
input clk;
|
||||
input bit [3:0] sel;
|
||||
input bit [3:0] a;
|
||||
input bit c;
|
||||
output bit dout;
|
||||
|
||||
localparam logic DC = 1'b?;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
unique casez(sel)
|
||||
4'b0000: dout <= a[0];
|
||||
4'b001?: dout <= a[1];
|
||||
{1'b0, 1'b1, 1'b?, 1'b?}: dout <= a[2];
|
||||
{1'b1, 1'b?, 1'b?, DC}: dout <= a[3];
|
||||
default: dout <= '0;
|
||||
endcase
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003-2009 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.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,97 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty.
|
||||
//
|
||||
|
||||
module some_module (
|
||||
input wrclk
|
||||
);
|
||||
|
||||
logic [ 1 : 0 ] some_state;
|
||||
logic [1:0] some_other_state;
|
||||
|
||||
always @(posedge wrclk) begin
|
||||
case (some_state)
|
||||
2'b11:
|
||||
if (some_other_state == 0)
|
||||
some_state <= 2'b00;
|
||||
default:
|
||||
$display ("This is a display statement");
|
||||
endcase
|
||||
|
||||
if (wrclk)
|
||||
some_other_state <= 0;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
`define BROKEN
|
||||
|
||||
module t1(
|
||||
input [3:0] i_clks,
|
||||
input i_clk0,
|
||||
input i_clk1
|
||||
);
|
||||
|
||||
some_module
|
||||
some_module
|
||||
(
|
||||
`ifdef BROKEN
|
||||
.wrclk (i_clks[3])
|
||||
`else
|
||||
.wrclk (i_clk1)
|
||||
`endif
|
||||
);
|
||||
endmodule
|
||||
|
||||
module t2(
|
||||
input [2:0] i_clks,
|
||||
input i_clk0,
|
||||
input i_clk1,
|
||||
input i_clk2,
|
||||
input i_data
|
||||
);
|
||||
logic [3:0] the_clks;
|
||||
logic data_q;
|
||||
|
||||
assign the_clks = {i_clk1, i_clk2, i_clk1, i_clk0};
|
||||
|
||||
always @(posedge i_clk0) begin
|
||||
data_q <= i_data;
|
||||
end
|
||||
|
||||
t1 t1
|
||||
(
|
||||
.i_clks (the_clks),
|
||||
.i_clk0 (i_clk0),
|
||||
.i_clk1 (i_clk1)
|
||||
);
|
||||
endmodule
|
||||
|
||||
module t(
|
||||
input clk0 /*verilator clocker*/,
|
||||
input clk1 /*verilator clocker*/,
|
||||
input clk2 /*verilator clocker*/,
|
||||
input data_in
|
||||
);
|
||||
|
||||
logic [2:0] clks;
|
||||
|
||||
assign clks = {1'b0, clk1, clk0};
|
||||
|
||||
t2
|
||||
t2
|
||||
(
|
||||
.i_clks (clks),
|
||||
.i_clk0 (clk0),
|
||||
.i_clk1 (clk1),
|
||||
.i_clk2 (clk2),
|
||||
.i_data (data_in)
|
||||
);
|
||||
|
||||
initial begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003-2009 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.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,106 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty.
|
||||
//
|
||||
|
||||
module some_module (
|
||||
input wrclk
|
||||
);
|
||||
|
||||
logic [ 1 : 0 ] some_state;
|
||||
logic [1:0] some_other_state;
|
||||
|
||||
always @(posedge wrclk) begin
|
||||
case (some_state)
|
||||
2'b11:
|
||||
if (some_other_state == 0)
|
||||
some_state <= 2'b00;
|
||||
default:
|
||||
$display ("This is a display statement");
|
||||
endcase
|
||||
|
||||
if (wrclk)
|
||||
some_other_state <= 0;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
`define BROKEN
|
||||
|
||||
module t1(
|
||||
input [3:0] i_clks,
|
||||
input i_clk0,
|
||||
input i_clk1
|
||||
);
|
||||
|
||||
some_module
|
||||
some_module
|
||||
(
|
||||
`ifdef BROKEN
|
||||
.wrclk (i_clks[3])
|
||||
`else
|
||||
.wrclk (i_clk1)
|
||||
`endif
|
||||
);
|
||||
endmodule
|
||||
|
||||
module t2(
|
||||
input [2:0] i_clks,
|
||||
input i_clk0,
|
||||
input i_clk1,
|
||||
input i_clk2,
|
||||
input i_data
|
||||
);
|
||||
logic [3:0] the_clks;
|
||||
logic data_q;
|
||||
|
||||
assign the_clks[3] = i_clk1;
|
||||
assign the_clks[2] = i_clk2;
|
||||
assign the_clks[1] = i_clk1;
|
||||
assign the_clks[0] = i_clk0;
|
||||
|
||||
always @(posedge i_clk0) begin
|
||||
data_q <= i_data;
|
||||
end
|
||||
|
||||
t1 t1
|
||||
(
|
||||
.i_clks (the_clks),
|
||||
.i_clk0 (i_clk0),
|
||||
.i_clk1 (i_clk1)
|
||||
);
|
||||
endmodule
|
||||
|
||||
module t(
|
||||
/*AUTOARG*/
|
||||
// Inputs
|
||||
clk /*verilator clocker*/,
|
||||
input clk0 /*verilator clocker*/,
|
||||
input clk1 /*verilator clocker*/,
|
||||
input clk2 /*verilator clocker*/,
|
||||
input data_in
|
||||
);
|
||||
|
||||
input clk;
|
||||
|
||||
logic [2:0] clks;
|
||||
|
||||
assign clks = {1'b0, clk1, clk0};
|
||||
|
||||
t2
|
||||
t2
|
||||
(
|
||||
.i_clks (clks),
|
||||
.i_clk0 (clk0),
|
||||
.i_clk1 (clk),
|
||||
.i_clk2 (clk2),
|
||||
.i_data (data_in)
|
||||
);
|
||||
|
||||
always @(posedge clk) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003-2009 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.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,101 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty.
|
||||
//
|
||||
|
||||
/* verilator lint_off LITENDIAN */
|
||||
module some_module (
|
||||
input wrclk
|
||||
);
|
||||
|
||||
logic [ 1 : 0 ] some_state;
|
||||
logic [1:0] some_other_state;
|
||||
|
||||
always @(posedge wrclk) begin
|
||||
case (some_state)
|
||||
2'b11:
|
||||
if (some_other_state == 0)
|
||||
some_state <= 2'b00;
|
||||
default:
|
||||
$display ("This is a display statement");
|
||||
endcase
|
||||
|
||||
if (wrclk)
|
||||
some_other_state <= 0;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
`define BROKEN
|
||||
|
||||
module t1(
|
||||
input [-12:-9] i_clks,
|
||||
input i_clk0,
|
||||
input i_clk1
|
||||
);
|
||||
|
||||
some_module
|
||||
some_module
|
||||
(
|
||||
`ifdef BROKEN
|
||||
.wrclk (i_clks[-12])
|
||||
`else
|
||||
.wrclk (i_clk1)
|
||||
`endif
|
||||
);
|
||||
endmodule
|
||||
|
||||
module t2(
|
||||
input [2:0] i_clks,
|
||||
input i_clk0,
|
||||
input i_clk1,
|
||||
input i_clk2,
|
||||
input i_data
|
||||
);
|
||||
logic [-12:-9] the_clks;
|
||||
logic data_q;
|
||||
|
||||
assign the_clks[-12] = i_clk1;
|
||||
assign the_clks[-11] = i_clk2;
|
||||
assign the_clks[-10] = i_clk1;
|
||||
assign the_clks[-9] = i_clk0;
|
||||
|
||||
always @(posedge i_clk0) begin
|
||||
data_q <= i_data;
|
||||
end
|
||||
|
||||
t1 t1
|
||||
(
|
||||
.i_clks (the_clks),
|
||||
.i_clk0 (i_clk0),
|
||||
.i_clk1 (i_clk1)
|
||||
);
|
||||
endmodule
|
||||
|
||||
module t(
|
||||
input clk0 /*verilator clocker*/,
|
||||
input clk1 /*verilator clocker*/,
|
||||
input clk2 /*verilator clocker*/,
|
||||
input data_in
|
||||
);
|
||||
|
||||
logic [2:0] clks;
|
||||
|
||||
assign clks = {1'b0, clk1, clk0};
|
||||
|
||||
t2
|
||||
t2
|
||||
(
|
||||
.i_clks (clks),
|
||||
.i_clk0 (clk0),
|
||||
.i_clk1 (clk1),
|
||||
.i_clk2 (clk2),
|
||||
.i_data (data_in)
|
||||
);
|
||||
|
||||
initial begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003-2009 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.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,105 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty.
|
||||
//
|
||||
|
||||
module some_module (
|
||||
input wrclk
|
||||
);
|
||||
|
||||
logic [ 1 : 0 ] some_state;
|
||||
logic [1:0] some_other_state;
|
||||
|
||||
always @(posedge wrclk) begin
|
||||
case (some_state)
|
||||
2'b11:
|
||||
if (some_other_state == 0)
|
||||
some_state <= 2'b00;
|
||||
default:
|
||||
$display ("This is a display statement");
|
||||
endcase
|
||||
|
||||
if (wrclk)
|
||||
some_other_state <= 0;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
`define BROKEN
|
||||
|
||||
module t1(
|
||||
input [3:0] i_clks,
|
||||
input i_clk0,
|
||||
input i_clk1
|
||||
);
|
||||
|
||||
generate
|
||||
genvar i;
|
||||
for (i = 0; i < 2; i = i + 1) begin: a_generate_block
|
||||
some_module
|
||||
some_module
|
||||
(
|
||||
`ifdef BROKEN
|
||||
.wrclk (i_clks[3])
|
||||
`else
|
||||
.wrclk (i_clk1)
|
||||
`endif
|
||||
);
|
||||
end
|
||||
endgenerate
|
||||
endmodule
|
||||
|
||||
module t2(
|
||||
input [2:0] i_clks,
|
||||
input i_clk0,
|
||||
input i_clk1,
|
||||
input i_clk2,
|
||||
input i_data
|
||||
);
|
||||
logic [3:0] the_clks;
|
||||
logic data_q;
|
||||
|
||||
assign the_clks[3] = i_clk1;
|
||||
assign the_clks[2] = i_clk2;
|
||||
assign the_clks[1] = i_clk1;
|
||||
assign the_clks[0] = i_clk0;
|
||||
|
||||
always @(posedge i_clk0) begin
|
||||
data_q <= i_data;
|
||||
end
|
||||
|
||||
t1 t1
|
||||
(
|
||||
.i_clks (the_clks),
|
||||
.i_clk0 (i_clk0),
|
||||
.i_clk1 (i_clk1)
|
||||
);
|
||||
endmodule
|
||||
|
||||
module t(
|
||||
input clk0 /*verilator clocker*/,
|
||||
input clk1 /*verilator clocker*/,
|
||||
input clk2 /*verilator clocker*/,
|
||||
input data_in
|
||||
);
|
||||
|
||||
logic [2:0] clks;
|
||||
|
||||
assign clks = {1'b0, clk1, clk0};
|
||||
|
||||
t2
|
||||
t2
|
||||
(
|
||||
.i_clks (clks),
|
||||
.i_clk0 (clk0),
|
||||
.i_clk1 (clk1),
|
||||
.i_clk2 (clk2),
|
||||
.i_data (data_in)
|
||||
);
|
||||
|
||||
initial begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003-2009 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.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,104 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty.
|
||||
//
|
||||
|
||||
module some_module (
|
||||
input [3:0] i_clks
|
||||
);
|
||||
|
||||
logic [ 1 : 0 ] some_state;
|
||||
logic [1:0] some_other_state;
|
||||
|
||||
always @(posedge i_clks[3]) begin
|
||||
case (some_state)
|
||||
2'b11:
|
||||
if (some_other_state == 0)
|
||||
some_state <= 2'b00;
|
||||
default:
|
||||
$display ("This is a display statement");
|
||||
endcase
|
||||
|
||||
if (i_clks[3])
|
||||
some_other_state <= 0;
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
`define BROKEN
|
||||
|
||||
module t1(
|
||||
input [3:0] i_clks,
|
||||
input i_clk0,
|
||||
input i_clk1
|
||||
);
|
||||
|
||||
some_module
|
||||
some_module
|
||||
(
|
||||
.i_clks (i_clks)
|
||||
);
|
||||
endmodule
|
||||
|
||||
module t2(
|
||||
input [2:0] i_clks,
|
||||
input i_clk0,
|
||||
input i_clk1,
|
||||
input i_clk2,
|
||||
input i_data
|
||||
);
|
||||
logic [3:0] the_clks;
|
||||
logic data_q;
|
||||
|
||||
assign the_clks[3] = i_clk1;
|
||||
assign the_clks[2] = i_clk2;
|
||||
assign the_clks[1] = i_clk1;
|
||||
assign the_clks[0] = i_clk0;
|
||||
|
||||
always @(posedge i_clk0) begin
|
||||
data_q <= i_data;
|
||||
end
|
||||
|
||||
t1 t1
|
||||
(
|
||||
.i_clks (the_clks),
|
||||
.i_clk0 (i_clk0),
|
||||
.i_clk1 (i_clk1)
|
||||
);
|
||||
endmodule
|
||||
|
||||
module t(
|
||||
/*AUTOARG*/
|
||||
// Inputs
|
||||
clk /*verilator clocker*/,
|
||||
input clk0 /*verilator clocker*/,
|
||||
input clk1 /*verilator clocker*/,
|
||||
input clk2 /*verilator clocker*/,
|
||||
input data_in
|
||||
);
|
||||
|
||||
input clk;
|
||||
|
||||
logic [2:0] clks;
|
||||
|
||||
assign clks = {1'b0, clk1, clk0};
|
||||
|
||||
t2
|
||||
t2
|
||||
(
|
||||
.i_clks (clks),
|
||||
.i_clk0 (clk0),
|
||||
.i_clk1 (clk),
|
||||
.i_clk2 (clk2),
|
||||
.i_data (data_in)
|
||||
);
|
||||
|
||||
// initial begin
|
||||
// $write("*-* All Finished *-*\n");
|
||||
// $finish;
|
||||
// end
|
||||
endmodule
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003-2009 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.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,113 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty.
|
||||
//
|
||||
|
||||
module some_module (
|
||||
input [3:0] i_clks
|
||||
);
|
||||
|
||||
logic [ 1 : 0 ] some_state;
|
||||
logic [1:0] some_other_state;
|
||||
logic the_clk;
|
||||
|
||||
assign the_clk = i_clks[3];
|
||||
|
||||
always @(posedge the_clk) begin
|
||||
case (some_state)
|
||||
2'b11:
|
||||
if (some_other_state == 0)
|
||||
some_state <= 2'b00;
|
||||
default:
|
||||
$display ("This is a display statement");
|
||||
endcase
|
||||
|
||||
if (the_clk)
|
||||
some_other_state <= 0;
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
`define BROKEN
|
||||
|
||||
module t1(
|
||||
input [3:0] i_clks,
|
||||
input i_clk0,
|
||||
input i_clk1
|
||||
);
|
||||
|
||||
some_module
|
||||
some_module
|
||||
(
|
||||
.i_clks (i_clks)
|
||||
);
|
||||
endmodule
|
||||
|
||||
module ident(
|
||||
input i_ident,
|
||||
output o_ident
|
||||
);
|
||||
assign o_ident = i_ident;
|
||||
endmodule
|
||||
|
||||
module t2(
|
||||
input [2:0] i_clks,
|
||||
input i_clk0,
|
||||
input i_clk1,
|
||||
input i_clk2,
|
||||
input i_data
|
||||
);
|
||||
logic [3:0] the_clks;
|
||||
logic data_q;
|
||||
logic ident_clk1;
|
||||
|
||||
always @(posedge i_clk0) begin
|
||||
data_q <= i_data;
|
||||
end
|
||||
|
||||
ident
|
||||
ident
|
||||
(
|
||||
.i_ident (i_clk1),
|
||||
.o_ident (ident_clk1)
|
||||
);
|
||||
|
||||
t1 t1
|
||||
(
|
||||
.i_clks ({ident_clk1, i_clk2, ident_clk1, i_clk0}),
|
||||
.i_clk0 (i_clk0),
|
||||
.i_clk1 (i_clk1)
|
||||
);
|
||||
endmodule
|
||||
|
||||
module t(
|
||||
/*AUTOARG*/
|
||||
// Inputs
|
||||
clk /*verilator clocker*/ /*verilator public_flat*/,
|
||||
input clk0 /*verilator clocker*/,
|
||||
input clk1 /*verilator clocker*/,
|
||||
input clk2 /*verilator clocker*/,
|
||||
input data_in
|
||||
);
|
||||
|
||||
input clk;
|
||||
|
||||
logic [2:0] clks;
|
||||
|
||||
assign clks = {1'b0, clk1, clk0};
|
||||
|
||||
t2
|
||||
t2
|
||||
(
|
||||
.i_clks (clks),
|
||||
.i_clk0 (clk0),
|
||||
.i_clk1 (clk),
|
||||
.i_clk2 (clk2),
|
||||
.i_data (data_in)
|
||||
);
|
||||
|
||||
endmodule
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2017 by Todd Strader. 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.
|
||||
#
|
||||
compile (
|
||||
v_flags2 => ["--lint-only"],
|
||||
fails=>1,
|
||||
expect=>
|
||||
q{%Warning-USERFATAL: f_add = 15
|
||||
%Warning-USERFATAL: Use "/* verilator lint_off USERFATAL */" and lint_on around source to disable this message.
|
||||
%Error: t/t_func_const2_bad.v:10: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_add2'
|
||||
%Error: t/t_func_const2_bad.v:21: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing
|
||||
Called from:
|
||||
t/t_func_const2_bad.v:26: f_add() with parameters:
|
||||
a = 32'h7
|
||||
b = 32'h8
|
||||
Called from:
|
||||
t/t_func_const2_bad.v:10: f_add2() with parameters:
|
||||
a = ?32?sh7
|
||||
b = ?32?sh8
|
||||
c = ?32?sh9
|
||||
},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,28 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2017 by Todd Strader.
|
||||
|
||||
module t;
|
||||
|
||||
localparam P6 = f_add(5, 1);
|
||||
localparam P14 = f_add2(2, 3, f_add(4, 5));
|
||||
localparam P24 = f_add2(7, 8, 9);
|
||||
|
||||
initial begin
|
||||
// Should never get here
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
function integer f_add(input [31:0] a, input [31:0] b);
|
||||
f_add = a+b;
|
||||
if (f_add == 15)
|
||||
$fatal(2, "f_add = 15");
|
||||
endfunction
|
||||
|
||||
// Speced ok: function called from function
|
||||
function integer f_add2(input [31:0] a, input [31:0] b, input [31:0] c);
|
||||
f_add2 = f_add(a,b)+c;
|
||||
endfunction
|
||||
endmodule
|
||||
@@ -11,24 +11,39 @@ compile (
|
||||
v_flags2 => ["--lint-only"],
|
||||
fails=>1,
|
||||
expect=>
|
||||
q{%Error: t/t_func_const_bad.v:\d+: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_output'
|
||||
%Error: t/t_func_const_bad.v:\d+: ... Location of non-constant VAR 'o': Language violation: Outputs not allowed in constant functions
|
||||
%Error: t/t_func_const_bad.v:\d+: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_dotted'
|
||||
%Error: t/t_func_const_bad.v:\d+: ... Location of non-constant VARXREF 'EIGHT': Language violation: Dotted hierarchical references not allowed in constant functions
|
||||
%Error: t/t_func_const_bad.v:\d+: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_nonparam'
|
||||
%Error: t/t_func_const_bad.v:\d+: ... Location of non-constant VARREF 'modvar': Language violation: reference to non-function-local variable
|
||||
%Error: t/t_func_const_bad.v:\d+: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_infinite'
|
||||
%Error: t/t_func_const_bad.v:\d+: ... Location of non-constant WHILE: Loop unrolling took too long; probably this is an infinite loop, or set --unroll-count above 1024
|
||||
%Error: t/t_func_const_bad.v:\d+: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_stop'
|
||||
%Error: t/t_func_const_bad.v:\d+: ... Location of non-constant STOP: .stop executed during function constification; maybe indicates assertion firing
|
||||
q{%Error: t/t_func_const_bad.v:11: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_output'
|
||||
%Error: t/t_func_const_bad.v:12: ... Location of non-constant VAR 'o': Language violation: Outputs not allowed in constant functions
|
||||
%Error: t/t_func_const_bad.v:20: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_dotted'
|
||||
%Error: t/t_func_const_bad.v:22: ... Location of non-constant VARXREF 'EIGHT': Language violation: Dotted hierarchical references not allowed in constant functions
|
||||
Called from:
|
||||
t/t_func_const_bad.v:20: f_bad_dotted() with parameters:
|
||||
a = ?32?sh2
|
||||
%Error: t/t_func_const_bad.v:27: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_nonparam'
|
||||
%Error: t/t_func_const_bad.v:29: ... Location of non-constant VARREF 'modvar': Language violation: reference to non-function-local variable
|
||||
Called from:
|
||||
t/t_func_const_bad.v:27: f_bad_nonparam() with parameters:
|
||||
a = ?32?sh3
|
||||
%Error: t/t_func_const_bad.v:35: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_infinite'
|
||||
%Error: t/t_func_const_bad.v:37: ... Location of non-constant WHILE: Loop unrolling took too long; probably this is an infinite loop, or set --unroll-count above 1024
|
||||
Called from:
|
||||
t/t_func_const_bad.v:35: f_bad_infinite() with parameters:
|
||||
a = ?32?sh3
|
||||
%Error: t/t_func_const_bad.v:43: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_stop'
|
||||
%Error: t/t_func_const_bad.v:45: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing
|
||||
Called from:
|
||||
t/t_func_const_bad.v:43: f_bad_stop() with parameters:
|
||||
a = ?32?sh3
|
||||
-Info: Printing in loop: 0
|
||||
-Info: Printing in loop: 1
|
||||
-Info: Printing in loop: 2
|
||||
%Warning-USERFATAL: Fatal Error
|
||||
%Warning-USERFATAL: Use ... verilator lint_off USERFATAL ... and lint_on around source to disable this message.
|
||||
%Error: t/t_func_const_bad.v:\d+: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_fatal'
|
||||
%Error: t/t_func_const_bad.v:\d+: ... Location of non-constant STOP: .stop executed during function constification; maybe indicates assertion firing
|
||||
%Error: Exiting due to.*},
|
||||
%Warning-USERFATAL: Use "/* verilator lint_off USERFATAL */" and lint_on around source to disable this message.
|
||||
%Error: t/t_func_const_bad.v:49: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_fatal'
|
||||
%Error: t/t_func_const_bad.v:54: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing
|
||||
Called from:
|
||||
t/t_func_const_bad.v:49: f_bad_fatal() with parameters:
|
||||
a = ?32?sh3
|
||||
},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2017 by Todd Strader. 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.
|
||||
#
|
||||
compile (
|
||||
v_flags2 => ["--lint-only"],
|
||||
fails=>1,
|
||||
expect=>
|
||||
q{%Warning-USERFATAL: f_add = 15
|
||||
%Warning-USERFATAL: Use "/* verilator lint_off USERFATAL */" and lint_on around source to disable this message.
|
||||
%Error: t/t_func_const_packed_array_bad.v:11: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_add2'
|
||||
%Error: t/t_func_const_packed_array_bad.v:22: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing
|
||||
Called from:
|
||||
t/t_func_const_packed_array_bad.v:30: f_add() with parameters:
|
||||
params = [0 = 32'h7, 1 = 32'h8]
|
||||
Called from:
|
||||
t/t_func_const_packed_array_bad.v:11: f_add2() with parameters:
|
||||
a = ?32?sh7
|
||||
b = ?32?sh8
|
||||
c = ?32?sh9
|
||||
},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,32 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2017 by Todd Strader.
|
||||
|
||||
module t;
|
||||
|
||||
localparam [ 1 : 0 ] [ 31 : 0 ] P = {32'd5, 32'd1};
|
||||
localparam P6 = f_add(P);
|
||||
localparam P14 = f_add2(2, 3, f_add(P));
|
||||
localparam P24 = f_add2(7, 8, 9);
|
||||
|
||||
initial begin
|
||||
// Should never get here
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
function integer f_add(input [ 1 : 0 ] [ 31 : 0 ] params);
|
||||
f_add = params[0]+params[1];
|
||||
if (f_add == 15)
|
||||
$fatal(2, "f_add = 15");
|
||||
endfunction
|
||||
|
||||
// Speced ok: function called from function
|
||||
function integer f_add2(input [31:0] a, input [31:0] b, input [31:0] c);
|
||||
logic [ 1 : 0 ] [ 31 : 0 ] params;
|
||||
params[0] = a;
|
||||
params[1] = b;
|
||||
f_add2 = f_add(params)+c;
|
||||
endfunction
|
||||
endmodule
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2017 by Todd Strader. 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.
|
||||
#
|
||||
compile (
|
||||
v_flags2 => ["--lint-only"],
|
||||
fails=>1,
|
||||
expect=>
|
||||
q{%Warning-USERFATAL: f_add = 15
|
||||
%Warning-USERFATAL: Use "/* verilator lint_off USERFATAL */" and lint_on around source to disable this message.
|
||||
%Error: t/t_func_const_packed_struct_bad.v:13: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_add2'
|
||||
%Error: t/t_func_const_packed_struct_bad.v:24: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing
|
||||
Called from:
|
||||
t/t_func_const_packed_struct_bad.v:32: f_add() with parameters:
|
||||
params = [0 = '{a: 32'h7, b: 32'h22b}, 1 = '{a: 32'h3039, b: 32'h8}]
|
||||
Called from:
|
||||
t/t_func_const_packed_struct_bad.v:13: f_add2() with parameters:
|
||||
a = ?32?sh7
|
||||
b = ?32?sh8
|
||||
c = ?32?sh9
|
||||
},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,34 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2017 by Todd Strader.
|
||||
|
||||
module t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [ 31 : 0 ] a;
|
||||
logic [ 31 : 0 ] b;
|
||||
} params_t;
|
||||
|
||||
localparam P24 = f_add2(7, 8, 9);
|
||||
|
||||
initial begin
|
||||
// Should never get here
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
function integer f_add(input params_t [ 1 : 0 ] params);
|
||||
f_add = params[0].a+params[1].b;
|
||||
if (f_add == 15)
|
||||
$fatal(2, "f_add = 15");
|
||||
endfunction
|
||||
|
||||
// Speced ok: function called from function
|
||||
function integer f_add2(input [31:0] a, input [31:0] b, input [31:0] c);
|
||||
params_t [ 1 : 0 ] params;
|
||||
params[0] = '{a:a, b:555};
|
||||
params[1] = '{a:12345, b:b};
|
||||
f_add2 = f_add(params)+c;
|
||||
endfunction
|
||||
endmodule
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2017 by Todd Strader. 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.
|
||||
#
|
||||
compile (
|
||||
v_flags2 => ["--lint-only"],
|
||||
fails=>1,
|
||||
expect=>
|
||||
q{%Warning-USERFATAL: f_add = 15
|
||||
%Warning-USERFATAL: Use "/* verilator lint_off USERFATAL */" and lint_on around source to disable this message.
|
||||
%Error: t/t_func_const_packed_struct_bad2.v:19: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_add2'
|
||||
%Error: t/t_func_const_packed_struct_bad2.v:30: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing
|
||||
Called from:
|
||||
t/t_func_const_packed_struct_bad2.v:42: f_add() with parameters:
|
||||
params = [0 = '{a: 32'h7, foo: 6'hb, sub_params: '{b: 32'h37, bar: 8'h6f}}, 1 = '{a: 32'h3039, foo: 6'hc, sub_params: '{b: 32'h8, bar: 8'h70}}]
|
||||
Called from:
|
||||
t/t_func_const_packed_struct_bad2.v:19: f_add2() with parameters:
|
||||
a = ?32?sh7
|
||||
b = ?32?sh8
|
||||
c = ?32?sh9
|
||||
},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,44 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2017 by Todd Strader.
|
||||
|
||||
module t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [ 31 : 0 ] b;
|
||||
logic [ 7 : 0 ] bar;
|
||||
} sub_params_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [ 31 : 0 ] a;
|
||||
logic [ 5 : 0 ] foo;
|
||||
sub_params_t sub_params;
|
||||
} params_t;
|
||||
|
||||
localparam P24 = f_add2(7, 8, 9);
|
||||
|
||||
initial begin
|
||||
// Should never get here
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
function integer f_add(input params_t [ 1 : 0 ] params);
|
||||
f_add = params[0].a+params[1].sub_params.b;
|
||||
if (f_add == 15)
|
||||
$fatal(2, "f_add = 15");
|
||||
endfunction
|
||||
|
||||
// Speced ok: function called from function
|
||||
function integer f_add2(input [31:0] a, input [31:0] b, input [31:0] c);
|
||||
params_t [ 1 : 0 ] params;
|
||||
sub_params_t sp0;
|
||||
sub_params_t sp1;
|
||||
sp0 = '{b:55, bar:111};
|
||||
params[0] = '{a:a, foo:11, sub_params:sp0};
|
||||
sp1 = '{b:b, bar:112};
|
||||
params[1] = '{a:12345, foo:12, sub_params:sp1};
|
||||
f_add2 = f_add(params)+c;
|
||||
endfunction
|
||||
endmodule
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2017 by Todd Strader. 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.
|
||||
#
|
||||
compile (
|
||||
v_flags2 => ["--lint-only"],
|
||||
fails=>1,
|
||||
expect=>
|
||||
q{%Warning-USERFATAL: f_add = 15
|
||||
%Warning-USERFATAL: Use "/* verilator lint_off USERFATAL */" and lint_on around source to disable this message.
|
||||
%Error: t/t_func_const_struct_bad.v:16: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_add2'
|
||||
%Error: t/t_func_const_struct_bad.v:27: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing
|
||||
Called from:
|
||||
t/t_func_const_struct_bad.v:37: f_add() with parameters:
|
||||
params = '{a: 32'h7, b: 32'h8}
|
||||
Called from:
|
||||
t/t_func_const_struct_bad.v:16: f_add2() with parameters:
|
||||
a = ?32?sh7
|
||||
b = ?32?sh8
|
||||
c = ?32?sh9
|
||||
},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,39 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2017 by Todd Strader.
|
||||
|
||||
module t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [ 31 : 0 ] a;
|
||||
logic [ 31 : 0 ] b;
|
||||
} params_t;
|
||||
|
||||
localparam params_t P = '{a:5, b:1};
|
||||
localparam P6 = f_add(P);
|
||||
localparam P14 = f_add2(2, 3, f_add(P));
|
||||
localparam P24 = f_add2(7, 8, 9);
|
||||
|
||||
initial begin
|
||||
// Should never get here
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
function integer f_add(input params_t params);
|
||||
f_add = params.a+params.b;
|
||||
if (f_add == 15)
|
||||
$fatal(2, "f_add = 15");
|
||||
endfunction
|
||||
|
||||
// Speced ok: function called from function
|
||||
function integer f_add2(input [31:0] a, input [31:0] b, input [31:0] c);
|
||||
params_t params;
|
||||
params = '{
|
||||
a: a,
|
||||
b: b
|
||||
};
|
||||
f_add2 = f_add(params)+c;
|
||||
endfunction
|
||||
endmodule
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/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.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,85 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2017 by John Stevenson.
|
||||
|
||||
typedef logic [63:0] uid_t;
|
||||
typedef logic [31:0] value_t;
|
||||
|
||||
interface the_intf #(parameter M = 5);
|
||||
logic valid;
|
||||
uid_t uid;
|
||||
value_t [M-1:0] values;
|
||||
|
||||
modport i(
|
||||
output valid,
|
||||
output uid,
|
||||
output values
|
||||
);
|
||||
modport t(
|
||||
input valid,
|
||||
input uid,
|
||||
input values
|
||||
);
|
||||
endinterface
|
||||
|
||||
module Contemplator #(
|
||||
parameter IMPL = 0,
|
||||
parameter M = 5,
|
||||
parameter N = 1 )
|
||||
(
|
||||
input logic clk,
|
||||
the_intf.i out [N-1:0]
|
||||
);
|
||||
|
||||
the_intf #(.M(M)) inp[N-1:0] ();
|
||||
|
||||
DeepThought #(
|
||||
.N ( N ))
|
||||
ultimateAnswerer(
|
||||
.src ( inp ),
|
||||
.dst ( out ));
|
||||
endmodule
|
||||
|
||||
module DeepThought #(
|
||||
parameter N = 1 )
|
||||
(
|
||||
the_intf.t src[N-1:0],
|
||||
the_intf.i dst[N-1:0]
|
||||
);
|
||||
endmodule
|
||||
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
localparam M = 5;
|
||||
localparam N = 1;
|
||||
|
||||
the_intf #(.M(M)) out0 [N-1:0] ();
|
||||
the_intf #(.M(M)) out1 [N-1:0] ();
|
||||
|
||||
Contemplator #(
|
||||
.IMPL ( 0 ),
|
||||
.M ( M ),
|
||||
.N ( N ))
|
||||
contemplatorOfTheZerothKind(
|
||||
.clk ( clk ),
|
||||
.out ( out0 ));
|
||||
|
||||
Contemplator #(
|
||||
.IMPL ( 1 ),
|
||||
.M ( M ),
|
||||
.N ( N ))
|
||||
contemplatorOfTheFirstKind(
|
||||
.clk ( clk ),
|
||||
.out ( out1 ));
|
||||
initial begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
#!/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.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,89 @@
|
||||
// DESCRIPTION: Verilator: Interface parameter getter
|
||||
//
|
||||
// A test of the import parameter used with modport
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2015 by Todd Strader
|
||||
|
||||
interface test_if #(parameter integer FOO = 1);
|
||||
|
||||
// Interface variable
|
||||
logic data;
|
||||
|
||||
// Modport
|
||||
modport mp(
|
||||
import getFoo,
|
||||
output data
|
||||
);
|
||||
|
||||
function integer getFoo ();
|
||||
return FOO;
|
||||
endfunction
|
||||
|
||||
endinterface // test_if
|
||||
|
||||
function integer identity (input integer x);
|
||||
return x;
|
||||
endfunction
|
||||
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
test_if #( .FOO (identity(5)) ) the_interface ();
|
||||
|
||||
testmod testmod_i (.clk (clk),
|
||||
.intf (the_interface),
|
||||
.intf_no_mp (the_interface)
|
||||
);
|
||||
|
||||
localparam THE_TOP_FOO = the_interface.FOO;
|
||||
|
||||
initial begin
|
||||
if (THE_TOP_FOO != 5) begin
|
||||
$display("%%Error: THE_TOP_FOO = %0d", THE_TOP_FOO);
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
module testmod
|
||||
(
|
||||
input clk,
|
||||
test_if.mp intf,
|
||||
test_if intf_no_mp
|
||||
);
|
||||
|
||||
localparam THE_FOO = intf.FOO;
|
||||
localparam THE_OTHER_FOO = intf_no_mp.FOO;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (THE_FOO != 5) begin
|
||||
$display("%%Error: THE_FOO = %0d", THE_FOO);
|
||||
$stop;
|
||||
end
|
||||
if (THE_OTHER_FOO != 5) begin
|
||||
$display("%%Error: THE_OTHER_FOO = %0d", THE_OTHER_FOO);
|
||||
$stop;
|
||||
end
|
||||
if (intf.FOO != 5) begin
|
||||
$display("%%Error: intf.FOO = %0d", intf.FOO);
|
||||
$stop;
|
||||
end
|
||||
if (intf_no_mp.FOO != 5) begin
|
||||
$display("%%Error: intf_no_mp.FOO = %0d", intf_no_mp.FOO);
|
||||
$stop;
|
||||
end
|
||||
// if (i.getFoo() != 5) begin
|
||||
// $display("%%Error: i.getFoo() = %0d", i.getFoo());
|
||||
// $stop;
|
||||
// end
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -10,8 +10,8 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
compile (
|
||||
fails=>1,
|
||||
expect=>
|
||||
q{%Error: t/t_interface_size_bad.v:\d+: Illegal IFACEREF port connection 'foo', mismatch between port which is an interface array of size 4, and expression which is an interface array of size 5.
|
||||
%Error: t/t_interface_size_bad.v:\d+: Illegal IFACEREF port connection 'foo', mismatch between port which is an interface array of size 6, and expression which is an interface array of size 5.
|
||||
q{%Error: t/t_interface_size_bad.v:\d+: Illegal IFACEREF port connection 'foo', mismatch between port which is an interface array of size 5, and expression which is an interface array of size 4.
|
||||
%Error: t/t_interface_size_bad.v:\d+: Illegal IFACEREF port connection 'foo', mismatch between port which is an interface array of size 5, and expression which is an interface array of size 6.
|
||||
%Error: Exiting due to.*},
|
||||
);
|
||||
|
||||
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2017 by Todd Strader. 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.
|
||||
|
||||
$Self->skip("Verilator only test") if !$Self->{vlt};
|
||||
|
||||
compile (
|
||||
fails=>1,
|
||||
expect=>
|
||||
'%Warning-WIDTH: t/t_lint_literal_bad.v:9: Value too large for 8 bit number: 256
|
||||
',
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,11 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2017 by Todd Strader.
|
||||
|
||||
module t (
|
||||
);
|
||||
|
||||
localparam the_localparam = 8'd256;
|
||||
|
||||
endmodule
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/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.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,72 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2017 by Wilson Snyder.
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
|
||||
reg [5:0] addr;
|
||||
|
||||
parameter BANKS = 6;
|
||||
parameter ROWS = 8;
|
||||
|
||||
wire [2:0] bank;
|
||||
wire [2:0] row;
|
||||
|
||||
integer a;
|
||||
integer used[BANKS][ROWS];
|
||||
|
||||
// Test loop
|
||||
initial begin
|
||||
for (a = 0; a < BANKS*ROWS; ++a) begin
|
||||
addr[5:0] = a[5:0];
|
||||
hash (addr, bank, row);
|
||||
used [bank][row] ++;
|
||||
if (used [bank][row] > 1) begin
|
||||
$write ("Error: Hash failed addr=%x bank=%x row=%x\n", addr, bank, row);
|
||||
end
|
||||
end
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
task hash (input [5:0] addr,
|
||||
output [2:0] bank,
|
||||
output [2:0] row);
|
||||
|
||||
reg [1:0] third;
|
||||
reg [1:0] fourth;
|
||||
|
||||
third = {addr[5], addr[4]};
|
||||
fourth = {addr[3] ^ addr[1],
|
||||
addr[2] ^ addr[0]};
|
||||
|
||||
case (third)
|
||||
2'h0:
|
||||
case (fourth)
|
||||
2'h0: begin bank = 3'h0; row = {1'h0, addr[1:0]}; end
|
||||
2'h1: begin bank = 3'h1; row = {1'h0, addr[1:0]}; end
|
||||
2'h2: begin bank = 3'h2; row = {1'h0, addr[1:0]}; end
|
||||
2'h3: begin bank = 3'h3; row = {1'h0, addr[1:0]}; end
|
||||
endcase
|
||||
|
||||
2'h1:
|
||||
case (fourth)
|
||||
2'h0: begin bank = 3'h0; row = {1'h1, addr[1:0]}; end
|
||||
2'h1: begin bank = 3'h1; row = {1'h1, addr[1:0]}; end
|
||||
2'h2: begin bank = 3'h4; row = {1'h0, addr[1:0]}; end
|
||||
2'h3: begin bank = 3'h5; row = {1'h0, addr[1:0]}; end
|
||||
endcase
|
||||
|
||||
2'h2:
|
||||
case (fourth)
|
||||
2'h0: begin bank = 3'h2; row = {1'h1, addr[1:0]}; end
|
||||
2'h1: begin bank = 3'h3; row = {1'h1, addr[1:0]}; end
|
||||
2'h2: begin bank = 3'h4; row = {1'h1, addr[1:0]}; end
|
||||
2'h3: begin bank = 3'h5; row = {1'h1, addr[1:0]}; end
|
||||
endcase
|
||||
|
||||
2'h3: $stop;
|
||||
endcase
|
||||
endtask
|
||||
endmodule
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/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.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,21 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2017 by Wilson Snyder.
|
||||
|
||||
module t;
|
||||
localparam int c[4] = '{5, 6, 7, 8};
|
||||
a #(.p(c)) i_a ();
|
||||
endmodule
|
||||
|
||||
module a
|
||||
#( parameter int p[4] = '{1, 2, 3, 4} );
|
||||
initial begin
|
||||
if (p[0] != 5) $stop;
|
||||
if (p[1] != 6) $stop;
|
||||
if (p[2] != 7) $stop;
|
||||
if (p[3] != 8) $stop;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -8,6 +8,8 @@ module t;
|
||||
integer p_i;
|
||||
reg [7*8:1] p_str;
|
||||
string sv_str;
|
||||
reg [7*8:1] p_in;
|
||||
string sv_in;
|
||||
|
||||
initial begin
|
||||
if ($test$plusargs("PLUS")!==1) $stop;
|
||||
@@ -20,23 +22,47 @@ module t;
|
||||
if ($value$plusargs("NOTTHERE%d", p_i)!==0) $stop;
|
||||
if (p_i !== 10) $stop;
|
||||
|
||||
p_i = 0;
|
||||
if ($value$plusargs("INT=%d", p_i)!==1) $stop;
|
||||
if (p_i !== 32'd1234) $stop;
|
||||
|
||||
p_i = 0;
|
||||
if ($value$plusargs("INT=%H", p_i)!==1) $stop; // tests uppercase % also
|
||||
if (p_i !== 32'h1234) $stop;
|
||||
|
||||
if ($value$plusargs("INT=%o", p_i)!==1) $stop;
|
||||
p_i = 0;
|
||||
// Check octal and WIDTH
|
||||
if (!$value$plusargs("INT=%o", p_i)) $stop;
|
||||
if (p_i !== 32'o1234) $stop;
|
||||
|
||||
p_str = "none";
|
||||
if ($value$plusargs("IN%s", p_str)!==1) $stop;
|
||||
$display("str='%s'",p_str);
|
||||
if (p_str !== "T=1234") $stop;
|
||||
|
||||
sv_str = "none";
|
||||
if ($value$plusargs("IN%s", sv_str)!==1) $stop;
|
||||
$display("str='%s'",sv_str);
|
||||
if (sv_str != "T=1234") $stop;
|
||||
|
||||
p_in = "IN%s";
|
||||
`ifdef VERILATOR
|
||||
p_in = $c(p_in); // Prevent constant propagation
|
||||
`endif
|
||||
sv_str = "none";
|
||||
if ($value$plusargs(p_in, sv_str)!==1) $stop;
|
||||
$display("str='%s'",sv_str);
|
||||
if (sv_str != "T=1234") $stop;
|
||||
|
||||
sv_in = "INT=%d";
|
||||
`ifdef VERILATOR
|
||||
if ($c1(0)) sv_in = "NEVER"; // Prevent constant propagation
|
||||
`endif
|
||||
p_i = 0;
|
||||
if ($value$plusargs(sv_in, p_i)!==1) $stop;
|
||||
$display("i='%d'",p_i);
|
||||
if (p_i !== 32'd1234) $stop;
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
@@ -8,13 +8,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
fails=>$Self->{v3},
|
||||
expect=>
|
||||
q{%Error: t/t_sys_plusargs_bad.v:\d+: Missing or extra \$value\$plusargs format qualifier: 'NOTTHERE'
|
||||
%Error: t/t_sys_plusargs_bad.v:\d+: Illegal \$value\$plusargs format qualifier: 'z'
|
||||
%Error: t/t_sys_plusargs_bad.v:\d+: Missing or extra \$value\$plusargs format qualifier: 'INT=%x%x'
|
||||
%Error: Exiting due to.*},
|
||||
);
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
|
||||
@@ -17,6 +17,7 @@ module t;
|
||||
// BAD: Multi letter
|
||||
if ($value$plusargs("INT=%x%x", p_i)!==0) $stop;
|
||||
|
||||
$stop;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
`begin_keywords "VAMS-2.3"
|
||||
|
||||
module t (/*autoarg*/
|
||||
// Outputs
|
||||
aout,
|
||||
// Inputs
|
||||
clk, in
|
||||
);
|
||||
@@ -15,21 +13,43 @@ module t (/*autoarg*/
|
||||
input clk;
|
||||
|
||||
input [15:0] in;
|
||||
output aout;
|
||||
wreal aout;
|
||||
|
||||
integer cyc=0;
|
||||
|
||||
real vin;
|
||||
real gnd;
|
||||
real vin;
|
||||
wreal vpass;
|
||||
through through (.vin, .vpass);
|
||||
|
||||
real gnd;
|
||||
wire out;
|
||||
within_range within_range (/*AUTOINST*/
|
||||
// Interfaces
|
||||
.vin (vin),
|
||||
.vpass (vpass),
|
||||
.gnd (gnd),
|
||||
// Outputs
|
||||
.out (out));
|
||||
|
||||
// wreal bus declaration
|
||||
wreal vin_upper_bus[1:0];
|
||||
|
||||
// wreal nets declaration
|
||||
wreal vout_split_0;
|
||||
wreal vout_split_1;
|
||||
|
||||
wreal_bus wreal_bus( .vin_bus(vin_upper_bus[1:0]),
|
||||
.vout_split_0(vout_split_0),
|
||||
.vout_split_1(vout_split_1));
|
||||
|
||||
|
||||
// implicit declaration of wreal
|
||||
`ifdef VERILATOR
|
||||
wreal wreal_implicit_net; // implicit declaration of wreal not supported yet
|
||||
`endif
|
||||
// verilator lint_off IMPLICIT
|
||||
first_level first_level(.in(cyc[0]), .out(wreal_implicit_net));
|
||||
// verilator lint_on IMPLICIT
|
||||
|
||||
parameter real lsb = 1;
|
||||
// verilator lint_off WIDTH
|
||||
assign aout = $itor(in) * lsb;
|
||||
@@ -70,14 +90,47 @@ module t (/*autoarg*/
|
||||
|
||||
endmodule
|
||||
|
||||
module within_range
|
||||
module through
|
||||
(input wreal vin,
|
||||
output wreal vpass);
|
||||
assign vpass = vin;
|
||||
endmodule
|
||||
|
||||
module within_range
|
||||
(input wreal vpass,
|
||||
input wreal gnd,
|
||||
output out);
|
||||
|
||||
parameter real V_MIN = 0.5;
|
||||
parameter real V_MAX = 10;
|
||||
|
||||
wreal in_int = vin - gnd;
|
||||
wreal in_int = vpass - gnd;
|
||||
wire out = (V_MIN <= in_int && in_int <= V_MAX);
|
||||
endmodule
|
||||
|
||||
|
||||
module wreal_bus
|
||||
(input wreal vin_bus [1:0],
|
||||
output wreal vout_split_0,
|
||||
output wreal vout_split_1);
|
||||
assign vout_split_0 = vin_bus[0];
|
||||
assign vout_split_1 = vin_bus[1];
|
||||
endmodule
|
||||
|
||||
module first_level
|
||||
(input in,
|
||||
`ifdef VERILATOR
|
||||
output wreal out
|
||||
`else
|
||||
output out // Implicity becomes real
|
||||
`endif
|
||||
);
|
||||
second_level second_level(.in(in), .out(out));
|
||||
endmodule
|
||||
|
||||
module second_level
|
||||
(input in,
|
||||
output out);
|
||||
wreal out;
|
||||
assign out = in ? 1.23456: 7.8910;
|
||||
endmodule
|
||||
|
||||
Reference in New Issue
Block a user