Compare commits

...
18 Commits
Author SHA1 Message Date
Wilson Snyder 02530172e7 Version bump 2017-05-30 22:01:21 -04:00
Wilson Snyder 447d803800 Fix internal clang warnings. 2017-05-24 23:51:15 -04:00
Wilson Snyder 6b04901c4d Fix testplusargs false width warning, bug1165. 2017-05-19 07:20:41 -04:00
Wilson Snyder 7fb29621c3 Fix interface functions returning wrong parameters, bug996. 2017-05-18 22:49:17 -04:00
Wilson Snyder b032fce962 Support $value$plusargs with variables, bug1165. 2017-05-18 22:41:43 -04:00
Wilson Snyder ce879122bb Fix --assert with complex case statements, bug1164. 2017-05-17 20:15:40 -04:00
Todd Strader 2fa16708b7 Fix non-arrayed cells with interface arrays, bug1153.
Signed-off-by: Wilson Snyder <[email protected]>
2017-05-10 19:05:42 -04:00
Todd Strader 54bc8608e3 Add stack trace when can't optimize function, bug1158.
Signed-off-by: Wilson Snyder <[email protected]>
2017-05-09 18:54:15 -04:00
Todd Strader 706a7802cc Fix non-cutable ordering loops on clock arrays, bug1009.
Signed-off-by: Wilson Snyder <[email protected]>
2017-05-09 08:05:21 -04:00
Wilson Snyder 9dc01cf540 Support arrayed parameter overrides, bug1153. 2017-05-02 19:16:54 -04:00
Wilson Snyder 8943ad5966 internals: Remove extra newlines on v3fatalSrc. No functional change. 2017-04-28 20:09:27 -04:00
Wilson Snyder deb7a1c9c0 Fix non-arrayed cells with interface arrays, bug1153. 2017-04-28 20:03:38 -04:00
Wilson Snyder 96a5445d44 Support ports of array of reals, bug1154. 2017-04-28 06:10:14 -04:00
Wilson Snyder d693065afb Fix backwards array interface error message 2017-04-27 06:36:14 -04:00
Wilson Snyder bdeee35669 Add warning on mis-sized literal, bug1156. 2017-04-26 18:34:01 -04:00
Wilson Snyder 62b3deb90d Tests: Improve vams to attach wire. 2017-04-04 19:15:15 -04:00
Wilson Snyder 9df9ff59e0 Commentary 2017-04-03 20:02:19 -04:00
Wilson Snyder 23a3271c06 devel release 2017-04-02 08:49:31 -04:00
87 changed files with 2416 additions and 303 deletions
+23
View File
@@ -3,6 +3,29 @@ Revision history for Verilator
The contributors that suggested a given feature are shown in []. Thanks! 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 * Verilator 3.902 2017-04-02
** Add -FI option to force includes,msg2146. [Amir Gonnen] ** Add -FI option to force includes,msg2146. [Amir Gonnen]
+47 -26
View File
@@ -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 find it difficult to find the exact name, try to use C</*verilator clocker*/> in
RTL file to mark the signal directly. 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> =item --compiler I<compiler-name>
Enables tunings and workarounds for the specified C++ compiler. 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 Verilator has an important difference from an event based simulator; signal
values that are changed by the VPI will not immediately propagate their 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. 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 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 routines extremely fast compared to event based simulators, but can confuse
some test-benches that expect immediate propagation. 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 than accessing the Verilator values by direct reference
(structure->module->signame), as the VPI accessors perform lookup in (structure->module->signame), as the VPI accessors perform lookup in
functions at runtime requiring at best hundreds of instructions, while the functions at runtime requiring at best hundreds of instructions, while the
direct references are evaluated by the compiler and result in only a couple direct references are evaluated by the compiler and result in only a couple
of instructions. of instructions.
For signal callbacks to work the main loop of the program must call
VerilatedVpi::callValueCbs().
=head2 VPI Example =head2 VPI Example
In the below example, we have readme marked read-only, and writeme which if 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 written from outside the model will have the same semantics as if it
changed on the specified clock edge. changed on the specified clock edge.
module t; cat <<EOF >our.v
reg readme /*verilator public_flat_rd*/; module our (input clk);
reg writeme /*verilator public_flat_rw @(posedge clk) */; reg readme /*verilator public_flat_rd*/;
endmodule 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 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() { cat <<EOF >sim_main.cpp
vpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)"t.readme", NULL); #include "Vour.h"
if (!vh1) { error... } #include "verilated.h"
const char* name = vpi_get_str(vpiName, vh1); #include "verilated_vpi.h" // Required to get definitions
printf("Module name: %s\n"); // Prints "readme"
s_vpi_value v; vluint64_t main_time = 0; // See comments in first example
v.format = vpiIntVal; double sc_time_stamp () { return main_time; }
vpi_get_value(vh1, &v);
printf("Value of v: %d\n", v.value.integer); // Prints "readme"
}
For signal callbacks to work the main loop of the program must call void read_and_check() {
VerilatedVpi::callValueCbs(). 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 s_vpi_value v;
... v.format = vpiIntVal;
while (time passes) { vpi_get_value(vh1, &v);
... printf("Value of v: %d\n", v.value.integer); // Prints "readme"
topp->eval(); }
VerilatedVpi::callValueCbs();
} 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 =head1 CROSS COMPILATION
+1 -1
View File
@@ -6,7 +6,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel]) #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 # When releasing, also update header of Changes file
AC_CONFIG_HEADER(src/config_build.h) AC_CONFIG_HEADER(src/config_build.h)
+62 -20
View File
@@ -302,8 +302,7 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
bool inPct = false; bool inPct = false;
bool widthSet = false; bool widthSet = false;
int width = 0; int width = 0;
const char* pos = formatp; for (const char* pos = formatp; *pos; ++pos) {
for (; *pos; ++pos) {
if (!inPct && pos[0]=='%') { if (!inPct && pos[0]=='%') {
pctp = pos; pctp = pos;
inPct = true; inPct = true;
@@ -1077,22 +1076,36 @@ IData VL_TESTPLUSARGS_I(const char* formatp) {
else return 1; else return 1;
} }
IData VL_VALUEPLUSARGS_IN(int, const char* prefixp, char, string& ldr) { IData VL_VALUEPLUSARGS_INW(int rbits, const string& ld, WDataOutP rwp) {
const string& match = VerilatedImp::argPlusMatch(prefixp); string prefix;
const char* dp = match.c_str() + 1 /*leading + */ + strlen(prefixp); bool inPct = false;
if (match == "") return 0; bool done = false;
ldr = string(dp); char fmt = ' ';
return 1; 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(prefix.c_str());
const string& match = VerilatedImp::argPlusMatch(prefixp); const char* dp = match.c_str() + 1 /*leading + */ + prefix.length();
const char* dp = match.c_str() + 1 /*leading + */ + strlen(prefixp);
if (match == "") return 0; if (match == "") return 0;
VL_ZERO_RESET_W(rbits, rwp); VL_ZERO_RESET_W(rbits, rwp);
switch (tolower(fmt)) { switch (tolower(fmt)) {
case '%':
break;
case 'd': case 'd':
vlsint64_t ld; vlsint64_t ld;
sscanf(dp,"%30" VL_PRI64 "d",&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': case 'x':
_vl_vsss_based(rwp,rbits, 4, dp, 0, (int)strlen(dp)); _vl_vsss_based(rwp,rbits, 4, dp, 0, (int)strlen(dp));
break; break;
case 's': case 's': // string/no conversion
for (int i=0, lsb=0, pos=((int)strlen(dp))-1; i<rbits && pos>=0; pos--) { for (int i=0, lsb=0, posp=((int)strlen(dp))-1; i<rbits && posp>=0; posp--) {
_vl_vsss_setbit(rwp,rbits,lsb, 8, dp[pos]); lsb+=8; _vl_vsss_setbit(rwp,rbits,lsb, 8, dp[posp]); lsb+=8;
} }
break; break;
default: // Compile time should have found all errors before this case 'e': //FALLTHRU - Unsupported
vl_fatal (__FILE__, __LINE__, "", "$value$plusargs format error"); case 'f': //FALLTHRU - Unsupported
break; 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); _VL_CLEAN_INPLACE_W(rbits,rwp);
return 1; 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 char* vl_mc_scan_plusargs(const char* prefixp) {
const string& match = VerilatedImp::argPlusMatch(prefixp); const string& match = VerilatedImp::argPlusMatch(prefixp);
+2
View File
@@ -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){ static inline WDataOutP VL_MULS_WWW(int,int lbits,int, WDataOutP owp,WDataInP lwp,WDataInP rwp){
int words = VL_WORDS_I(lbits); int words = VL_WORDS_I(lbits);
// cppcheck-suppress variableScope
IData lwstore[VL_MULS_MAX_WORDS]; // Fixed size, as MSVC++ doesn't allow [words] here IData lwstore[VL_MULS_MAX_WORDS]; // Fixed size, as MSVC++ doesn't allow [words] here
// cppcheck-suppress variableScope
IData rwstore[VL_MULS_MAX_WORDS]; IData rwstore[VL_MULS_MAX_WORDS];
WDataInP lwusp = lwp; WDataInP lwusp = lwp;
WDataInP rwusp = rwp; WDataInP rwusp = rwp;
+14 -1
View File
@@ -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 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 void VL_SFORMAT_X(int obits_ignored, string &output, const char* formatp, ...);
extern string VL_SFORMATF_NX(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 #endif // Guard
+1 -1
View File
@@ -108,7 +108,7 @@ private:
// Move the active's contents to the other active // Move the active's contents to the other active
UINFO(4," merge active "<<sensesp<<" into "<<wantp<<endl); UINFO(4," merge active "<<sensesp<<" into "<<wantp<<endl);
if (nodep->sensesStorep()) { 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(); sensesp->unlinkFrBack();
// There may be other references to same sense tree, // There may be other references to same sense tree,
// we'll be removing all references when we get to them, // we'll be removing all references when we get to them,
+4 -14
View File
@@ -246,20 +246,10 @@ private:
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) { for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) { for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
AstNode* onep; AstNode* onep;
AstConst* iconstp = icondp->castConst(); if (nodep->casex() || nodep->casez() || nodep->caseInside()) {
if (iconstp && iconstp->num().isFourState() onep = AstEqWild::newTyped(itemp->fileline(),
&& (nodep->casex() || nodep->casez() || nodep->caseInside())) { nodep->exprp()->cloneTree(false),
V3Number nummask (itemp->fileline(), iconstp->width()); icondp->cloneTree(false));
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);
} else { } else {
onep = AstEq::newTyped(icondp->fileline(), onep = AstEq::newTyped(icondp->fileline(),
nodep->exprp()->cloneTree(false), nodep->exprp()->cloneTree(false),
+13 -1
View File
@@ -1675,6 +1675,7 @@ public:
virtual bool maybePointedTo() const { return true; } virtual bool maybePointedTo() const { return true; }
virtual AstNodeDType* virtRefDTypep() const { return NULL; } // Iff has a non-null refDTypep(), as generic node function 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 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. // 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; } 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 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,... virtual int widthTotalBytes() const; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
// op1 = members // 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 AstMemberDType* membersp() const { return op1p()->castMemberDType(); } // op1 = AstMember list
void addMembersp(AstNode* nodep) { addNOp1p(nodep); } void addMembersp(AstNode* nodep) { addNOp1p(nodep); }
bool packed() const { return m_packed; } bool packed() const { return m_packed; }
@@ -1754,7 +1758,7 @@ public:
virtual void dump(ostream& str); virtual void dump(ostream& str);
virtual void dumpSmall(ostream& str); virtual void dumpSmall(ostream& str);
virtual const char* broken() const { BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists()) 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()) { virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) {
m_refDTypep = m_refDTypep->clonep(); m_refDTypep = m_refDTypep->clonep();
}} }}
@@ -1763,6 +1767,14 @@ public:
return (msb()==sp->msb() return (msb()==sp->msb()
&& subDTypep()==sp->subDTypep() && subDTypep()==sp->subDTypep()
&& rangenp()->sameTree(sp->rangenp())); } // HashedDT doesn't recurse, so need to check children && 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())); } virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_refDTypep),V3Hash(msb()),V3Hash(lsb())); }
AstNodeDType* getChildDTypep() const { return childDTypep(); } AstNodeDType* getChildDTypep() const { return childDTypep(); }
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
+7
View File
@@ -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 { bool AstVar::isSigPublic() const {
return (m_sigPublic || (v3Global.opt.allPublic() && !isTemp() && !isGenVar())); return (m_sigPublic || (v3Global.opt.allPublic() && !isTemp() && !isGenVar()));
+29 -16
View File
@@ -180,6 +180,10 @@ public:
virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); } virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); }
virtual AstNodeDType* skipRefToConstp() const { return subDTypep()->skipRefToConstp(); } virtual AstNodeDType* skipRefToConstp() const { return subDTypep()->skipRefToConstp(); }
virtual AstNodeDType* skipRefToEnump() const { return subDTypep()->skipRefToEnump(); } 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 widthAlignBytes() const { return dtypep()->widthAlignBytes(); }
virtual int widthTotalBytes() const { return dtypep()->widthTotalBytes(); } virtual int widthTotalBytes() const { return dtypep()->widthTotalBytes(); }
// METHODS // METHODS
@@ -250,7 +254,9 @@ public:
m_uniqueNum = uniqueNumInc(); m_uniqueNum = uniqueNumInc();
} }
ASTNODE_NODE_FUNCS(DefImplicitDType) 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); } virtual V3Hash sameHash() const { return V3Hash(m_uniqueNum); }
AstNodeDType* getChildDTypep() const { return childDTypep(); } AstNodeDType* getChildDTypep() const { return childDTypep(); }
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable 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 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 virtual bool same(AstNode* samep) const { // width/widthMin/numeric compared elsewhere
return samep->castBasicDType()->m == m; } 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 string name() const { return m.m_keyword.ascii(); }
virtual const char* broken() const { BROKEN_RTN(dtypep()!=this); return NULL; } virtual const char* broken() const { BROKEN_RTN(dtypep()!=this); return NULL; }
AstRange* rangep() const { return op1p()->castRange(); } // op1 = Range of variable AstRange* rangep() const { return op1p()->castRange(); } // op1 = Range of variable
@@ -456,6 +464,8 @@ public:
}} }}
virtual bool same(AstNode* samep) const { virtual bool same(AstNode* samep) const {
return (m_refDTypep==samep->castConstDType()->m_refDTypep); } 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 virtual V3Hash sameHash() const { return V3Hash(m_refDTypep); } // node's type() included elsewhere
AstNodeDType* getChildDTypep() const { return childDTypep(); } AstNodeDType* getChildDTypep() const { return childDTypep(); }
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
@@ -499,6 +509,7 @@ public:
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToEnump() 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 widthAlignBytes() const { return 1; }
virtual int widthTotalBytes() const { return 1; } virtual int widthTotalBytes() const { return 1; }
string cellName() const { return m_cellName; } string cellName() const { return m_cellName; }
@@ -540,6 +551,8 @@ public:
return (m_refDTypep==samep->castRefDType()->m_refDTypep return (m_refDTypep==samep->castRefDType()->m_refDTypep
&& m_name==samep->castRefDType()->m_name && m_name==samep->castRefDType()->m_name
&& m_packagep==samep->castRefDType()->m_packagep); } && 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 V3Hash sameHash() const { return V3Hash(V3Hash(m_refDTypep),V3Hash(m_packagep)); }
virtual void dump(ostream& str=cout); virtual void dump(ostream& str=cout);
virtual string name() const { return m_name; } virtual string name() const { return m_name; }
@@ -623,6 +636,7 @@ public:
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; } virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; }
virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); } 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) 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) 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(); m_refDTypep = m_refDTypep->clonep();
}} }}
virtual bool same(AstNode* samep) const { return m_uniqueNum==samep->castEnumDType()->m_uniqueNum; } 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); } virtual V3Hash sameHash() const { return V3Hash(m_uniqueNum); }
AstNodeDType* getChildDTypep() const { return childDTypep(); } AstNodeDType* getChildDTypep() const { return childDTypep(); }
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Data type AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Data type
@@ -733,6 +748,7 @@ public:
ASTNODE_NODE_FUNCS(ParseTypeDType) ASTNODE_NODE_FUNCS(ParseTypeDType)
AstNodeDType* dtypep() const { return NULL; } AstNodeDType* dtypep() const { return NULL; }
// METHODS // METHODS
virtual bool similarDType(AstNodeDType* samep) const { return this==samep; }
virtual AstBasicDType* basicp() const { return NULL; } virtual AstBasicDType* basicp() const { return NULL; }
virtual AstNodeDType* skipRefp() const { return NULL; } virtual AstNodeDType* skipRefp() const { return NULL; }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
@@ -2642,28 +2658,24 @@ public:
class AstValuePlusArgs : public AstNodeMath { class AstValuePlusArgs : public AstNodeMath {
// Parents: expr // Parents: expr
// Child: variable to set. If NULL then this is a $test$plusargs instead of $value$plusargs // Child: variable to set. If NULL then this is a $test$plusargs instead of $value$plusargs
private:
string m_text;
public: public:
AstValuePlusArgs(FileLine* fileline, const string& text, AstNode* exprsp) AstValuePlusArgs(FileLine* fileline, AstNode* searchp, AstNode* outp)
: AstNodeMath (fileline), m_text(text) { : AstNodeMath (fileline) {
setOp1p(exprsp); setOp1p(searchp); setOp2p(outp);
} }
ASTNODE_NODE_FUNCS(ValuePlusArgs) ASTNODE_NODE_FUNCS(ValuePlusArgs)
virtual string name() const { return m_text; }
virtual string verilogKwd() const { return "$value$plusargs"; } virtual string verilogKwd() const { return "$value$plusargs"; }
virtual string emitVerilog() { return verilogKwd(); } virtual string emitVerilog() { return "%f$value$plusargs(%l, %k%r)"; }
virtual string emitC() { return "VL_VALUEPLUSARGS_%nq(%lw, %P, NULL)"; } virtual string emitC() { V3ERROR_NA; return ""; }
virtual bool isGateOptimizable() const { return false; } virtual bool isGateOptimizable() const { return false; }
virtual bool isPredictOptimizable() const { return false; } virtual bool isPredictOptimizable() const { return false; }
virtual bool cleanOut() { return true; } virtual bool cleanOut() { return true; }
virtual V3Hash sameHash() const { return V3Hash(text()); } virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(AstNode* samep) const { virtual bool same(AstNode* samep) const { return true; }
return text()==samep->castValuePlusArgs()->text(); } AstNode* searchp() const { return op1p(); } // op1 = Search expression
AstNode* exprsp() const { return op1p(); } // op1 = Expressions to output void searchp(AstNode* nodep) { setOp1p(nodep); }
void exprsp(AstNode* nodep) { setOp1p(nodep); } // op1 = Expressions to output AstNode* outp() const { return op2p(); } // op2 = Expressions to output
string text() const { return m_text; } // * = Text to display void outp(AstNode* nodep) { setOp2p(nodep); }
void text(const string& text) { m_text=text; }
}; };
class AstTestPlusArgs : public AstNodeMath { class AstTestPlusArgs : public AstNodeMath {
@@ -4657,6 +4669,7 @@ public:
dtypeSetLogicBool(); } dtypeSetLogicBool(); }
ASTNODE_NODE_FUNCS(EqWild) ASTNODE_NODE_FUNCS(EqWild)
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstEqWild(this->fileline(), lhsp, rhsp); } 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 void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opWildEq(lhs,rhs); }
virtual string emitVerilog() { return "%k(%l %f==? %r)"; } virtual string emitVerilog() { return "%k(%l %f==? %r)"; }
virtual string emitC() { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; } virtual string emitC() { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; }
+5 -5
View File
@@ -62,7 +62,7 @@ public:
if (debug()>=9) cout<<"-nodeDel: "<<(void*)(nodep)<<endl; if (debug()>=9) cout<<"-nodeDel: "<<(void*)(nodep)<<endl;
NodeMap::iterator iter = s_nodes.find(nodep); NodeMap::iterator iter = s_nodes.find(nodep);
if (iter==s_nodes.end() || !(iter->second & FLAG_ALLOCATED)) { 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); if (iter!=s_nodes.end()) s_nodes.erase(iter);
} }
@@ -71,7 +71,7 @@ public:
if (debug()>=9) cout<<"-nodeNew: "<<(void*)(nodep)<<endl; if (debug()>=9) cout<<"-nodeNew: "<<(void*)(nodep)<<endl;
NodeMap::iterator iter = s_nodes.find(nodep); NodeMap::iterator iter = s_nodes.find(nodep);
if (iter!=s_nodes.end() || (iter->second & FLAG_ALLOCATED)) { 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()) { if (iter == s_nodes.end()) {
int flags = FLAG_ALLOCATED; // This int needed to appease GCC 4.1.2 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); NodeMap::iterator iter = s_nodes.find(nodep);
if (iter == s_nodes.end()) { if (iter == s_nodes.end()) {
#ifdef VL_LEAK_CHECKS #ifdef VL_LEAK_CHECKS
nodep->v3fatalSrc("AstNode is in tree, but not allocated\n"); nodep->v3fatalSrc("AstNode is in tree, but not allocated");
#endif #endif
} else { } else {
if (!(iter->second & FLAG_ALLOCATED)) { if (!(iter->second & FLAG_ALLOCATED)) {
#ifdef VL_LEAK_CHECKS #ifdef VL_LEAK_CHECKS
nodep->v3fatalSrc("AstNode is in tree, but not allocated\n"); nodep->v3fatalSrc("AstNode is in tree, but not allocated");
#endif #endif
} }
if (iter->second & FLAG_IN_TREE) { 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); int or_flags = FLAG_IN_TREE | (linkable?FLAG_LINKABLE:0);
+7 -2
View File
@@ -75,7 +75,8 @@ public:
m_numStmts += 1; 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_basename = basename;
m_argsp = argsp; m_argsp = argsp;
m_callargsp = callargsp; m_callargsp = callargsp;
@@ -87,6 +88,9 @@ public:
m_tlFuncp->isStatic(false); m_tlFuncp->isStatic(false);
m_tlFuncp->slow(true); m_tlFuncp->slow(true);
m_tlFuncp->argTypes(m_argsp); m_tlFuncp->argTypes(m_argsp);
if (stmt != "") {
m_tlFuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
}
m_funcp = m_tlFuncp; m_funcp = m_tlFuncp;
m_modp->addStmtp(m_tlFuncp); m_modp->addStmtp(m_tlFuncp);
} }
@@ -100,7 +104,8 @@ void V3CCtors::cctorsAll() {
// Process each module in turn // Process each module in turn
V3CCtorsVisitor var_reset (modp, "_ctor_var_reset"); V3CCtorsVisitor var_reset (modp, "_ctor_var_reset");
V3CCtorsVisitor configure_coverage (modp, "_configure_coverage", 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()) { for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
AstVar* varp = np->castVar(); AstVar* varp = np->castVar();
+1 -1
View File
@@ -174,7 +174,7 @@ private:
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) { for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
//if (debug()>=9) icondp->dumpTree(cout," caseitem: "); //if (debug()>=9) icondp->dumpTree(cout," caseitem: ");
AstConst* iconstp = icondp->castConst(); 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)) { if (neverItem(nodep, iconstp)) {
// X in casez can't ever be executed // X in casez can't ever be executed
} else { } else {
+2 -2
View File
@@ -629,9 +629,9 @@ private:
} }
virtual void visit(AstNodeVarRef* nodep) { virtual void visit(AstNodeVarRef* nodep) {
if (m_scopep) { 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(); 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); CdcVarVertex* varvertexp = makeVarVertex(varscp);
UINFO(5," VARREF to "<<varscp<<endl); UINFO(5," VARREF to "<<varscp<<endl);
// We use weight of one for normal edges, // We use weight of one for normal edges,
+1 -1
View File
@@ -253,7 +253,7 @@ private:
AstNode::user1ClearTree(); AstNode::user1ClearTree();
// Create the change detection function // Create the change detection function
AstScope* scopep = nodep->scopep(); 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; m_statep->m_scopetopp = scopep;
// Create a wrapper change detection function that calls each change detection function // Create a wrapper change detection function that calls each change detection function
+1 -1
View File
@@ -559,7 +559,7 @@ class GaterVisitor : public GaterBaseVisitor {
if (!vVxp->inBeginp()) { if (!vVxp->inBeginp()) {
// At this point, any variable not linked is an error // At this point, any variable not linked is an error
// (It should have at least landed under the Head node) // (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)) { if (!lastVxp || vVxp->sortCmp(lastVxp)) {
// Different sources for this new node // Different sources for this new node
+1 -1
View File
@@ -192,7 +192,7 @@ private:
UINFO(4," TOPSCOPE "<<nodep<<endl); UINFO(4," TOPSCOPE "<<nodep<<endl);
m_topScopep=nodep; m_topScopep=nodep;
m_scopep = nodep->scopep(); 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() //VV***** We reset all user1p()
AstNode::user1ClearTree(); AstNode::user1ClearTree();
// Make top functions // Make top functions
+1 -1
View File
@@ -239,7 +239,7 @@ private:
V3Hash hashval = it->first; V3Hash hashval = it->first;
AstNode* node1p = it->second; AstNode* node1p = it->second;
if (!node1p->castCFunc()) continue; 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) { for (V3Hashed::iterator eqit = it; eqit != m_hashed.end(); ++eqit) {
AstNode* node2p = eqit->second; AstNode* node2p = eqit->second;
if (!(eqit->first == hashval)) break; if (!(eqit->first == hashval)) break;
+9 -1
View File
@@ -555,7 +555,7 @@ private:
// Replace oldp node with a constant set to specified value // Replace oldp node with a constant set to specified value
UASSERT (oldp, "Null old\n"); UASSERT (oldp, "Null old\n");
if (oldp->castConst() && !oldp->castConst()->num().isFourState()) { if (oldp->castConst() && !oldp->castConst()->num().isFourState()) {
oldp->v3fatalSrc("Already constant??\n"); oldp->v3fatalSrc("Already constant??");
} }
AstNode* newp = new AstConst(oldp->fileline(), num); AstNode* newp = new AstConst(oldp->fileline(), num);
newp->dtypeFrom(oldp); newp->dtypeFrom(oldp);
@@ -1491,6 +1491,14 @@ private:
did=true; 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) { if (!did && m_required) {
+4 -4
View File
@@ -207,8 +207,8 @@ private:
dimvalp.push_front(valp); dimvalp.push_front(valp);
} }
AstVarRef* varrefp = dimselp->castVarRef(); AstVarRef* varrefp = dimselp->castVarRef();
if (!varrefp) nodep->v3fatalSrc("No var underneath arraysels\n"); if (!varrefp) nodep->v3fatalSrc("No var underneath arraysels");
if (!varrefp->varScopep()) varrefp->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp\n"); if (!varrefp->varScopep()) varrefp->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp");
varrefp->unlinkFrBack(); varrefp->unlinkFrBack();
AstVar* oldvarp = varrefp->varp(); AstVar* oldvarp = varrefp->varp();
int modVecNum = oldvarp->user4(); oldvarp->user4(modVecNum+1); 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) nodep->v3fatalSrc("<= not under sensitivity block");
if (!m_activep->hasClocked()) nodep->v3error("Internal: Blocking <= assignment in non-clocked block, should have converted in V3Active"); if (!m_activep->hasClocked()) nodep->v3error("Internal: Blocking <= assignment in non-clocked block, should have converted in V3Active");
AstVarScope* oldvscp = nodep->varScopep(); 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(); AstVarScope* dlyvscp = oldvscp->user1p()->castVarScope();
if (dlyvscp) { // Multiple use of delayed variable if (dlyvscp) { // Multiple use of delayed variable
AstActive* oldactivep = dlyvscp->user2p()->castActive(); AstActive* oldactivep = dlyvscp->user2p()->castActive();
@@ -433,7 +433,7 @@ private:
} }
virtual void visit(AstNodeFor* nodep) { 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) { virtual void visit(AstWhile* nodep) {
bool oldloop = m_inLoop; bool oldloop = m_inLoop;
+25 -47
View File
@@ -217,7 +217,7 @@ public:
} }
virtual void visit(AstNodeCase* nodep) { virtual void visit(AstNodeCase* nodep) {
// In V3Case... // 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) { virtual void visit(AstComment* nodep) {
putsDecoration((string)"// "+nodep->name()+" at "+nodep->fileline()->ascii()+"\n"); putsDecoration((string)"// "+nodep->name()+" at "+nodep->fileline()->ascii()+"\n");
@@ -277,54 +277,15 @@ public:
displayNode(nodep, NULL, nodep->text(), nodep->exprsp(), true); displayNode(nodep, NULL, nodep->text(), nodep->exprsp(), true);
} }
virtual void visit(AstValuePlusArgs* nodep) { virtual void visit(AstValuePlusArgs* nodep) {
string prefix; puts("VL_VALUEPLUSARGS_IN");
char format = '?'; emitIQW(nodep->outp());
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("("); puts("(");
puts(cvtToStr(nodep->exprsp()->widthMin())); // Note argument width, not node width (which is always 32) puts(cvtToStr(nodep->outp()->widthMin()));
putbs(",");
putsQuoted(prefix);
putbs(",");
puts("'"); puts(cvtToStr(format)); puts("'");
puts(","); puts(",");
nodep->exprsp()->iterateAndNext(*this); emitCvtPackStr(nodep->searchp());
puts(",");
putbs("");
nodep->outp()->iterateAndNext(*this);
puts(")"); puts(")");
} }
virtual void visit(AstTestPlusArgs* nodep) { virtual void visit(AstTestPlusArgs* nodep) {
@@ -618,6 +579,23 @@ public:
puts(nodep->hiername()); puts(nodep->hiername());
puts(nodep->varp()->name()); 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) { void emitConstant(AstConst* nodep, AstVarRef* assigntop, const string& assignString) {
// Put out constant set to the specified variable, or given variable in a string // Put out constant set to the specified variable, or given variable in a string
if (nodep->num().isFourState()) { if (nodep->num().isFourState()) {
-4
View File
@@ -238,10 +238,6 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
virtual void visit(AstSFormatF* nodep) { virtual void visit(AstSFormatF* nodep) {
visitNodeDisplay(nodep, NULL, nodep->text(), nodep->exprsp()); visitNodeDisplay(nodep, NULL, nodep->text(), nodep->exprsp());
} }
virtual void visit(AstValuePlusArgs* nodep) {
visitNodeDisplay(nodep, NULL, nodep->text(), nodep->exprsp());
}
virtual void visit(AstFOpen* nodep) { virtual void visit(AstFOpen* nodep) {
putfs(nodep,nodep->verilogKwd()); putfs(nodep,nodep->verilogKwd());
putbs(" ("); putbs(" (");
+1 -1
View File
@@ -270,7 +270,7 @@ void FileLine::operator delete(void* objp, size_t size) {
if (it != fileLineLeakChecks.end()) { if (it != fileLineLeakChecks.end()) {
fileLineLeakChecks.erase(it); fileLineLeakChecks.erase(it);
} else { } else {
flp->v3fatalSrc("Deleting FileLine object that was never tracked\n"); flp->v3fatalSrc("Deleting FileLine object that was never tracked");
} }
::operator delete(objp); ::operator delete(objp);
} }
+216 -4
View File
@@ -113,6 +113,20 @@ public:
} }
return ret; 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 { class GateVarVertex : public GateEitherVertex {
@@ -291,6 +305,7 @@ private:
// {statement}Node::user1p -> GateLogicVertex* for this statement // {statement}Node::user1p -> GateLogicVertex* for this statement
// AstVarScope::user2 -> bool: Signal used in SenItem in *this* always statement // AstVarScope::user2 -> bool: Signal used in SenItem in *this* always statement
// AstVar::user2 -> bool: Warned about SYNCASYNCNET // AstVar::user2 -> bool: Warned about SYNCASYNCNET
// AstVarNodeRef::user2 -> bool: ConcatOffset visited
AstUser1InUse m_inuser1; AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2; AstUser2InUse m_inuser2;
@@ -358,6 +373,7 @@ private:
void replaceAssigns(); void replaceAssigns();
void dedupe(); void dedupe();
void mergeAssigns(); void mergeAssigns();
void decomposeClkVectors();
// VISITORS // VISITORS
virtual void visit(AstNetlist* nodep) { virtual void visit(AstNetlist* nodep) {
@@ -365,6 +381,8 @@ private:
//if (debug()>6) m_graph.dump(); //if (debug()>6) m_graph.dump();
if (debug()>6) m_graph.dumpDotFilePrefixed("gate_pre"); if (debug()>6) m_graph.dumpDotFilePrefixed("gate_pre");
warnSignals(); // Before loss of sync/async pointers 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.removeRedundantEdgesSum(&V3GraphEdge::followAlwaysTrue);
m_graph.dumpDotFilePrefixed("gate_simp"); m_graph.dumpDotFilePrefixed("gate_simp");
// Find gate interconnect and optimize // Find gate interconnect and optimize
@@ -409,9 +427,9 @@ private:
} }
virtual void visit(AstNodeVarRef* nodep) { virtual void visit(AstNodeVarRef* nodep) {
if (m_scopep) { 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(); 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); GateVarVertex* vvertexp = makeVarVertex(varscp);
UINFO(5," VARREF to "<<varscp<<endl); UINFO(5," VARREF to "<<varscp<<endl);
if (m_inSenItem) vvertexp->setIsClock(); if (m_inSenItem) vvertexp->setIsClock();
@@ -484,7 +502,7 @@ private:
} }
virtual void visit(AstConcat* nodep) { virtual void visit(AstConcat* nodep) {
if (nodep->backp()->castNodeAssign() && nodep->backp()->castNodeAssign()->lhsp()==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); nodep->iterateChildren(*this);
} }
@@ -704,7 +722,7 @@ void GateVisitor::replaceAssigns() {
if (!vscp->valuep()->castNodeMath() if (!vscp->valuep()->castNodeMath()
|| vscp->valuep()->nextp()) { || vscp->valuep()->nextp()) {
vscp->dumpTree(cerr, "vscStrange: "); 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(); 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) // Convert VARSCOPE(ASSIGN(default, VARREF)) to just VARSCOPE(default)
+1 -1
View File
@@ -529,7 +529,7 @@ double V3Graph::orderDFSIterate(V3GraphVertex* vertexp) {
// Compute fanouts of each node // Compute fanouts of each node
// If forward edge, don't double count that fanout // If forward edge, don't double count that fanout
if (vertexp->user() == 2) return vertexp->fanout(); // Already processed it 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); vertexp->user(1);
double fanout = 0; double fanout = 0;
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
+2 -2
View File
@@ -44,7 +44,7 @@ DfaVertex* DfaGraph::findStart() {
startp = vvertexp; startp = vvertexp;
} }
} else { } else {
v3fatalSrc("Non DfaVertex in DfaGraph\n"); v3fatalSrc("Non DfaVertex in DfaGraph");
} }
} }
if (!startp) v3fatalSrc("No start point in NFA graph"); 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 // Remap edges
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
+3 -3
View File
@@ -277,7 +277,7 @@ private:
AstVarRef* exprvarrefp = nodep->user2p()->castVarRef(); AstVarRef* exprvarrefp = nodep->user2p()->castVarRef();
UINFO(8,"connectto: "<<nodep->user2p()<<endl); UINFO(8,"connectto: "<<nodep->user2p()<<endl);
if (!exprconstp && !exprvarrefp) { 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) { if (exprconstp) {
m_modp->addStmtp(new AstAssignW(nodep->fileline(), m_modp->addStmtp(new AstAssignW(nodep->fileline(),
@@ -362,7 +362,7 @@ private:
nodep->varp( exprvarrefp->varp() ); nodep->varp( exprvarrefp->varp() );
} }
else { else {
nodep->v3fatalSrc("Null connection?\n"); nodep->v3fatalSrc("Null connection?");
} }
} }
nodep->name(nodep->varp()->name()); nodep->name(nodep->varp()->name());
@@ -514,7 +514,7 @@ private:
AstNode* connectRefp = pinp->exprp(); AstNode* connectRefp = pinp->exprp();
if (!connectRefp->castConst() && !connectRefp->castVarRef()) { 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()) { if (pinNewVarp->isOutOnly() && connectRefp->castConst()) {
pinp->v3error("Output port is connected to a constant pin, electrical short"); pinp->v3error("Output port is connected to a constant pin, electrical short");
+109 -51
View File
@@ -90,7 +90,7 @@ private:
// Make a ASSIGNW (expr, pin) // Make a ASSIGNW (expr, pin)
AstNode* exprp = nodep->exprp()->cloneTree(false); AstNode* exprp = nodep->exprp()->cloneTree(false);
if (exprp->width() != nodep->modVarp()->width()) 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()) { if (nodep->modVarp()->isInout()) {
nodep->v3fatalSrc("Unsupported: Verilator is a 2-state simulator"); nodep->v3fatalSrc("Unsupported: Verilator is a 2-state simulator");
} else if (nodep->modVarp()->isOutput()) { } else if (nodep->modVarp()->isOutput()) {
@@ -154,14 +154,10 @@ public:
//###################################################################### //######################################################################
class InstDeVisitor : public AstNVisitor { class InstDeModVarVisitor : public AstNVisitor {
// Find all cells with arrays, and convert to non-arrayed // Expand all module variables, and save names for later reference
private: private:
// STATE // 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; typedef map<string,AstVar*> VarNameMap;
VarNameMap m_modVarNameMap; // Per module, name of cloned variables VarNameMap m_modVarNameMap; // Per module, name of cloned variables
@@ -172,15 +168,109 @@ private:
} }
// VISITORS // 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(); 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); nodep->iterateChildren(*this);
} }
virtual void visit(AstCell* nodep) { 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()) { if (nodep->rangep()) {
m_cellRangep = nodep->rangep(); m_cellRangep = nodep->rangep();
UINFO(4," CELL "<<nodep<<endl);
AstVar* ifaceVarp = nodep->nextp()->castVar(); AstVar* ifaceVarp = nodep->nextp()->castVar();
bool isIface = ifaceVarp bool isIface = ifaceVarp
@@ -199,9 +289,10 @@ private:
// The spec says we add [x], but that won't work in C... // The spec says we add [x], but that won't work in C...
newp->name(newp->name()+"__BRA__"+cvtToStr(m_instNum)+"__KET__"); newp->name(newp->name()+"__BRA__"+cvtToStr(m_instNum)+"__KET__");
newp->origName(newp->origName()+"__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 // If this AstCell is actually an interface instantiation, also clone the IfaceRef
// the IfaceRef. // within the same parent module as the cell
if (isIface) { if (isIface) {
AstUnpackArrayDType* arrdtype = ifaceVarp->dtypep()->castUnpackArrayDType(); AstUnpackArrayDType* arrdtype = ifaceVarp->dtypep()->castUnpackArrayDType();
AstIfaceRefDType* origIfaceRefp = arrdtype->subDTypep()->castIfaceRefDType(); AstIfaceRefDType* origIfaceRefp = arrdtype->subDTypep()->castIfaceRefDType();
@@ -229,42 +320,11 @@ private:
} }
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep); nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
} else { } else {
m_cellRangep = NULL;
nodep->iterateChildren(*this); 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) { virtual void visit(AstPin* nodep) {
// Any non-direct pins need reconnection with a part-select // Any non-direct pins need reconnection with a part-select
if (!nodep->exprp()) return; // No-connect if (!nodep->exprp()) return; // No-connect
@@ -334,30 +394,28 @@ private:
// Clone pin varp: // Clone pin varp:
for (int i = pinArrp->lsb(); i <= pinArrp->msb(); ++i) { for (int i = pinArrp->lsb(); i <= pinArrp->msb(); ++i) {
string varNewName = pinVarp->name() + "__BRA__" + cvtToStr(i) + "__KET__"; string varNewName = pinVarp->name() + "__BRA__" + cvtToStr(i) + "__KET__";
VarNameMap::iterator it = m_modVarNameMap.find(varNewName);
AstVar* varNewp = NULL; 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 (!pinVarp->backp()) {
if (it != m_modVarNameMap.end()) { varNewp = m_deModVars.find(varNewName);
varNewp = it->second;
}
} else { } else {
AstIfaceRefDType* ifaceRefp = pinArrp->subDTypep()->castIfaceRefDType(); AstIfaceRefDType* ifaceRefp = pinArrp->subDTypep()->castIfaceRefDType();
ifaceRefp->cellp(NULL); ifaceRefp->cellp(NULL);
varNewp = pinVarp->cloneTree(false); varNewp = pinVarp->cloneTree(false);
m_modVarNameMap.insert(make_pair(varNewName, varNewp));
varNewp->name(varNewName); varNewp->name(varNewName);
varNewp->origName(varNewp->origName() + "__BRA__" + cvtToStr(i) + "__KET__"); varNewp->origName(varNewp->origName() + "__BRA__" + cvtToStr(i) + "__KET__");
varNewp->dtypep(ifaceRefp); varNewp->dtypep(ifaceRefp);
m_deModVars.insert(varNewp);
if (!prevp) { if (!prevp) {
prevp = varNewp; prevp = varNewp;
} else { } else {
prevp->addNextHere(varNewp); prevp->addNextHere(varNewp);
} }
} }
if (varNewp == NULL) { if (!varNewp) {
nodep->v3fatalSrc("Module dearray failed\n"); if (debug()>=9) m_deModVars.dump();
nodep->v3fatalSrc("Module dearray failed for "<<AstNode::prettyName(varNewName));
} }
// But clone the pin for each module instance // But clone the pin for each module instance
+10 -6
View File
@@ -445,6 +445,10 @@ public:
<<") <- se"<<srcp<<" "<<srcp->nodep()<<endl); <<") <- se"<<srcp<<" "<<srcp->nodep()<<endl);
// srcp should be an interface reference pointing to the interface we want to import // srcp should be an interface reference pointing to the interface we want to import
lhsp->importFromIface(symsp(), srcp); 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 //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) { virtual void visit(AstNodeFTask* nodep) {
// NodeTask: Remember its name for later resolution // NodeTask: Remember its name for later resolution
UINFO(5," "<<nodep<<endl); 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 // Remember the existing symbol table scope
VSymEnt* oldCurSymp = m_curSymp; VSymEnt* oldCurSymp = m_curSymp;
{ {
@@ -873,7 +877,7 @@ class LinkDotFindVisitor : public AstNVisitor {
} }
virtual void visit(AstVar* nodep) { virtual void visit(AstVar* nodep) {
// Var: Remember its name for later resolution // 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); nodep->iterateChildren(*this);
if (!m_statep->forScopeCreation()) { if (!m_statep->forScopeCreation()) {
// Find under either a task or the module's vars // Find under either a task or the module's vars
@@ -957,12 +961,12 @@ class LinkDotFindVisitor : public AstNVisitor {
} }
virtual void visit(AstTypedef* nodep) { virtual void visit(AstTypedef* nodep) {
// Remember its name for later resolution // 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); nodep->iterateChildren(*this);
m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep); m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep);
} }
virtual void visit(AstParamTypeDType* nodep) { 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); nodep->iterateChildren(*this);
m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep); m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep);
} }
@@ -1593,7 +1597,7 @@ private:
checkNoDot(nodep); checkNoDot(nodep);
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
if (!nodep->modVarp()) { 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()); VSymEnt* foundp = m_pinSymp->findIdFlat(nodep->name());
const char* whatp = nodep->param() ? "parameter pin" : "pin"; const char* whatp = nodep->param() ? "parameter pin" : "pin";
if (!foundp) { if (!foundp) {
@@ -1861,7 +1865,7 @@ private:
} }
// //
if (!ok) { if (!ok) {
//Cells/interfaces can't be implicit // Cells/interfaces can't be implicit
bool isCell = foundp ? foundp->nodep()->castCell() != NULL : false; bool isCell = foundp ? foundp->nodep()->castCell() != NULL : false;
bool checkImplicit = (!m_ds.m_dotp && m_ds.m_dotText=="" && !isCell); bool checkImplicit = (!m_ds.m_dotp && m_ds.m_dotText=="" && !isCell);
bool err = !(checkImplicit && m_statep->implicitOk(m_modp, nodep->name())); bool err = !(checkImplicit && m_statep->implicitOk(m_modp, nodep->name()));
+3 -1
View File
@@ -174,8 +174,10 @@ private:
virtual void visit(AstValuePlusArgs* nodep) { virtual void visit(AstValuePlusArgs* nodep) {
bool last_setRefLvalue = m_setRefLvalue; bool last_setRefLvalue = m_setRefLvalue;
{ {
m_setRefLvalue = false;
nodep->searchp()->iterateAndNext(*this);
m_setRefLvalue = true; m_setRefLvalue = true;
nodep->exprsp()->iterateAndNext(*this); nodep->outp()->iterateAndNext(*this);
} }
m_setRefLvalue = last_setRefLvalue; m_setRefLvalue = last_setRefLvalue;
} }
+2 -2
View File
@@ -236,12 +236,12 @@ private:
virtual void visit(AstPragma* nodep) { virtual void visit(AstPragma* nodep) {
if (nodep->pragType() == AstPragmaType::PUBLIC_MODULE) { 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); m_modp->modPublic(true);
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep); nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
} }
else if (nodep->pragType() == AstPragmaType::PUBLIC_TASK) { 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_ftaskp->taskPublic(true);
m_modp->modPublic(true); // Need to get to the task... m_modp->modPublic(true); // Need to get to the task...
nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep); nodep->unlinkFrBack(); pushDeletep(nodep); VL_DANGLING(nodep);
+12 -6
View File
@@ -48,7 +48,7 @@ V3Number::V3Number(VerilogStringLiteral, FileLine* fileline, const string& str)
} }
} }
} }
opCleanThis(); opCleanThis(true);
} }
V3Number::V3Number (FileLine* fileline, const char* sourcep) { V3Number::V3Number (FileLine* fileline, const char* sourcep) {
@@ -254,7 +254,7 @@ V3Number::V3Number (FileLine* fileline, const char* sourcep) {
setBit(obit, bitIs(obit-1)); setBit(obit, bitIs(obit-1));
obit++; obit++;
} }
opCleanThis(); opCleanThis(true);
//printf("Dump \"%s\" CP \"%s\" B '%c' %d W %d\n", sourcep, value_startp, base, width(), m_value[0]); //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); return opSel(lhs, bits-1, 0);
} }
void V3Number::opCleanThis() { void V3Number::opCleanThis(bool warnOnTruncation) {
// Clean in place number // Clean MSB of number
m_value[words()-1] &= hiWordMask(); uint32_t newValueMsb = m_value[words()-1] & hiWordMask();
m_valueX[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) { V3Number& V3Number::opSel (const V3Number& lhs, const V3Number& msb, const V3Number& lsb) {
+1 -1
View File
@@ -45,7 +45,7 @@ class V3Number {
// METHODS // METHODS
V3Number& setSingleBits(char value); V3Number& setSingleBits(char value);
V3Number& setString(const string& str) { m_isString=true; m_stringVal=str; return *this; } V3Number& setString(const string& str) { m_isString=true; m_stringVal=str; return *this; }
void opCleanThis(); void opCleanThis(bool warnOnTruncation = false);
public: public:
FileLine* fileline() const { return m_fileline; } FileLine* fileline() const { return m_fileline; }
void fileline(FileLine* fl) { m_fileline=fl; } void fileline(FileLine* fl) { m_fileline=fl; }
+1 -1
View File
@@ -84,7 +84,7 @@ void test(string lhss, string op, string rhss, string exps) {
V3Number ok (new FileLine("ck",__LINE__), 1); V3Number ok (new FileLine("ck",__LINE__), 1);
ok.opCaseEq(expnum,gotnum); ok.opCaseEq(expnum,gotnum);
if (ok.toUInt()!=1) { if (ok.toUInt()!=1) {
v3fatalSrc("%Error:Test FAILED\n"); v3fatalSrc("%Error:Test FAILED");
} }
} }
+2 -2
View File
@@ -560,7 +560,7 @@ string V3Options::version() {
void V3Options::throwSigsegv() { void V3Options::throwSigsegv() {
// cppcheck-suppress nullPointer // 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=="-no-arg", then return true (found it), and flag=false
// if sw=="-noarg", then return true (found it), and flag=false // if sw=="-noarg", then return true (found it), and flag=false
// else return 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; } 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",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; } else if (0==strncmp(sw,"-no-",4) && (0==strcmp(sw+4,arg+1))) { flag=false; return true; }
+5 -5
View File
@@ -194,7 +194,7 @@ public:
// METHODS // METHODS
OrderVarVertex* newVarUserVertex(V3Graph* graphp, AstScope* scopep, OrderVarVertex* newVarUserVertex(V3Graph* graphp, AstScope* scopep,
AstVarScope* varscp, WhichVertex type, bool* createdp=NULL) { 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]; OrderVarVertex* vertexp = m_vertexp[type];
if (!vertexp) { if (!vertexp) {
UINFO(6,"New vertex "<<varscp<<endl); UINFO(6,"New vertex "<<varscp<<endl);
@@ -205,7 +205,7 @@ public:
case WV_PORD: vertexp = new OrderVarPordVertex (graphp, scopep, varscp); break; case WV_PORD: vertexp = new OrderVarPordVertex (graphp, scopep, varscp); break;
case WV_POST: vertexp = new OrderVarPostVertex (graphp, scopep, varscp); break; case WV_POST: vertexp = new OrderVarPostVertex (graphp, scopep, varscp); break;
case WV_SETL: vertexp = new OrderVarSettleVertex(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; m_vertexp[type] = vertexp;
} else { } else {
@@ -806,15 +806,15 @@ private:
virtual void visit(AstNodeVarRef* nodep) { virtual void visit(AstNodeVarRef* nodep) {
if (m_scopep) { if (m_scopep) {
AstVarScope* varscp = nodep->varScopep(); 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) { if (m_inSenTree) {
// Add CLOCK dependency... This is a root of the tree we'll trace // 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); OrderVarVertex* varVxp = newVarUserVertex(varscp, WV_STD);
varVxp->isClock(true); varVxp->isClock(true);
new OrderEdge(&m_graph, varVxp, m_activeSenVxp, WEIGHT_MEDIUM); new OrderEdge(&m_graph, varVxp, m_activeSenVxp, WEIGHT_MEDIUM);
} else { } 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 // What new directions is this used
// We don't want to add extra edges if the logic block has many usages of same var // We don't want to add extra edges if the logic block has many usages of same var
bool gen = false; bool gen = false;
+61 -3
View File
@@ -204,7 +204,7 @@ private:
pinp->modPTypep(cloneiter->second->castParamTypeDType()); pinp->modPTypep(cloneiter->second->castParamTypeDType());
} }
else { else {
pinp->v3fatalSrc("Not linked?\n"); pinp->v3fatalSrc("Not linked?");
} }
} }
} }
@@ -283,7 +283,59 @@ private:
virtual void visit(AstVarRef* nodep) { virtual void visit(AstVarRef* nodep) {
if (nodep->varp()) nodep->varp()->iterate(*this); 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) { 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 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 (AstVar* modvarp = pinp->modVarp()) {
if (!modvarp->isGParam()) { if (!modvarp->isGParam()) {
pinp->v3error("Attempted parameter setting of non-parameter: Param "<<pinp->prettyName()<<" of "<<nodep->prettyName()); 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 { } else {
AstConst* exprp = pinp->exprp()->castConst(); AstConst* exprp = pinp->exprp()->castConst();
AstConst* origp = modvarp->valuep()->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()) { for (AstPin* pinp = nodep->paramsp(); pinp; pinp=pinp->nextp()->castPin()) {
if (pinp->exprp()) { if (pinp->exprp()) {
if (AstVar* modvarp = pinp->modVarp()) { if (AstVar* modvarp = pinp->modVarp()) {
AstConst* constp = pinp->exprp()->castConst(); AstNode* newp = pinp->exprp(); // Const or InitArray
// Remove any existing parameter // Remove any existing parameter
if (modvarp->valuep()) modvarp->valuep()->unlinkFrBack()->deleteTree(); if (modvarp->valuep()) modvarp->valuep()->unlinkFrBack()->deleteTree();
// Set this parameter to value requested by cell // Set this parameter to value requested by cell
modvarp->valuep(constp->cloneTree(false)); modvarp->valuep(newp->cloneTree(false));
} }
else if (AstParamTypeDType* modptp = pinp->modPTypep()) { else if (AstParamTypeDType* modptp = pinp->modPTypep()) {
AstNodeDType* dtypep = pinp->exprp()->castNodeDType(); AstNodeDType* dtypep = pinp->exprp()->castNodeDType();
+78
View File
@@ -44,12 +44,25 @@
#include "V3Task.h" #include "V3Task.h"
#include <deque> #include <deque>
#include <sstream>
//============================================================================ //============================================================================
//###################################################################### //######################################################################
// Simulate class functions // 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 { class SimulateVisitor : public AstNVisitor {
// Simulate a node tree, returning value of variables // Simulate a node tree, returning value of variables
// Two major operating modes: // Two major operating modes:
@@ -90,6 +103,7 @@ private:
// Simulating: // Simulating:
deque<V3Number*> m_numFreeps; ///< List of all numbers free and not in use 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<V3Number*> m_numAllps; ///< List of all numbers free and in use
deque<SimulateStackNode*> m_callStack; ///< Call stack for verbose error messages
// Cleanup // Cleanup
// V3Numbers that represents strings are a bit special and the API for V3Number does not allow changing them. // 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; 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 // Checking METHODS
public: public:
/// Call other-this function on all new *non-constant* var references /// Call other-this function on all new *non-constant* var references
@@ -119,6 +181,19 @@ public:
cout<<endl; cout<<endl;
} }
m_whyNotOptimizable = why; 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; } 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 // Evaluate the function
funcp->accept(*this); funcp->accept(*this);
m_callStack.pop_front();
if (!m_checkOnly && optimizable()) { if (!m_checkOnly && optimizable()) {
// Grab return value from output variable (if it's a function) // Grab return value from output variable (if it's a function)
if (!funcp->fvarp()) nodep->v3fatalSrc("Function reference points at non-function"); if (!funcp->fvarp()) nodep->v3fatalSrc("Function reference points at non-function");
+4 -4
View File
@@ -272,12 +272,12 @@ private:
//UINFO(9," push "<<nodep<<endl); //UINFO(9," push "<<nodep<<endl);
SplitLogicVertex* vertexp = new SplitLogicVertex(&m_graph, nodep); SplitLogicVertex* vertexp = new SplitLogicVertex(&m_graph, nodep);
m_stmtStackps.push_back(vertexp); 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); nodep->user3p(vertexp);
} }
void scoreboardPopStmt() { void scoreboardPopStmt() {
//UINFO(9," pop"<<endl); //UINFO(9," pop"<<endl);
if (m_stmtStackps.empty()) v3fatalSrc("Stack underflow\n"); if (m_stmtStackps.empty()) v3fatalSrc("Stack underflow");
m_stmtStackps.pop_back(); m_stmtStackps.pop_back();
} }
@@ -346,8 +346,8 @@ private:
SplitLogicVertex* vvertexp = (SplitLogicVertex*)nextp->user3p(); SplitLogicVertex* vvertexp = (SplitLogicVertex*)nextp->user3p();
vvertexp->splitColor(vvertexp->color()); vvertexp->splitColor(vvertexp->color());
uint32_t color = vvertexp->splitColor(); uint32_t color = vvertexp->splitColor();
if (color >= numVertexes) nextp->v3fatalSrc("More colors than vertexes!\n"); if (color >= numVertexes) nextp->v3fatalSrc("More colors than vertexes");
if (!color) nextp->v3fatalSrc("No node color assigned\n"); if (!color) nextp->v3fatalSrc("No node color assigned");
if (lastOfColor[color]) { if (lastOfColor[color]) {
new SplitStrictEdge(&m_graph, lastOfColor[color], vvertexp); new SplitStrictEdge(&m_graph, lastOfColor[color], vvertexp);
} }
+8 -5
View File
@@ -183,16 +183,19 @@ public:
} }
return any; 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 // Import interface tokens from source symbol table into this symbol table, recursively
UINFO(9, " importIf se"<<(void*)this<<" from se"<<(void*)srcp<<endl); 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) { for (IdNameMap::const_iterator it=srcp->m_idNameMap.begin(); it!=srcp->m_idNameMap.end(); ++it) {
const string& name = it->first; const string& name = it->first;
VSymEnt* subSrcp = it->second; VSymEnt* subSrcp = it->second;
VSymEnt* subSymp = new VSymEnt(graphp, subSrcp); AstVar* varp = subSrcp->nodep()->castVar();
reinsert(name, subSymp); if (!onlyUnmodportable || (varp && varp->varType() == AstVarType::GPARAM)) {
// And recurse to create children VSymEnt* subSymp = new VSymEnt(graphp, subSrcp);
subSymp->importFromIface(graphp, subSrcp); reinsert(name, subSymp);
// And recurse to create children
subSymp->importFromIface(graphp, subSrcp);
}
} }
} }
void cellErrorScopes(AstNode* lookp, string prettyName="") { void cellErrorScopes(AstNode* lookp, string prettyName="") {
+2 -2
View File
@@ -263,7 +263,7 @@ private:
if (nodep->varp()->user2p()) { // It's being converted to a alias. if (nodep->varp()->user2p()) { // It's being converted to a alias.
UINFO(9, " relinkVar "<<(void*)nodep->varp()->user2p()<<" "<<nodep<<endl); UINFO(9, " relinkVar "<<(void*)nodep->varp()->user2p()<<" "<<nodep<<endl);
AstVarScope* newvscp = nodep->varp()->user2p()->castVarScope(); AstVarScope* newvscp = nodep->varp()->user2p()->castVarScope();
if (!newvscp) nodep->v3fatalSrc("Null?\n"); if (!newvscp) nodep->v3fatalSrc("not linked");
nodep->varScopep(newvscp); nodep->varScopep(newvscp);
nodep->varp(nodep->varScopep()->varp()); nodep->varp(nodep->varScopep()->varp());
nodep->name(nodep->varp()->name()); nodep->name(nodep->varp()->name());
@@ -1147,7 +1147,7 @@ private:
m_insStmtp = NULL; // Next thing should be new statement m_insStmtp = NULL; // Next thing should be new statement
} }
virtual void visit(AstNodeFor* nodep) { 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) { virtual void visit(AstNodeStmt* nodep) {
m_insMode = IM_BEFORE; m_insMode = IM_BEFORE;
+1 -1
View File
@@ -387,7 +387,7 @@ private:
} else if (basefromp->castConst()) { } else if (basefromp->castConst()) {
// If it's a PARAMETER[bit], then basefromp may be a constant instead of a varrefp // If it's a PARAMETER[bit], then basefromp may be a constant instead of a varrefp
} else { } 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 // Find range of dtype we are selecting from
int declElements = -1; int declElements = -1;
+20 -15
View File
@@ -2094,8 +2094,9 @@ private:
} }
virtual void visit(AstValuePlusArgs* nodep) { virtual void visit(AstValuePlusArgs* nodep) {
if (m_vup->prelim()) { if (m_vup->prelim()) {
userIterateAndNext(nodep->exprsp(), WidthVP(SELF,BOTH).p()); userIterateAndNext(nodep->searchp(), WidthVP(SELF,BOTH).p());
nodep->dtypeSetSigned32(); // Spec says integer return userIterateAndNext(nodep->outp(), WidthVP(SELF,BOTH).p());
nodep->dtypeChgWidthSigned(32,1,AstNumeric::SIGNED); // Spec says integer return
} }
} }
virtual void visit(AstUCStmt* nodep) { virtual void visit(AstUCStmt* nodep) {
@@ -2136,7 +2137,8 @@ private:
AstNodeDType* subDTypep = pinDTypep; AstNodeDType* subDTypep = pinDTypep;
int pinwidth = pinDTypep->width(); int pinwidth = pinDTypep->width();
int conwidth = conDTypep->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()); userIterateAndNext(nodep->exprp(), WidthVP(subDTypep,FINAL).p());
} }
else if (m_cellRangep) { else if (m_cellRangep) {
@@ -2178,22 +2180,22 @@ private:
} }
// TODO Simple dtype checking, should be a more general check // TODO Simple dtype checking, should be a more general check
AstNodeArrayDType* loArrayp = exprDTypep->skipRefp()->castUnpackArrayDType(); AstNodeArrayDType* exprArrayp = exprDTypep->skipRefp()->castUnpackArrayDType();
AstNodeArrayDType* hiArrayp = modDTypep->skipRefp()->castUnpackArrayDType(); AstNodeArrayDType* modArrayp = modDTypep->skipRefp()->castUnpackArrayDType();
if (loArrayp && hiArrayp && loArrayp->subDTypep()->skipRefp()->castIfaceRefDType() if (exprArrayp && modArrayp && exprArrayp->subDTypep()->skipRefp()->castIfaceRefDType()
&& loArrayp->declRange().elements() != hiArrayp->declRange().elements()) { && exprArrayp->declRange().elements() != modArrayp->declRange().elements()) {
int loSize = loArrayp->declRange().elements(); int exprSize = exprArrayp->declRange().elements();
int hiSize = hiArrayp->declRange().elements(); int modSize = modArrayp->declRange().elements();
nodep->v3error("Illegal "<<nodep->prettyOperatorName()<<"," nodep->v3error("Illegal "<<nodep->prettyOperatorName()<<","
<<" mismatch between port which is an interface array of size "<<loSize<<"," <<" mismatch between port which is an interface array of size "<<modSize<<","
<<" and expression which is an interface array of size "<<hiSize<<"."); <<" and expression which is an interface array of size "<<exprSize<<".");
UINFO(1," Related lo: "<<modDTypep->skipRefp()<<endl); UINFO(1," Related lo: "<<modDTypep->skipRefp()<<endl);
UINFO(1," Related hi: "<<exprDTypep->skipRefp()<<endl); UINFO(1," Related hi: "<<exprDTypep->skipRefp()<<endl);
} else if ((loArrayp && !hiArrayp && pinwidth != conwidth) } else if ((exprArrayp && !modArrayp && pinwidth != conwidth)
|| (!loArrayp && hiArrayp && pinwidth != conwidth)) { || (!exprArrayp && modArrayp && pinwidth != conwidth)) {
nodep->v3error("Illegal "<<nodep->prettyOperatorName()<<"," nodep->v3error("Illegal "<<nodep->prettyOperatorName()<<","
<<" mismatch between port which is"<<(loArrayp?"":" not")<<" an array," <<" mismatch between port which is"<<(modArrayp?"":" not")<<" an array,"
<<" and expression which is"<<(hiArrayp?"":" not")<<" an array."); <<" and expression which is"<<(exprArrayp?"":" not")<<" an array.");
UINFO(1," Related lo: "<<modDTypep->skipRefp()<<endl); UINFO(1," Related lo: "<<modDTypep->skipRefp()<<endl);
UINFO(1," Related hi: "<<exprDTypep->skipRefp()<<endl); UINFO(1," Related hi: "<<exprDTypep->skipRefp()<<endl);
} }
@@ -2909,6 +2911,9 @@ private:
return false; // No change return false; // No change
} }
bool similarDTypeRecurse(AstNodeDType* node1p, AstNodeDType* node2p) {
return node1p->skipRefp()->similarDType(node2p->skipRefp());
}
void iterateCheckFileDesc (AstNode* nodep, AstNode* underp, Stage stage) { void iterateCheckFileDesc (AstNode* nodep, AstNode* underp, Stage stage) {
if (stage != BOTH) nodep->v3fatalSrc("Bad call"); if (stage != BOTH) nodep->v3fatalSrc("Bad call");
// underp may change as a result of replacement // underp may change as a result of replacement
+1 -1
View File
@@ -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=="-no-arg", then return true (found it), and flag=false
// if sw=="-noarg", then return true (found it), and flag=false // if sw=="-noarg", then return true (found it), and flag=false
// else return 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; } 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",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; } else if (0==strncmp(sw,"-no-",4) && (0==strcmp(sw+4,arg+1))) { flag=false; return true; }
+1 -1
View File
@@ -873,7 +873,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
/* Attributes */ /* Attributes */
/* Note simulators vary in support for "(* /_*something*_/ foo*)" where _ doesn't exist */ /* Note simulators vary in support for "(* /_*something*_/ foo*)" where _ doesn't exist */
<V95,V01,V05,VA5,S05,S09,S12,SAX>{ <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
View File
@@ -2710,12 +2710,12 @@ system_f_call<nodep>: // IEEE: system_tf_call (as func)
| yD_SQRT '(' expr ')' { $$ = new AstSqrtD($1,$3); } | yD_SQRT '(' expr ')' { $$ = new AstSqrtD($1,$3); }
| yD_SSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstSScanF($1,*$5,$3,$6); } | yD_SSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstSScanF($1,*$5,$3,$6); }
| yD_STIME parenE { $$ = new AstSel($1,new AstTime($1),0,32); } | 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_TESTPLUSARGS '(' str ')' { $$ = new AstTestPlusArgs($1,*$3); }
| yD_TIME parenE { $$ = new AstTime($1); } | yD_TIME parenE { $$ = new AstTime($1); }
| yD_UNPACKED_DIMENSIONS '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_UNPK_DIMENSIONS,$3); } | yD_UNPACKED_DIMENSIONS '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_UNPK_DIMENSIONS,$3); }
| yD_UNSIGNED '(' expr ')' { $$ = new AstUnsigned($1,$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 exprOrDataType<nodep>: // expr | data_type: combined to prevent conflicts
+19
View File
@@ -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;
+33
View File
@@ -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
+18
View File
@@ -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;
+97
View File
@@ -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
+18
View File
@@ -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;
+106
View File
@@ -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
+18
View File
@@ -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;
+101
View File
@@ -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
+18
View File
@@ -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;
+105
View File
@@ -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
+18
View File
@@ -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;
+104
View File
@@ -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
+18
View File
@@ -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;
+113
View File
@@ -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
+31
View File
@@ -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;
+28
View File
@@ -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
+29 -14
View File
@@ -11,24 +11,39 @@ compile (
v_flags2 => ["--lint-only"], v_flags2 => ["--lint-only"],
fails=>1, fails=>1,
expect=> 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' 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:\d+: ... Location of non-constant VAR 'o': Language violation: Outputs not allowed in constant functions %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:\d+: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_dotted' %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:\d+: ... Location of non-constant VARXREF 'EIGHT': Language violation: Dotted hierarchical references not allowed in constant functions %Error: t/t_func_const_bad.v:22: ... 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' Called from:
%Error: t/t_func_const_bad.v:\d+: ... Location of non-constant VARREF 'modvar': Language violation: reference to non-function-local variable t/t_func_const_bad.v:20: f_bad_dotted() with parameters:
%Error: t/t_func_const_bad.v:\d+: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_infinite' a = ?32?sh2
%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:27: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_nonparam'
%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:29: ... Location of non-constant VARREF 'modvar': Language violation: reference to non-function-local variable
%Error: t/t_func_const_bad.v:\d+: ... Location of non-constant STOP: .stop executed during function constification; maybe indicates assertion firing 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: 0
-Info: Printing in loop: 1 -Info: Printing in loop: 1
-Info: Printing in loop: 2 -Info: Printing in loop: 2
%Warning-USERFATAL: Fatal Error %Warning-USERFATAL: Fatal Error
%Warning-USERFATAL: Use ... verilator lint_off USERFATAL ... and lint_on around source to disable this message. %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:49: 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: t/t_func_const_bad.v:54: ... Location of non-constant STOP: $stop executed during function constification; maybe indicates assertion firing
%Error: Exiting due to.*}, Called from:
t/t_func_const_bad.v:49: f_bad_fatal() with parameters:
a = ?32?sh3
},
); );
ok(1); ok(1);
+30
View File
@@ -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
View File
@@ -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
View File
@@ -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
+30
View File
@@ -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;
+39
View File
@@ -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
+18
View File
@@ -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;
+85
View File
@@ -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
View File
@@ -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
+2 -2
View File
@@ -10,8 +10,8 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
compile ( compile (
fails=>1, fails=>1,
expect=> 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. 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 6, 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 5, and expression which is an interface array of size 6.
%Error: Exiting due to.*}, %Error: Exiting due to.*},
); );
+20
View File
@@ -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;
+11
View File
@@ -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
+18
View File
@@ -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;
+72
View File
@@ -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
+18
View File
@@ -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;
+21
View File
@@ -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
+27 -1
View File
@@ -8,6 +8,8 @@ module t;
integer p_i; integer p_i;
reg [7*8:1] p_str; reg [7*8:1] p_str;
string sv_str; string sv_str;
reg [7*8:1] p_in;
string sv_in;
initial begin initial begin
if ($test$plusargs("PLUS")!==1) $stop; if ($test$plusargs("PLUS")!==1) $stop;
@@ -20,23 +22,47 @@ module t;
if ($value$plusargs("NOTTHERE%d", p_i)!==0) $stop; if ($value$plusargs("NOTTHERE%d", p_i)!==0) $stop;
if (p_i !== 10) $stop; if (p_i !== 10) $stop;
p_i = 0;
if ($value$plusargs("INT=%d", p_i)!==1) $stop; if ($value$plusargs("INT=%d", p_i)!==1) $stop;
if (p_i !== 32'd1234) $stop; if (p_i !== 32'd1234) $stop;
p_i = 0;
if ($value$plusargs("INT=%H", p_i)!==1) $stop; // tests uppercase % also if ($value$plusargs("INT=%H", p_i)!==1) $stop; // tests uppercase % also
if (p_i !== 32'h1234) $stop; 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; if (p_i !== 32'o1234) $stop;
p_str = "none";
if ($value$plusargs("IN%s", p_str)!==1) $stop; if ($value$plusargs("IN%s", p_str)!==1) $stop;
$display("str='%s'",p_str); $display("str='%s'",p_str);
if (p_str !== "T=1234") $stop; if (p_str !== "T=1234") $stop;
sv_str = "none";
if ($value$plusargs("IN%s", sv_str)!==1) $stop; if ($value$plusargs("IN%s", sv_str)!==1) $stop;
$display("str='%s'",sv_str); $display("str='%s'",sv_str);
if (sv_str != "T=1234") $stop; 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"); $write("*-* All Finished *-*\n");
$finish; $finish;
end end
+5 -7
View File
@@ -8,13 +8,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Version 2.0. # Version 2.0.
compile ( compile (
fails=>$Self->{v3}, );
expect=>
q{%Error: t/t_sys_plusargs_bad.v:\d+: Missing or extra \$value\$plusargs format qualifier: 'NOTTHERE' execute (
%Error: t/t_sys_plusargs_bad.v:\d+: Illegal \$value\$plusargs format qualifier: 'z' check_finished=>1,
%Error: t/t_sys_plusargs_bad.v:\d+: Missing or extra \$value\$plusargs format qualifier: 'INT=%x%x' );
%Error: Exiting due to.*},
);
ok(1); ok(1);
1; 1;
+2 -1
View File
@@ -17,6 +17,7 @@ module t;
// BAD: Multi letter // BAD: Multi letter
if ($value$plusargs("INT=%x%x", p_i)!==0) $stop; if ($value$plusargs("INT=%x%x", p_i)!==0) $stop;
$stop; $write("*-* All Finished *-*\n");
$finish;
end end
endmodule endmodule
+61 -8
View File
@@ -6,8 +6,6 @@
`begin_keywords "VAMS-2.3" `begin_keywords "VAMS-2.3"
module t (/*autoarg*/ module t (/*autoarg*/
// Outputs
aout,
// Inputs // Inputs
clk, in clk, in
); );
@@ -15,21 +13,43 @@ module t (/*autoarg*/
input clk; input clk;
input [15:0] in; input [15:0] in;
output aout;
wreal aout; wreal aout;
integer cyc=0; integer cyc=0;
real vin; real vin;
real gnd; wreal vpass;
through through (.vin, .vpass);
real gnd;
wire out; wire out;
within_range within_range (/*AUTOINST*/ within_range within_range (/*AUTOINST*/
// Interfaces // Interfaces
.vin (vin), .vpass (vpass),
.gnd (gnd), .gnd (gnd),
// Outputs // Outputs
.out (out)); .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; parameter real lsb = 1;
// verilator lint_off WIDTH // verilator lint_off WIDTH
assign aout = $itor(in) * lsb; assign aout = $itor(in) * lsb;
@@ -70,14 +90,47 @@ module t (/*autoarg*/
endmodule endmodule
module within_range module through
(input wreal vin, (input wreal vin,
output wreal vpass);
assign vpass = vin;
endmodule
module within_range
(input wreal vpass,
input wreal gnd, input wreal gnd,
output out); output out);
parameter real V_MIN = 0.5; parameter real V_MIN = 0.5;
parameter real V_MAX = 10; 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); wire out = (V_MIN <= in_int && in_int <= V_MAX);
endmodule 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