Compare commits

...
18 Commits
Author SHA1 Message Date
Wilson Snyder 55f0d4ddd8 Version bump 2014-11-15 08:38:44 -05:00
Wilson Snyder 6d66fcaa57 Fix +define+A+B to define A and B to match other simulators, bug847. 2014-11-13 19:05:07 -05:00
Wilson Snyder 26e79ca889 Fix quoted comment slashes in defines, bug845. 2014-11-12 16:37:51 -05:00
Wilson Snyder 62eb247c1e Optimize SUB/ADD together. 2014-11-09 18:33:54 -05:00
Wilson Snyder c5fd583b2c Fix select when partially out-of-bound, bug823. 2014-11-09 18:29:52 -05:00
Wilson Snyder 117db3e11c Trace_off now operates on cells, bug826. 2014-11-08 14:15:10 -05:00
Wilson Snyder 3f82fd2f37 Add public enums, bug833. 2014-11-07 07:50:11 -05:00
Wilson Snyder e9c46afcf7 Fix public parameters in unused packages, bug804. 2014-11-06 17:53:01 -05:00
Wilson Snyder 3234fa15ef Fix trace overflow on huge arrays, bug834. 2014-11-05 22:22:27 -05:00
Jie Xu 7ef84df852 Add optimization of wires from arrayed cells, msg1447.
Signed-off-by: Wilson Snyder <[email protected]>
2014-11-05 21:09:35 -05:00
Jie Xu 4e2884b509 Optimize e.g. {(b<<4)[7:4], (b<<4)[3:0]}. From assignmerge tree.
Signed-off-by: Wilson Snyder <[email protected]>
2014-11-05 20:58:36 -05:00
Wilson Snyder 03100020ab Fix not tracing modules following primitives, bug837. 2014-11-04 07:49:03 -05:00
Wilson Snyder 8bfb5cc5e9 Internals: Add sameGateTree. 2014-11-02 19:52:49 -05:00
Wilson Snyder cf6d07aafa Add optimization of operators between concats, msg1447. 2014-10-22 21:44:41 -04:00
Wilson Snyder 85c3179dbd Commentary 2014-10-21 19:11:46 -04:00
Wilson Snyder bfbca34eb0 Fix cast-to-size context-determined sizing, bug828. 2014-10-17 19:01:04 -04:00
Wilson Snyder b73edc0564 Fix generate unrolling with function call, bug830. 2014-10-15 21:29:37 -04:00
Wilson Snyder 6ba90e3a50 devel release 2014-09-21 09:06:40 -04:00
57 changed files with 1431 additions and 108 deletions
+27
View File
@@ -3,6 +3,33 @@ Revision history for Verilator
The contributors that suggested a given feature are shown in []. [by ...]
indicates the contributor was also the author of the fix; Thanks!
* Verilator 3.866 2014-11-15
*** Fix +define+A+B to define A and B to match other simulators, bug847. [Adam Krolnik]
*** Add optimization of wires from arrayed cells, msg1447. [Jie Xu]
*** Add optimization of operators between concats, msg1447. [Jie Xu]
*** Add public enums, bug833. [Jonathon Donaldson]
*** Trace_off now operates on cells, bug826. [Lane Brooks]
**** Fix public parameters in unused packages, bug804. [Jonathon Donaldson]
**** Fix select when partially out-of-bound, bug823. [Cliffort Wolf]
**** Fix generate unrolling with function call, bug830. [Steven Slatter]
**** Fix cast-to-size context-determined sizing, bug828. [Geoff Barrett]
**** Fix not tracing modules following primitives, bug837. [Jie Xu]
**** Fix trace overflow on huge arrays, bug834. [Geoff Barrett]
**** Fix quoted comment slashes in defines, bug845. [Adam Krolnik]
* Verilator 3.864 2014-09-21
*** Support power operator with real, bug809. [Jonathon Donaldson]
+29 -13
View File
@@ -267,7 +267,7 @@ descriptions in the next sections for more information.
--debugi <level> Enable debugging at a specified level
--debugi-<srcfile> <level> Enable debugging a source file at a level
--default-language <lang> Default language to parse
+define+<var>+<value> Set preprocessor define
+define+<var>=<value> Set preprocessor define
--dump-tree Enable dumping .tree files
--dump-treei <level> Enable dumping .tree files at a level
-E Preprocess, but do not compile
@@ -572,13 +572,16 @@ the comment "DefaultClock":
=item -DI<var>=I<value>
Defines the given preprocessor symbol. Same as +define; +define is fairly
standard across Verilog tools while -D is an alias for GCC compatibility.
Defines the given preprocessor symbol, without allowing. Similar to
+define; +define is fairly standard across Verilog tools while -D is an
alias for GCC compatibility.
=item --debug
Select the debug built image of Verilator (if available), and enable more
internal assertions, debugging messages, and intermediate form dump files.
internal assertions (equivelent to C<--debug-check>), debugging messages
(equivelent to C<--debugi 4>), and intermediate form dump files (equivilent
to C<--dump-tree>).
=item --debug-check
@@ -590,9 +593,9 @@ changing debug verbosity. Enabled automatically when --debug specified.
=item --debugi-<srcfile> <level>
Rarely needed - for developer use. Set internal debugging level globally
to the specified debug level (1-10) or set the specified source file to the
specified level. Higher levels produce more detailed messages (plain
C<--debug> is equivalent to C<--debugi 4>).
to the specified debug level (1-10) or set the specified Verilator source
file to the specified level (e.g. C<--debugi-V3Width 9>). Higher levels
produce more detailed messages.
=item --default-language I<value>
@@ -613,10 +616,13 @@ used.
If no language is specified, either by this flag or +I<lang>ext+ options,
then the latest SystemVerilog language (IEEE 1800-2012) is used.
=item +define+I<var>+I<value>
=item +define+I<var>=I<value>
Defines the given preprocessor symbol. Same as -D; +define is fairly
standard across Verilog tools while -D is an alias for GCC compatibility.
=item +define+I<var>=I<value>+I<var2>=I<value2>...
Defines the given preprocessor symbol, or multiple symbols if separated by
plusses. Similar to -D; +define is fairly standard across Verilog tools
while -D is an alias for GCC compatibility.
=item --dump-tree
@@ -2249,6 +2255,14 @@ reduce the size of the final executable when a task is used a very large
number of times. For this flag to work, the task and tasks below it must
be pure; they cannot reference any variables outside the task itself.
=item /*verilator public*/ (typedef enum)
Used after an enum typedef declaration to indicate the emitted C code
should have the enum values visible. Due to C++ language restrictions, this
may only be used on 64-bit or narrower integral enumerations.
typedef enum logic [2:0] { ZERO = 3'b0 } pub_t /*verilator public*/;
=item /*verilator public*/ (variable)
Used after an input, output, register, or wire declaration to indicate the
@@ -2336,12 +2350,14 @@ behavior. See the test_regress/t/t_dpi_display.v file for an example.
=item /*verilator tracing_off*/
Disable waveform tracing for all future signals that are declared in this
module. Often this is placed just after a primitive's module statement, so
that the entire module is not traced.
module, or cells below this module. Often this is placed just after a
primitive's module statement, so that the entire module and cells below it
are not traced.
=item /*verilator tracing_on*/
Re-enable waveform tracing for all future signals that are declared.
Re-enable waveform tracing for all future signals or cells that are
declared.
=back
+1 -1
View File
@@ -6,7 +6,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[3.864 2014-09-21])
AC_INIT([Verilator],[3.866 2014-11-15])
AC_CONFIG_HEADER(src/config_build.h)
AC_CONFIG_FILES(Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h)
+19 -2
View File
@@ -261,6 +261,20 @@ void VerilatedVcd::printTime (vluint64_t timeui) {
printQuad(timeui);
}
void VerilatedVcd::bufferResize(vluint64_t minsize) {
// minsize is size of largest write. We buffer at least 8 times as much data,
// writing when we are 3/4 full (with thus 2*minsize remaining free)
if (VL_UNLIKELY(minsize > m_wrChunkSize)) {
char* oldbufp = m_wrBufp;
m_wrChunkSize = minsize*2;
m_wrBufp = new char [m_wrChunkSize * 8];
memcpy(m_wrBufp, oldbufp, m_writep - oldbufp);
m_writep = m_wrBufp + (m_writep - oldbufp);
m_wrFlushp = m_wrBufp + m_wrChunkSize * 6;
delete oldbufp; oldbufp=NULL;
}
}
void VerilatedVcd::bufferFlush () {
// We add output data to m_writep.
// When it gets nearly full we dump it using this routine which calls write()
@@ -444,6 +458,9 @@ void VerilatedVcd::declare (vluint32_t code, const char* name, const char* wirep
m_sigs.reserve(m_nextCode*2); // Power-of-2 allocation speeds things up
}
// Make sure write buffer is large enough (one character per bit), plus header
bufferResize(bits+1024);
// Save declaration info
VerilatedVcdSig sig = VerilatedVcdSig(code, bits);
m_sigs.push_back(sig);
@@ -522,7 +539,7 @@ void VerilatedVcd::declDouble (vluint32_t code, const char* name, int arraynum
void VerilatedVcd::fullDouble (vluint32_t code, const double newval) {
(*((double*)&m_sigs_oldvalp[code])) = newval;
// Buffer can't overflow; we have at least bufferInsertSize() bytes (>>>16 bytes)
// Buffer can't overflow before sprintf; we sized during declaration
sprintf(m_writep, "r%.16g", newval);
m_writep += strlen(m_writep);
*m_writep++=' '; printCode(code); *m_writep++='\n';
@@ -530,7 +547,7 @@ void VerilatedVcd::fullDouble (vluint32_t code, const double newval) {
}
void VerilatedVcd::fullFloat (vluint32_t code, const float newval) {
(*((float*)&m_sigs_oldvalp[code])) = newval;
// Buffer can't overflow; we have at least bufferInsertSize() bytes (>>>16 bytes)
// Buffer can't overflow before sprintf; we sized during declaration
sprintf(m_writep, "r%.16g", (double)newval);
m_writep += strlen(m_writep);
*m_writep++=' '; printCode(code); *m_writep++='\n';
+10 -7
View File
@@ -77,7 +77,9 @@ private:
vluint64_t m_timeLastDump; ///< Last time we did a dump
char* m_wrBufp; ///< Output buffer
char* m_wrFlushp; ///< Output buffer flush trigger location
char* m_writep; ///< Write pointer into output buffer
vluint64_t m_wrChunkSize; ///< Output buffer size
vluint64_t m_wroteBytes; ///< Number of bytes written to this file
vluint32_t* m_sigs_oldvalp; ///< Pointer to old signal values
@@ -87,13 +89,12 @@ private:
NameMap* m_namemapp; ///< List of names for the header
static vector<VerilatedVcd*> s_vcdVecp; ///< List of all created traces
inline static size_t bufferSize() { return 256*1024; } // See below for slack calculation
inline static size_t bufferInsertSize() { return 16*1024; }
void bufferResize(vluint64_t minsize);
void bufferFlush();
void bufferCheck() {
inline void bufferCheck() {
// Flush the write buffer if there's not enough space left for new information
// We only call this once per vector, so we need enough slop for a very wide "b###" line
if (VL_UNLIKELY(m_writep > (m_wrBufp+(bufferSize()-bufferInsertSize())))) {
if (VL_UNLIKELY(m_writep > m_wrFlushp)) {
bufferFlush();
}
}
@@ -135,17 +136,19 @@ protected:
public:
// CREATORS
VerilatedVcd () : m_isOpen(false), m_rolloverMB(0), m_modDepth(0), m_nextCode(1) {
m_wrBufp = new char [bufferSize()];
m_writep = m_wrBufp;
m_namemapp = NULL;
m_timeRes = m_timeUnit = 1e-9;
m_timeLastDump = 0;
m_sigs_oldvalp = NULL;
m_evcd = false;
m_scopeEscape = '.'; // Backward compatibility
m_wroteBytes = 0;
m_fd = 0;
m_fullDump = true;
m_wrChunkSize = 8*1024;
m_wrBufp = new char [m_wrChunkSize*8];
m_wrFlushp = m_wrBufp + m_wrChunkSize * 6;
m_writep = m_wrBufp;
m_wroteBytes = 0;
}
~VerilatedVcd();
+8 -11
View File
@@ -884,24 +884,21 @@ void AstNode::cloneRelinkTree() {
//======================================================================
// Comparison
bool AstNode::sameTree(AstNode* node2p) {
return sameTreeIter(node2p, true);
}
bool AstNode::sameTreeIter(AstNode* node2p, bool ignNext) {
bool AstNode::sameTreeIter(AstNode* node2p, bool ignNext, bool gateOnly) {
// Return true if the two trees are identical
if (this==NULL && node2p==NULL) return true;
if (this==NULL || node2p==NULL) return false;
if (this->type() != node2p->type()
|| this->dtypep() != node2p->dtypep()
|| !this->same(node2p)) {
|| !this->same(node2p)
|| (gateOnly && !this->isGateOptimizable())) {
return false;
}
return (this->op1p()->sameTreeIter(node2p->op1p(),false)
&& this->op2p()->sameTreeIter(node2p->op2p(),false)
&& this->op3p()->sameTreeIter(node2p->op3p(),false)
&& this->op4p()->sameTreeIter(node2p->op4p(),false)
&& (ignNext || this->nextp()->sameTreeIter(node2p->nextp(),false))
return (this->op1p()->sameTreeIter(node2p->op1p(),false,gateOnly)
&& this->op2p()->sameTreeIter(node2p->op2p(),false,gateOnly)
&& this->op3p()->sameTreeIter(node2p->op3p(),false,gateOnly)
&& this->op4p()->sameTreeIter(node2p->op4p(),false,gateOnly)
&& (ignNext || this->nextp()->sameTreeIter(node2p->nextp(),false,gateOnly))
);
}
+11 -2
View File
@@ -236,6 +236,8 @@ public:
DIM_SIZE, // V3Width processes
DIM_UNPK_DIMENSIONS, // V3Width converts to constant
//
DT_PUBLIC, // V3LinkParse moves to AstTypedef::attrPublic
//
MEMBER_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
//
VAR_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
@@ -255,6 +257,7 @@ public:
"%E-AT",
"DIM_BITS", "DIM_DIMENSIONS", "DIM_HIGH", "DIM_INCREMENT", "DIM_LEFT",
"DIM_LOW", "DIM_RIGHT", "DIM_SIZE", "DIM_UNPK_DIMENSIONS",
"DT_PUBLIC",
"MEMBER_BASE",
"VAR_BASE", "VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC",
"VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD","VAR_PUBLIC_FLAT_RW",
@@ -932,7 +935,7 @@ class AstNode {
AstNode* cloneTreeIterList();
void checkTreeIter(AstNode* backp);
void checkTreeIterList(AstNode* backp);
bool sameTreeIter(AstNode* node2p, bool ignNext);
bool sameTreeIter(AstNode* node2p, bool ignNext, bool gateOnly);
void deleteTreeIter();
void deleteNode();
static void relinkOneLink(AstNode*& pointpr, AstNode* newp);
@@ -1158,6 +1161,7 @@ public:
// METHODS - Iterate on a tree
AstNode* cloneTree(bool cloneNextLink);
bool sameTree(AstNode* node2p); // Does tree of this == node2p?
bool sameGateTree(AstNode* node2p); // Does tree of this == node2p?, not allowing non-isGateOptimizable
void deleteTree(); // Always deletes the next link
void checkTree(); // User Interface version
void checkIter() const;
@@ -1564,8 +1568,9 @@ public:
virtual void dumpSmall(ostream& str);
virtual bool hasDType() const { return true; }
virtual AstBasicDType* basicp() const = 0; // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const = 0; // recurses over typedefs to next non-typeref type
virtual AstNodeDType* skipRefp() const = 0; // recurses over typedefs/const/enum to next non-typeref type
virtual AstNodeDType* skipRefToConstp() const = 0; // recurses over typedefs to next non-typeref-or-const type
virtual AstNodeDType* skipRefToEnump() const = 0; // recurses over typedefs/const to next non-typeref-or-enum/struct type
virtual int widthAlignBytes() const = 0; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
virtual int widthTotalBytes() const = 0; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
virtual bool maybePointedTo() const { return true; }
@@ -1616,6 +1621,7 @@ public:
virtual AstBasicDType* basicp() const { return findLogicDType(width(),width(),numeric())->castBasicDType(); }
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)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,...
// op1 = members
@@ -1672,6 +1678,7 @@ public:
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); }
virtual int widthTotalBytes() const { return elementsConst() * subDTypep()->widthTotalBytes(); }
int msb() const;
@@ -1886,6 +1893,8 @@ inline bool AstNode::isNeqZero() { return (this->castConst() && this->castConst
inline bool AstNode::isOne() { return (this->castConst() && this->castConst()->num().isEqOne()); }
inline bool AstNode::isAllOnes() { return (this->castConst() && this->castConst()->isEqAllOnes()); }
inline bool AstNode::isAllOnesV() { return (this->castConst() && this->castConst()->isEqAllOnesV()); }
inline bool AstNode::sameTree(AstNode* node2p) { return sameTreeIter(node2p, true, false); }
inline bool AstNode::sameGateTree(AstNode* node2p) { return sameTreeIter(node2p, true, true); }
inline void AstNodeVarRef::init() { if (m_varp) dtypep(m_varp->dtypep()); }
+4
View File
@@ -819,6 +819,10 @@ void AstPin::dump(ostream& str) {
else { str<<" ->UNLINKED"; }
if (svImplicit()) str<<" [.SV]";
}
void AstTypedef::dump(ostream& str) {
this->AstNode::dump(str);
if (attrPublic()) str<<" [PUBLIC]";
}
void AstRange::dump(ostream& str) {
this->AstNode::dump(str);
if (littleEndian()) str<<" [LITTLE]";
+28 -3
View File
@@ -183,22 +183,30 @@ public:
class AstTypedef : public AstNode {
private:
string m_name;
bool m_attrPublic;
public:
AstTypedef(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp)
AstTypedef(FileLine* fl, const string& name, AstNode* attrsp, VFlagChildDType, AstNodeDType* dtp)
: AstNode(fl), m_name(name) {
childDTypep(dtp); // Only for parser
addAttrsp(attrsp);
dtypep(NULL); // V3Width will resolve
m_attrPublic = false;
}
ASTNODE_NODE_FUNCS(Typedef, TYPEDEF)
virtual void dump(ostream& str);
AstNodeDType* getChildDTypep() const { return childDTypep(); }
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Type assigning to
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
void addAttrsp(AstNode* nodep) { addNOp4p(nodep); }
AstNode* attrsp() const { return op4p()->castNode(); } // op4 = Attributes during early parse
// METHODS
virtual string name() const { return m_name; }
virtual bool maybePointedTo() const { return true; }
virtual bool hasDType() const { return true; }
void name(const string& flag) { m_name = flag; }
bool attrPublic() const { return m_attrPublic; }
void attrPublic(bool flag) { m_attrPublic = flag; }
};
class AstTypedefFwd : public AstNode {
@@ -242,6 +250,7 @@ public:
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const { return dtypep()->widthAlignBytes(); }
virtual int widthTotalBytes() const { return dtypep()->widthTotalBytes(); }
virtual string name() const { return m_name; }
@@ -384,6 +393,7 @@ public:
virtual AstBasicDType* basicp() const { return (AstBasicDType*)this; } // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)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,...
AstBasicDTypeKwd keyword() const { return m.m_keyword; } // Avoid using - use isSomething accessors instead
@@ -445,6 +455,7 @@ public:
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); }
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
};
@@ -474,6 +485,7 @@ public:
virtual AstBasicDType* basicp() const { return NULL; }
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const { return 1; }
virtual int widthTotalBytes() const { return 1; }
string cellName() const { return m_cellName; }
@@ -528,6 +540,10 @@ public:
if (defp()) return defp()->skipRefToConstp();
else { v3fatalSrc("Typedef not linked"); return NULL; }
}
virtual AstNodeDType* skipRefToEnump() const {
if (defp()) return defp()->skipRefToEnump();
else { v3fatalSrc("Typedef not linked"); return NULL; }
}
virtual int widthAlignBytes() const { return dtypeSkipRefp()->widthAlignBytes(); }
virtual int widthTotalBytes() const { return dtypeSkipRefp()->widthTotalBytes(); }
void name(const string& flag) { m_name = flag; }
@@ -599,6 +615,7 @@ public:
AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType)
virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); }
virtual AstNodeDType* skipRefToConstp() const { return subDTypep()->skipRefToConstp(); }
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); } // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); } // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
// METHODS
@@ -688,6 +705,7 @@ public:
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const { return subDTypep()->skipRefp(); }
virtual AstNodeDType* skipRefToConstp() const { return subDTypep()->skipRefToConstp(); }
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); }
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
};
@@ -1201,11 +1219,13 @@ private:
AstScope* m_scopep; // Scope variable is underneath
AstVar* m_varp; // [AfterLink] Pointer to variable itself
bool m_circular:1; // Used in circular ordering dependency, need change detect
bool m_trace:1; // Tracing is turned on for this scope
public:
AstVarScope(FileLine* fl, AstScope* scopep, AstVar* varp)
:AstNode(fl)
, m_scopep(scopep), m_varp(varp) {
m_circular = false;
m_trace = true;
dtypeFrom(varp);
}
ASTNODE_NODE_FUNCS(VarScope, VARSCOPE)
@@ -1226,6 +1246,8 @@ public:
void valuep(AstNode* valuep) { addOp1p(valuep); }
bool isCircular() const { return m_circular; }
void circular(bool flag) { m_circular = flag; }
bool isTrace() const { return m_trace; }
void trace(bool flag) { m_trace = flag; }
};
class AstVarRef : public AstNodeVarRef {
@@ -1483,13 +1505,14 @@ private:
string m_origName; // Original name before dot addition
string m_modName; // Module the cell instances
AstNodeModule* m_modp; // [AfterLink] Pointer to module instanced
bool m_hasIfaceVar; // True if a Var has been created for this cell
bool m_hasIfaceVar:1; // True if a Var has been created for this cell
bool m_trace:1; // Trace this cell
public:
AstCell(FileLine* fl, const string& instName, const string& modName,
AstPin* pinsp, AstPin* paramsp, AstRange* rangep)
: AstNode(fl)
, m_name(instName), m_origName(instName), m_modName(modName)
, m_modp(NULL), m_hasIfaceVar(false) {
, m_modp(NULL), m_hasIfaceVar(false), m_trace(true) {
addNOp1p(pinsp); addNOp2p(paramsp); setNOp3p(rangep); }
ASTNODE_NODE_FUNCS(Cell, CELL)
// No cloneRelink, we presume cloneee's want the same module linkages
@@ -1512,6 +1535,8 @@ public:
void modp(AstNodeModule* nodep) { m_modp = nodep; }
bool hasIfaceVar() const { return m_hasIfaceVar; }
void hasIfaceVar(bool flag) { m_hasIfaceVar = flag; }
void trace(bool flag) { m_trace=flag; }
bool isTrace() const { return m_trace; }
};
class AstCellInline : public AstNode {
+4
View File
@@ -238,6 +238,10 @@ private:
nodep->iterateChildren(*this);
insureCleanAndNext (nodep->valuep());
}
virtual void visit(AstTypedef* nodep, AstNUser*) {
// No cleaning, or would loose pointer to enum
nodep->iterateChildren(*this);
}
// Control flow operators
virtual void visit(AstNodeCond* nodep, AstNUser*) {
+142 -6
View File
@@ -173,6 +173,16 @@ private:
if (rnodep->width() != bnodep->width()) return false;
return rnodep->lhsp()->castConst();
}
static bool operandSubAdd(AstNode* nodep) {
// SUB( ADD(CONSTx,y), CONSTz) -> ADD(SUB(CONSTx,CONSTz), y)
AstNodeBiop* np = nodep->castNodeBiop();
AstNodeBiop* lp = np->lhsp()->castNodeBiop();
return (lp
&& lp->lhsp()->castConst()
&& np->rhsp()->castConst()
&& lp->width()==np->width());
}
static bool operandAndOrSame(AstNode* nodep) {
// OR( AND(VAL,x), AND(VAL,y)) -> AND(VAL,OR(x,y))
// OR( AND(x,VAL), AND(y,VAL)) -> AND(OR(x,y),VAL)
@@ -418,12 +428,12 @@ private:
static bool operandsSame(AstNode* node1p, AstNode* node2p) {
// For now we just detect constants & simple vars, though it could be more generic
if (node1p->castConst() && node2p->castConst()) {
return node1p->sameTree(node2p);
return node1p->sameGateTree(node2p);
}
else if (node1p->castVarRef() && node2p->castVarRef()) {
// Avoid comparing widthMin's, which results in lost optimization attempts
// If cleanup sameTree to be smarter, this can be restored.
//return node1p->sameTree(node2p);
// If cleanup sameGateTree to be smarter, this can be restored.
//return node1p->sameGateTree(node2p);
return node1p->same(node2p);
} else {
return false;
@@ -439,7 +449,7 @@ private:
AstVarRef* elsevarp = elsep->lhsp()->castVarRef();
if (!ifvarp || !elsevarp) return false;
if (ifvarp->isWide()) return false; // Would need temporaries, so not worth it
if (!ifvarp->sameTree(elsevarp)) return false;
if (!ifvarp->sameGateTree(elsevarp)) return false;
return true;
}
bool operandIfIf(AstNodeIf* nodep) {
@@ -450,6 +460,89 @@ private:
if (afterComment(lowerIfp->elsesp())) return false;
return true;
}
bool ifConcatMergeableBiop(AstNode* nodep) {
return (nodep->castAnd()
|| nodep->castOr()
|| nodep->castXor()
|| nodep->castXnor());
}
bool ifAdjacentSel(AstSel* lhsp, AstSel* rhsp) {
if (!v3Global.opt.oAssemble()) return false; // opt disabled
if (!lhsp || !rhsp) return false;
AstNode* lfromp = lhsp->fromp();
AstNode* rfromp = rhsp->fromp();
if (!lfromp || !rfromp || !lfromp->sameGateTree(rfromp)) return false;
AstConst* lstart = lhsp->lsbp()->castConst();
AstConst* rstart = rhsp->lsbp()->castConst();
AstConst* lwidth = lhsp->widthp()->castConst();
AstConst* rwidth = rhsp->widthp()->castConst();
if (!lstart || !rstart || !lwidth || !rwidth) return false; // too complicated
int rend = (rstart->toSInt() + rwidth->toSInt());
if (rend == lstart->toSInt()) return true;
return false;
}
bool ifMergeAdjacent(AstNode* lhsp, AstNode* rhsp) {
// called by concatmergeable to determine if {lhsp, rhsp} make sense
if (!v3Global.opt.oAssemble()) return false; // opt disabled
// two same varref
if (operandsSame(lhsp, rhsp)) return true;
AstSel* lselp = lhsp->castSel();
AstSel* rselp = rhsp->castSel();
// a[i:0] a
if (lselp && !rselp && rhsp->sameGateTree(lselp->fromp()))
rselp = new AstSel(rhsp->fileline(), rhsp->cloneTree(false), 0, rhsp->width());
// a[i:j] {a[j-1:k], b}
if (lselp && !rselp && rhsp->castConcat())
return ifMergeAdjacent(lhsp, rhsp->castConcat()->lhsp());
// a a[msb:j]
if (rselp && !lselp && lhsp->sameGateTree(rselp->fromp()))
lselp = new AstSel(lhsp->fileline(), lhsp->cloneTree(false), 0, lhsp->width());
// {b, a[j:k]} a[k-1:i]
if (rselp && !lselp && lhsp->castConcat())
return ifMergeAdjacent(lhsp->castConcat()->rhsp(), rhsp);
if (!lselp || !rselp) return false;
// a[a:b] a[b-1:c] are adjacent
AstNode* lfromp = lselp->fromp();
AstNode* rfromp = rselp->fromp();
if (!lfromp || !rfromp || !lfromp->sameGateTree(rfromp)) return false;
AstConst* lstart = lselp->lsbp()->castConst();
AstConst* rstart = rselp->lsbp()->castConst();
AstConst* lwidth = lselp->widthp()->castConst();
AstConst* rwidth = rselp->widthp()->castConst();
if (!lstart || !rstart || !lwidth || !rwidth) return false; // too complicated
int rend = (rstart->toSInt() + rwidth->toSInt());
// a[i:j] a[j-1:k]
if (rend == lstart->toSInt()) return true;
// a[i:0] a[msb:j]
if (rend == rfromp->width() && lstart->toSInt() == 0) return true;
return false;
}
bool concatMergeable(AstNode* lhsp, AstNode* rhsp) {
// determine if {a OP b, c OP d} => {a, c} OP {b, d} is advantagous
if (!v3Global.opt.oAssemble()) return false; // opt disabled
if (lhsp->type() != rhsp->type()) return false;
if (!ifConcatMergeableBiop(lhsp)) return false;
AstNodeBiop* lp = lhsp->castNodeBiop();
AstNodeBiop* rp = rhsp->castNodeBiop();
if (!lp || !rp) return false;
// {a[]&b[], a[]&b[]}
bool lad = ifMergeAdjacent(lp->lhsp(), rp->lhsp());
bool rad = ifMergeAdjacent(lp->rhsp(), rp->rhsp());
if (lad && rad) return true;
// {a[] & b[]&c[], a[] & b[]&c[]}
else if (lad && concatMergeable(lp->rhsp(), rp->rhsp())) return true;
// {a[]&b[] & c[], a[]&b[] & c[]}
else if (rad && concatMergeable(lp->lhsp(), rp->lhsp())) return true;
else {
// {(a[]&b[])&(c[]&d[]), (a[]&b[])&(c[]&d[])}
if (concatMergeable(lp->lhsp(), rp->lhsp())
&& concatMergeable(lp->rhsp(), rp->rhsp()))
return true;
}
return false;
}
//----------------------------------------
// Constant Replacement functions.
@@ -668,6 +761,45 @@ private:
rrp->deleteTree();
//nodep->dumpTree(cout, " repShiftSame_new: ");
}
void replaceConcatSel(AstConcat* nodep) {
// {a[1], a[0]} -> a[1:0]
AstSel* lselp = nodep->lhsp()->unlinkFrBack()->castSel();
AstSel* rselp = nodep->rhsp()->unlinkFrBack()->castSel();
int lstart = lselp->lsbConst();
int lwidth = lselp->widthConst();
int rstart = rselp->lsbConst();
int rwidth = rselp->widthConst();
if ((rstart + rwidth) != lstart) nodep->v3fatalSrc("tried to merge two selects which are not adjacent");
AstSel* newselp = new AstSel(lselp->fromp()->fileline(), rselp->fromp()->cloneTree(false), rstart, lwidth+rwidth);
UINFO(5, "merged two adjacent sel "<<lselp <<" and "<<rselp<< " to one "<<newselp<<endl);
nodep->replaceWith(newselp);
lselp->deleteTree(); lselp = NULL;
rselp->deleteTree(); rselp = NULL;
nodep->deleteTree(); nodep = NULL;
}
void replaceConcatMerge(AstConcat* nodep) {
AstNodeBiop* lp = nodep->lhsp()->castNodeBiop();
AstNodeBiop* rp = nodep->rhsp()->castNodeBiop();
AstNode* llp = lp->lhsp()->cloneTree(false);
AstNode* lrp = lp->rhsp()->cloneTree(false);
AstNode* rlp = rp->lhsp()->cloneTree(false);
AstNode* rrp = rp->rhsp()->cloneTree(false);
if (concatMergeable(lp, rp)) {
AstConcat* newlp = new AstConcat(rlp->fileline(), llp, rlp);
AstConcat* newrp = new AstConcat(rrp->fileline(), lrp, rrp);
// use the lhs to replace the parent concat
lp->lhsp()->replaceWith(newlp);
lp->rhsp()->replaceWith(newrp);
lp->dtypeChgWidthSigned(newlp->width(), newlp->width(), AstNumeric::fromBool(true));
UINFO(5, "merged "<< nodep <<endl);
rp->unlinkFrBack()->deleteTree(); rp = NULL;
nodep->replaceWith(lp->unlinkFrBack()); nodep->deleteTree(); nodep = NULL;
lp->lhsp()->accept(*this);
lp->rhsp()->accept(*this);
} else nodep->v3fatalSrc("tried to merge two Concat which are not adjacent");
}
void replaceExtend (AstNode* nodep, AstNode* arg0p) {
// -> EXTEND(nodep)
// like a AstExtend{$rhsp}, but we need to set the width correctly from base node
@@ -792,7 +924,7 @@ private:
AstSel* sel2p = nextp->lhsp()->castSel(); if (!sel2p) return false;
AstVarRef* varref1p = sel1p->fromp()->castVarRef(); if (!varref1p) return false;
AstVarRef* varref2p = sel2p->fromp()->castVarRef(); if (!varref2p) return false;
if (!varref1p->sameTree(varref2p)) return false;
if (!varref1p->sameGateTree(varref2p)) return false;
AstConst* con1p = sel1p->lsbp()->castConst(); if (!con1p) return false;
AstConst* con2p = sel2p->lsbp()->castConst(); if (!con2p) return false;
// We need to make sure there's no self-references involved in either
@@ -1539,7 +1671,7 @@ private:
AstSenItem* litemp = senp->castSenItem();
AstSenItem* ritemp = cmpp->castSenItem();
if (litemp && ritemp) {
if ((litemp->varrefp() && ritemp->varrefp() && litemp->varrefp()->sameTree(ritemp->varrefp()))
if ((litemp->varrefp() && ritemp->varrefp() && litemp->varrefp()->sameGateTree(ritemp->varrefp()))
|| (!litemp->varrefp() && !ritemp->varrefp())) {
// We've sorted in the order ANY, BOTH, POS, NEG, so we don't need to try opposite orders
if (( litemp->edgeType()==AstEdgeType::ET_ANYEDGE) // ANY or {BOTH|POS|NEG} -> ANY
@@ -1910,6 +2042,7 @@ private:
TREEOP ("AstMul {operandIsPowTwo($lhsp), $rhsp}", "replaceMulShift(nodep)"); // a*2^n -> a<<n
TREEOP ("AstDiv {$lhsp, operandIsPowTwo($rhsp)}", "replaceDivShift(nodep)"); // a/2^n -> a>>n
TREEOP ("AstPow {operandIsTwo($lhsp), $rhsp}", "replacePowShift(nodep)"); // 2**a == 1<<a
TREEOP ("AstSub {$lhsp.castAdd, operandSubAdd(nodep)}", "AstAdd{AstSub{$lhsp->castAdd()->lhsp(),$rhsp}, $lhsp->castAdd()->rhsp()}"); // ((a+x)-y) -> (a+(x-y))
// Trinary ops
// Note V3Case::Sel requires Cond to always be conditionally executed in C to prevent core dump!
TREEOP ("AstNodeCond{$condp.isZero, $expr1p, $expr2p}", "replaceWChild(nodep,$expr2p)");
@@ -2064,6 +2197,9 @@ private:
// CONCAT({const},CONCAT({const},{c})) -> CONCAT((constifiedCONC{const|const},{c}))
TREEOPV("AstConcat{operandConcatMove(nodep)}", "moveConcat(nodep)");
TREEOPV("AstConcat{$lhsp.isZero, $rhsp}", "replaceExtend(nodep, nodep->rhsp())");
// CONCAT(a[1],a[0]) -> a[1:0]
TREEOPV("AstConcat{$lhsp->castSel(), $rhsp->castSel(), ifAdjacentSel($lhsp->castSel(),,$rhsp->castSel())}", "replaceConcatSel(nodep)");
TREEOPV("AstConcat{ifConcatMergeableBiop($lhsp), concatMergeable($lhsp,,$rhsp)}", "replaceConcatMerge(nodep)");
// Common two-level operations that can be simplified
TREEOP ("AstAnd {$lhsp.castOr, $rhsp.castOr, operandAndOrSame(nodep)}", "replaceAndOr(nodep)");
TREEOP ("AstOr {$lhsp.castAnd,$rhsp.castAnd,operandAndOrSame(nodep)}", "replaceAndOr(nodep)");
+16
View File
@@ -81,6 +81,7 @@ private:
typedef multimap<AstVarScope*,AstNodeAssign*> AssignMap;
// STATE
AstNodeModule* m_modp; // Current module
vector<AstNode*> m_varEtcsp; // List of all encountered to avoid another loop through tree
vector<AstVarScope*> m_vscsp; // List of all encountered to avoid another loop through tree
AssignMap m_assignMap; // List of all simple assignments for each variable
@@ -112,6 +113,12 @@ private:
}
// VISITORS
virtual void visit(AstNodeModule* nodep, AstNUser*) {
m_modp = nodep;
nodep->iterateChildren(*this);
checkAll(nodep);
m_modp = NULL;
}
virtual void visit(AstCell* nodep, AstNUser*) {
nodep->iterateChildren(*this);
checkAll(nodep);
@@ -158,6 +165,13 @@ private:
nodep->packagep()->user1Inc();
}
}
virtual void visit(AstTypedef* nodep, AstNUser*) {
nodep->iterateChildren(*this);
checkAll(nodep);
// Don't let packages with only public variables disappear
// Normal modules may disappear, e.g. if they are parameterized then removed
if (nodep->attrPublic() && m_modp && m_modp->castPackage()) m_modp->user1Inc();
}
virtual void visit(AstVarScope* nodep, AstNUser*) {
nodep->iterateChildren(*this);
checkAll(nodep);
@@ -168,6 +182,7 @@ private:
virtual void visit(AstVar* nodep, AstNUser*) {
nodep->iterateChildren(*this);
checkAll(nodep);
if (nodep->isSigPublic() && m_modp && m_modp->castPackage()) m_modp->user1Inc();
if (mightElim(nodep)) {
m_varEtcsp.push_back(nodep);
}
@@ -253,6 +268,7 @@ private:
public:
// CONSTRUCTORS
DeadVisitor(AstNetlist* nodep, bool elimUserVars, bool elimDTypes) {
m_modp = NULL;
m_elimUserVars = elimUserVars;
m_elimDTypes = elimDTypes;
m_sideEffect = false;
+35 -1
View File
@@ -96,6 +96,38 @@ public:
}
}
void emitTypedefs(AstNode* firstp) {
bool first = true;
for (AstNode* loopp=firstp; loopp; loopp = loopp->nextp()) {
if (AstTypedef* nodep = loopp->castTypedef()) {
if (nodep->attrPublic()) {
if (first) {
first = false;
puts("\n// TYPEDEFS\n");
puts("// That were declared public\n");
} else {
puts("\n");
}
if (AstEnumDType* adtypep = nodep->dtypep()->skipRefToEnump()->castEnumDType()) {
if (adtypep->width()>64) {
puts("// enum "+nodep->name()+" // Ignored: Too wide for C++\n");
} else {
puts("enum "+nodep->name()+" {\n");
for (AstEnumItem* itemp = adtypep->itemsp(); itemp; itemp=itemp->nextp()->castEnumItem()) {
puts(itemp->name());
puts(" = ");
itemp->valuep()->iterateAndNext(*this);
if (nodep->nextp()) puts(",");
puts("\n");
}
puts("};\n");
}
}
}
}
}
}
// VISITORS
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
bool paren = true; bool decind = false;
@@ -663,6 +695,7 @@ public:
nodep->iterateChildren(*this);
}
// NOPs
virtual void visit(AstTypedef*, AstNUser*) {}
virtual void visit(AstPragma*, AstNUser*) {}
virtual void visit(AstCell*, AstNUser*) {} // Handled outside the Visit class
virtual void visit(AstVar*, AstNUser*) {} // Handled outside the Visit class
@@ -670,7 +703,6 @@ public:
virtual void visit(AstTraceDecl*, AstNUser*) {} // Handled outside the Visit class
virtual void visit(AstTraceInc*, AstNUser*) {} // Handled outside the Visit class
virtual void visit(AstCFile*, AstNUser*) {} // Handled outside the Visit class
virtual void visit(AstTypedef*, AstNUser*) {} // Nothing needed presently
// Default
virtual void visit(AstNode* nodep, AstNUser*) {
puts((string)"\n???? // "+nodep->prettyTypeName()+"\n");
@@ -1845,6 +1877,8 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
}
}
emitTypedefs(modp->stmtsp());
puts("\n// PORTS\n");
if (modp->isTop()) puts("// The application code writes and reads these signals to\n");
if (modp->isTop()) puts("// propagate new values into/out from the Verilated model.\n");
+130 -1
View File
@@ -303,6 +303,7 @@ private:
V3Double0 m_statSigs; // Statistic tracking
V3Double0 m_statRefs; // Statistic tracking
V3Double0 m_statDedupLogic; // Statistic tracking
V3Double0 m_statAssignMerged; // Statistic tracking
// METHODS
void iterateNewStmt(AstNode* nodep, const char* nonReducibleReason, const char* consumeReason) {
@@ -352,6 +353,7 @@ private:
void consumedMove();
void replaceAssigns();
void dedupe();
void mergeAssigns();
// VISITORS
virtual void visit(AstNetlist* nodep, AstNUser*) {
@@ -368,6 +370,7 @@ private:
optimizeSignals(true);
// Remove redundant logic
if (v3Global.opt.oDedupe()) dedupe();
if (v3Global.opt.oAssemble()) mergeAssigns();
// Warn
warnSignals();
consumedMark();
@@ -506,6 +509,7 @@ public:
V3Stats::addStat("Optimizations, Gate sigs deleted", m_statSigs);
V3Stats::addStat("Optimizations, Gate inputs replaced", m_statRefs);
V3Stats::addStat("Optimizations, Gate sigs deduped", m_statDedupLogic);
V3Stats::addStat("Optimizations, Gate assign merged", m_statAssignMerged);
}
};
@@ -1009,7 +1013,6 @@ private:
lvertexp->user(true);
}
}
return NULL;
}
@@ -1063,6 +1066,132 @@ void GateVisitor::dedupe() {
m_statDedupLogic += deduper.numDeduped();
}
//######################################################################
// Recurse through the graph, try to merge assigns
class GateMergeAssignsGraphVisitor : public GateGraphBaseVisitor {
private:
// NODE STATE
AstNodeAssign* m_assignp;
AstActive* m_activep;
GateLogicVertex* m_logicvp;
V3Graph* m_graphp;
V3Double0 m_numMergedAssigns; // Statistic tracking
// assemble two Sel into one if possible
AstSel* merge(AstSel* pre, AstSel* cur) {
AstVarRef* preVarRefp = pre->fromp()->castVarRef();
AstVarRef* curVarRefp = cur->fromp()->castVarRef();
if (!preVarRefp || !curVarRefp || !curVarRefp->same(preVarRefp)) return NULL; // not the same var
AstConst* pstart = pre->lsbp()->castConst();
AstConst* pwidth = pre->widthp()->castConst();
AstConst* cstart = cur->lsbp()->castConst();
AstConst* cwidth = cur->widthp()->castConst();
if (!pstart || !pwidth || !cstart || !cwidth) return NULL; // too complicated
if (cur->lsbConst()+cur->widthConst() == pre->lsbConst())
return new AstSel(curVarRefp->fileline(), curVarRefp->cloneTree(false), cur->lsbConst(), pre->widthConst()+cur->widthConst());
else return NULL;
}
virtual AstNUser* visit(GateVarVertex *vvertexp, AstNUser*) {
for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep; ) {
V3GraphEdge* oldedgep = edgep;
edgep = edgep->inNextp(); // for recursive since the edge could be deleted
if (GateLogicVertex* lvertexp = dynamic_cast<GateLogicVertex*>(oldedgep->fromp())) {
if (AstNodeAssign* assignp = lvertexp->nodep()->castNodeAssign()) {
//if (lvertexp->outSize1() && assignp->lhsp()->castSel()) {
if (assignp->lhsp()->castSel() && lvertexp->outSize1()) {
UINFO(9, "assing to the nodep["<<assignp->lhsp()->castSel()->lsbConst()<<"]"<<endl);
// first assign with Sel-lhs
if (!m_activep) m_activep = lvertexp->activep();
if (!m_logicvp) m_logicvp = lvertexp;
if (!m_assignp) m_assignp = assignp;
// not under the same active
if (m_activep != lvertexp->activep()) {
m_activep = lvertexp->activep();
m_logicvp = lvertexp;
m_assignp = assignp;
continue;
}
AstSel* preselp = m_assignp->lhsp()->castSel();
AstSel* curselp = assignp->lhsp()->castSel();
if (!preselp || !curselp) continue;
if (AstSel* newselp = merge(preselp, curselp)) {
UINFO(5, "assemble to new sel: "<<newselp<<endl);
// replace preSel with newSel
preselp->replaceWith(newselp); preselp->deleteTree(); preselp = NULL;
// create new rhs for pre assignment
AstNode* newrhsp = new AstConcat(m_assignp->rhsp()->fileline(), m_assignp->rhsp()->cloneTree(false), assignp->rhsp()->cloneTree(false));
AstNode* oldrhsp = m_assignp->rhsp();
oldrhsp->replaceWith(newrhsp); oldrhsp->deleteTree(); oldrhsp = NULL;
m_assignp->dtypeChgWidthSigned(m_assignp->width()+assignp->width(), m_assignp->width()+assignp->width(), AstNumeric::fromBool(true));
// don't need to delete, will be handled
//assignp->unlinkFrBack(); assignp->deleteTree(); assignp = NULL;
// update the graph
{
// delete all inedges to lvertexp
if (!lvertexp->inEmpty()) {
for (V3GraphEdge* ledgep = lvertexp->inBeginp(); ledgep; ) {
V3GraphEdge* oedgep = ledgep;
ledgep = ledgep->inNextp();
GateEitherVertex* fromvp = dynamic_cast<GateEitherVertex*>(oedgep->fromp());
new V3GraphEdge(m_graphp, fromvp, m_logicvp, 1);
oedgep->unlinkDelete(); oedgep = NULL;
}
}
// delete all outedges to lvertexp, only one
oldedgep->unlinkDelete(); oldedgep = NULL;
}
++m_numMergedAssigns;
} else {
m_assignp = assignp;
m_logicvp = lvertexp;
}
}
}
}
}
return NULL;
}
virtual AstNUser* visit(GateLogicVertex* lvertexp, AstNUser* vup) {
return NULL;
}
public:
GateMergeAssignsGraphVisitor(V3Graph* graphp) {
m_assignp = NULL;
m_activep = NULL;
m_logicvp = NULL;
m_numMergedAssigns = 0;
m_graphp = graphp;
}
void mergeAssignsTree(GateVarVertex* vvertexp) {
vvertexp->accept(*this);
}
V3Double0 numMergedAssigns() { return m_numMergedAssigns; }
};
//----------------------------------------------------------------------
void GateVisitor::mergeAssigns() {
GateMergeAssignsGraphVisitor merger(&m_graph);
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
merger.mergeAssignsTree(vvertexp);
}
}
m_statAssignMerged += merger.numMergedAssigns();
}
//######################################################################
// Convert VARSCOPE(ASSIGN(default, VARREF)) to just VARSCOPE(default)
+1
View File
@@ -314,6 +314,7 @@ private:
// Also clear I/O bits, as it is now local.
string name = m_cellp->name() + "__DOT__" + nodep->name();
if (!nodep->isFuncLocal()) nodep->inlineAttrReset(name);
if (!m_cellp->isTrace()) nodep->trace(false);
if (debug()>=9) { nodep->dumpTree(cout,"varchanged:"); }
if (debug()>=9) { nodep->valuep()->dumpTree(cout,"varchangei:"); }
// Iterate won't hit AstIfaceRefDType directly as it is no longer underneath the module
+19 -2
View File
@@ -62,6 +62,7 @@ private:
AstNodeModule* m_valueModp; // If set, move AstVar->valuep() initial values to this module
AstNodeModule* m_modp; // Current module
AstNodeFTask* m_ftaskp; // Current task
AstNodeDType* m_dtypep; // Current data type
// METHODS
static int debug() {
@@ -104,6 +105,15 @@ private:
m_valueModp = upperValueModp;
}
}
virtual void visit(AstNodeDType* nodep, AstNUser*) {
if (!nodep->user1SetOnce()) { // Process only once.
cleanFileline(nodep);
AstNodeDType* upperDtypep = m_dtypep;
m_dtypep = nodep;
nodep->iterateChildren(*this);
m_dtypep = upperDtypep;
}
}
virtual void visit(AstEnumItem* nodep, AstNUser*) {
// Expand ranges
cleanFileline(nodep);
@@ -176,7 +186,13 @@ private:
virtual void visit(AstAttrOf* nodep, AstNUser*) {
cleanFileline(nodep);
nodep->iterateChildren(*this);
if (nodep->attrType() == AstAttrType::VAR_CLOCK) {
if (nodep->attrType() == AstAttrType::DT_PUBLIC) {
AstTypedef* typep = nodep->backp()->castTypedef();
if (!typep) nodep->v3fatalSrc("Attribute not attached to typedef");
typep->attrPublic(true);
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
}
else if (nodep->attrType() == AstAttrType::VAR_CLOCK) {
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
m_varp->attrScClocked(true);
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
@@ -265,7 +281,7 @@ private:
nodep->deleteTree(); nodep=NULL;
return;
} else {
defp = new AstTypedef(nodep->fileline(), nodep->name(), VFlagChildDType(), dtypep);
defp = new AstTypedef(nodep->fileline(), nodep->name(), NULL, VFlagChildDType(), dtypep);
m_implTypedef.insert(make_pair(make_pair(nodep->containerp(), defp->name()), defp));
backp->addNextHere(defp);
}
@@ -327,6 +343,7 @@ public:
m_varp = NULL;
m_modp = NULL;
m_ftaskp = NULL;
m_dtypep = NULL;
m_inAlways = false;
m_inGenerate = false;
m_needStart = false;
+23 -11
View File
@@ -107,17 +107,27 @@ void V3Options::addLangExt(const string& langext, const V3LangCode& lc) {
void V3Options::addLibExtV(const string& libext) {
m_impp->addLibExtV(libext);
}
void V3Options::addDefine(const string& defline) {
void V3Options::addDefine(const string& defline, bool allowPlus) {
// Split +define+foo=value into the appropriate parts and parse
string def = defline;
string value;
string::size_type pos;
if ( ((pos=defline.find("+")) != string::npos)
|| ((pos=defline.find("=")) != string::npos)) {
value = def.substr(pos+1);
def.erase(pos);
// Optional + says to allow multiple defines on the line
// + is not quotable, as other simulators do not allow that
string left = defline;
while (left != "") {
string def = left;
string::size_type pos;
if (allowPlus && ((pos=left.find("+")) != string::npos)) {
left = left.substr(pos+1);
def.erase(pos);
} else {
left = "";
}
string value;
if ((pos=def.find("=")) != string::npos) {
value = def.substr(pos+1);
def.erase(pos);
}
V3PreShell::defineCmdLine(def,value);
}
V3PreShell::defineCmdLine(def,value);
}
void V3Options::addCppFile(const string& filename) {
@@ -668,7 +678,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
if (argv[i][0]=='+') {
char *sw = argv[i];
if ( !strncmp (sw, "+define+", 8)) {
addDefine (string (sw+strlen("+define+")));
addDefine (string (sw+strlen("+define+")), true);
}
else if ( !strncmp (sw, "+incdir+", 8)) {
addIncDirUser (parseFileArg(optdir, string (sw+strlen("+incdir+"))));
@@ -774,6 +784,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
case 'b': m_oCombine = flag; break;
case 'c': m_oConst = flag; break;
case 'd': m_oDedupe = flag; break;
case 'm': m_oAssemble = flag; break;
case 'e': m_oCase = flag; break;
case 'f': m_oFlopGater = flag; break;
case 'g': m_oGate = flag; break;
@@ -802,7 +813,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
m_convergeLimit = atoi(argv[i]);
}
else if ( !strncmp (sw, "-D", 2)) {
addDefine (string (sw+strlen("-D")));
addDefine (string (sw+strlen("-D")), false);
}
else if ( !strcmp (sw, "-debug") ) {
setDebugMode(3);
@@ -1319,6 +1330,7 @@ void V3Options::optimize(int level) {
m_oSubstConst = flag;
m_oTable = flag;
m_oDedupe = flag;
m_oAssemble = flag;
// And set specific optimization levels
if (level >= 3) {
m_inlineMult = -1; // Maximum inlining
+3 -1
View File
@@ -139,6 +139,7 @@ class V3Options {
bool m_oCombine; // main switch: -Ob: common icode packing
bool m_oConst; // main switch: -Oc: constant folding
bool m_oDedupe; // main switch: -Od: logic deduplication
bool m_oAssemble; // main switch: -Om: assign assemble
bool m_oExpand; // main switch: -Ox: expansion of C macros
bool m_oFlopGater; // main switch: -Of: flop gater detection
bool m_oGate; // main switch: -Og: gate wire elimination
@@ -155,7 +156,7 @@ class V3Options {
private:
// METHODS
void addArg(const string& flag);
void addDefine(const string& defline);
void addDefine(const string& defline, bool allowPlus);
void addFuture(const string& flag);
void addIncDirUser(const string& incdir); // User requested
void addIncDirFallback(const string& incdir); // Low priority if not found otherwise
@@ -282,6 +283,7 @@ class V3Options {
bool oCombine() const { return m_oCombine; }
bool oConst() const { return m_oConst; }
bool oDedupe() const { return m_oDedupe; }
bool oAssemble() const { return m_oAssemble; }
bool oExpand() const { return m_oExpand; }
bool oFlopGater() const { return m_oFlopGater; }
bool oGate() const { return m_oGate; }
+2
View File
@@ -169,6 +169,7 @@ class V3PreLex {
int m_pslParenLevel;// PSL Parenthesis (){} counting, so we can find final ;
bool m_pslMoreNeeded;// Next // comment is really psl
bool m_defCmtSlash; // /*...*/ comment in define had \ ending
bool m_defQuote; // Definition value inside quote
string m_defValue; // Definition value being built.
int m_enterExit; // For VL_LINE, the enter/exit level
@@ -181,6 +182,7 @@ class V3PreLex {
m_pedantic = false;
m_formalLevel = 0;
m_parenLevel = 0;
m_defQuote = false;
m_defCmtSlash = false;
m_tokFilelinep = filelinep;
m_enterExit = 0;
+4 -3
View File
@@ -125,7 +125,7 @@ psl [p]sl
<STRMODE>{backslash}{crnl} { linenoInc(); yymore(); }
<STRMODE>{backslash}. { yymore(); }
<STRMODE>{quote} { yy_pop_state();
if (LEXP->m_parenLevel || LEXP->m_formalLevel) { appendDefValue(yytext,yyleng); yyleng=0; }
if (LEXP->m_parenLevel || LEXP->m_defQuote) { LEXP->m_defQuote=false; appendDefValue(yytext,yyleng); yyleng=0; }
else return (VP_STRING); }
/* Stringification */
@@ -162,7 +162,7 @@ psl [p]sl
<DEFFORM><<EOF>> { linenoInc(); yy_pop_state(); yyerrorf("Unterminated ( in define formal arguments."); yyleng=0; return VP_DEFFORM; }
<DEFFORM>{crnl} { linenoInc(); appendDefValue((char*)"\n",1); } /* Include return so can maintain output line count */
<DEFFORM>[\\]{crnl} { linenoInc(); appendDefValue((char*)"\\\n",2); } /* Include return so can maintain output line count */
<DEFFORM>{quote} { yy_push_state(STRMODE); yymore(); } /* Legal only in default values */
<DEFFORM>{quote} { LEXP->m_defQuote=true; yy_push_state(STRMODE); yymore(); } /* Legal only in default values */
<DEFFORM>"`\\`\"" { appendDefValue(yytext,yyleng); } /* Maybe illegal, otherwise in default value */
<DEFFORM>{tickquote} { appendDefValue(yytext,yyleng); } /* Maybe illegal, otherwise in default value */
<DEFFORM>[{\[] { LEXP->m_formalLevel++; appendDefValue(yytext,yyleng); }
@@ -179,7 +179,8 @@ psl [p]sl
<DEFVAL><<EOF>> { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); } /* Technically illegal, but people complained */
<DEFVAL>{crnl} { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); }
<DEFVAL>[\\]{crnl} { linenoInc(); appendDefValue((char*)"\\\n",2); } /* Return, AND \ is part of define value */
<DEFVAL>[^\/\*\n\r\\]+ |
<DEFVAL>{quote} { LEXP->m_defQuote=true; yy_push_state(STRMODE); yymore(); }
<DEFVAL>[^\/\*\n\r\\\"]+ |
<DEFVAL>[\\][^\n\r] |
<DEFVAL>. { appendDefValue(yytext,yyleng); }
+1 -1
View File
@@ -352,7 +352,7 @@ private:
while (searchp && searchp->castComment()) searchp = searchp->nextp();
if (searchp
&& searchp->castDisplay()
&& nodep->filep()->sameTree(searchp->castDisplay()->filep())) {
&& nodep->filep()->sameGateTree(searchp->castDisplay()->filep())) {
// There's another display next; we can just wait to flush
} else {
UINFO(4,"Autoflush "<<nodep<<endl);
+3 -2
View File
@@ -241,6 +241,7 @@ private:
if (!nodep->user1p()) {
AstVarScope* varscp = new AstVarScope(nodep->fileline(), m_scopep, nodep);
UINFO(6," New scope "<<varscp<<endl);
if (m_aboveCellp && !m_aboveCellp->isTrace()) varscp->trace(false);
nodep->user1p(varscp);
if (!m_scopep) nodep->v3fatalSrc("No scope for var");
m_varScopes.insert(make_pair(make_pair(nodep, m_scopep), varscp));
@@ -258,8 +259,8 @@ private:
// the var's referenced package etc might not be created yet.
// So push to a list and post-correct
m_varRefScopes.insert(make_pair(nodep, m_scopep));
}
}
}
}
virtual void visit(AstScopeName* nodep, AstNUser*) {
// If there's a %m in the display text, we add a special node that will contain the name()
string prefix = (string)("__DOT__")+m_scopep->name();
+1 -1
View File
@@ -353,7 +353,7 @@ private:
== var2p->dtypep()->arrayUnpackedElements())) {
AstNode* init1p = var1p->valuep()->castInitArray();
AstNode* init2p = var2p->valuep()->castInitArray();
if (init1p->sameTree(init2p)) {
if (init1p->sameGateTree(init2p)) {
UINFO(8," Duplicate table var "<<vsc2p<<" == "<<vsc1p<<endl);
vsc1p->unlinkFrBack()->deleteTree();
return vsc2p;
+9 -5
View File
@@ -64,13 +64,17 @@ private:
return level;
}
const char* varIgnoreTrace(AstVar* nodep) {
const char* vscIgnoreTrace(AstVarScope* nodep) {
// Return true if this shouldn't be traced
// See also similar rule in V3Coverage::varIgnoreToggle
string prettyName = nodep->prettyName();
if (!nodep->isTrace()) {
AstVar* varp = nodep->varp();
string prettyName = varp->prettyName();
if (!varp->isTrace()) {
return "Verilator trace_off";
}
else if (!nodep->isTrace()) {
return "Verilator cell trace_off";
}
else if (!v3Global.opt.traceUnderscore()) {
if (prettyName.size()>=1 && prettyName[0] == '_')
return "Leading underscore";
@@ -163,8 +167,8 @@ private:
m_traVscp = nodep;
m_traValuep = NULL;
if (varIgnoreTrace(varp)) {
addIgnore(varIgnoreTrace(varp));
if (vscIgnoreTrace(nodep)) {
addIgnore(vscIgnoreTrace(nodep));
} else {
++m_statSigs;
if (nodep->valuep()) m_traValuep = nodep->valuep()->cloneTree(true);
+5 -5
View File
@@ -337,14 +337,14 @@ private:
// Find range of dtype we are selecting from
// Similar code in V3Const::warnSelect
int maxmsb = nodep->fromp()->dtypep()->width()-1;
int maxlsb = maxmsb - nodep->width() + 1;
if (debug()>=9) nodep->dumpTree(cout,"sel_old: ");
V3Number maxlsbnum (nodep->fileline(), nodep->lsbp()->width(), maxlsb);
V3Number maxmsbnum (nodep->fileline(), nodep->lsbp()->width(), maxmsb);
// See if the condition is constant true
// If (maxmsb >= selected), we're in bound
AstNode* condp = new AstGte (nodep->fileline(),
new AstConst(nodep->fileline(), maxlsbnum),
new AstConst(nodep->fileline(), maxmsbnum),
nodep->lsbp()->cloneTree(false));
// See if the condition is constant true (e.g. always in bound due to constant select)
// Note below has null backp(); the Edit function knows how to deal with that.
condp = V3Const::constifyEdit(condp);
if (condp->isOne()) {
@@ -352,7 +352,7 @@ private:
condp->deleteTree();
}
else if (!lvalue) {
// SEL(...) -> COND(LTE(bit<=maxlsb), ARRAYSEL(...), {width{1'bx}})
// SEL(...) -> COND(LTE(bit<=maxmsb), ARRAYSEL(...), {width{1'bx}})
AstNRelinker replaceHandle;
nodep->unlinkFrBack(&replaceHandle);
V3Number xnum (nodep->fileline(), nodep->width());
+28 -12
View File
@@ -164,15 +164,27 @@ private:
bool gt = condp->castGt() || condp->castGtS();
bool gte = condp->castGte() || condp->castGteS();
if (!lt && !lte && !gt && !gte)
return cantUnroll(nodep, "condition not <= or <");
AstNodeBiop* condBip = condp->castNodeBiop();
if (!condBip->rhsp()->castVarRef())
return cantUnroll(nodep, "condition not <=, <, >= or >");
AstNodeBiop* cmpInstrp = condp->castNodeBiop();
bool cmpVarLhs;
if (cmpInstrp->lhsp()->castVarRef()
&& cmpInstrp->lhsp()->castVarRef()->varp() == m_forVarp
&& cmpInstrp->lhsp()->castVarRef()->varScopep() == m_forVscp) {
cmpVarLhs = true;
} else if (cmpInstrp->rhsp()->castVarRef()
&& cmpInstrp->rhsp()->castVarRef()->varp() == m_forVarp
&& cmpInstrp->rhsp()->castVarRef()->varScopep() == m_forVscp) {
cmpVarLhs = false;
} else if (!cmpInstrp->rhsp()->castVarRef()) {
return cantUnroll(nodep, "no variable on rhs of condition");
if (condBip->rhsp()->castVarRef()->varp() != m_forVarp
|| condBip->rhsp()->castVarRef()->varScopep() != m_forVscp)
} else {
return cantUnroll(nodep, "different variable in condition");
if (m_generate) V3Const::constifyParamsEdit(condBip->lhsp()); // rhsp may change
AstConst* constStopp = condBip->lhsp()->castConst();
}
if (m_generate) V3Const::constifyParamsEdit(cmpVarLhs ? cmpInstrp->rhsp()
: cmpInstrp->lhsp()); // rhsp/lhsp may change
AstConst* constStopp = (cmpVarLhs ? cmpInstrp->rhsp()->castConst()
: cmpInstrp->lhsp()->castConst());
if (!constStopp) return cantUnroll(nodep, "non-constant final value");
UINFO(8, " Stop expr ok: "<<constStopp<<endl);
//
@@ -217,9 +229,9 @@ private:
if (m_varAssignHit) return cantUnroll(nodep, "genvar assigned *inside* loop");
//
// Finally, we can do it
forUnroller(nodep, initp, precondsp, condp, incp, bodysp,
forUnroller(nodep, initp, precondsp, incp, bodysp,
constInitp->num(),
condBip, constStopp->num(),
cmpInstrp, constStopp->num(), cmpVarLhs,
incInstrp, constIncp->num()); nodep = NULL;
// Cleanup
return true;
@@ -227,10 +239,10 @@ private:
void forUnroller(AstNode* nodep,
AstNode* initp,
AstNode* precondsp, AstNode* condp,
AstNode* precondsp,
AstNode* incp, AstNode* bodysp,
const V3Number& numInit,
AstNodeBiop* cmpInstrp, const V3Number& numStop,
AstNodeBiop* cmpInstrp, const V3Number& numStop, bool cmpVarLhs,
AstNodeBiop* incInstrp, const V3Number& numInc) {
UINFO(4, " Unroll for var="<<numInit<<"; var<"<<numStop<<"; var+="<<numInc<<endl);
UINFO(6, " cmpI "<<cmpInstrp<<endl);
@@ -270,7 +282,11 @@ private:
UINFO(8," Looping "<<loopValue<<endl);
// if loopValue<valStop
V3Number contin (nodep->fileline(), 1);
cmpInstrp->numberOperate(contin, numStop, loopValue);
if (cmpVarLhs) {
cmpInstrp->numberOperate(contin, loopValue, numStop);
} else {
cmpInstrp->numberOperate(contin, numStop, loopValue);
}
if (contin.isEqZero()) {
break; // Done with the loop
} else {
+1 -1
View File
@@ -931,7 +931,7 @@ private:
: nodep->findBitDType(width, width, underDtp->numeric()));
nodep->dtypep(newDtp);
// We ignore warnings as that is sort of the point of a cast
iterateCheck(nodep,"Cast LHS",nodep->lhsp(),SELF,FINAL,newDtp,EXTEND_EXP,false);
iterateCheck(nodep,"Cast LHS",nodep->lhsp(),CONTEXT,FINAL,newDtp,EXTEND_EXP,false);
}
if (vup->c()->final()) {
// CastSize not needed once sizes determined
+36 -13
View File
@@ -62,6 +62,7 @@ public:
int m_pinNum; // Pin number currently parsing
string m_instModule; // Name of module referenced for instantiations
AstPin* m_instParamp; // Parameters for instantiations
bool m_tracingParse; // Tracing disable for parser
static int s_modTypeImpNum; // Implicit type number, incremented each module
@@ -78,6 +79,7 @@ public:
m_instParamp = NULL;
m_varAttrp = NULL;
m_caseAttrp = NULL;
m_tracingParse = true;
}
static V3ParseGrammar* singletonp() {
static V3ParseGrammar singleton;
@@ -86,6 +88,9 @@ public:
// METHODS
void argWrapList(AstNodeFTaskRef* nodep);
bool allTracingOn(FileLine* fl) {
return v3Global.opt.trace() && m_tracingParse && fl->tracingOn();
}
AstNodeDType* createArray(AstNodeDType* basep, AstRange* rangep, bool isPacked);
AstVar* createVariable(FileLine* fileline, string name, AstRange* arrayp, AstNode* attrsp);
AstNode* createSupplyExpr(FileLine* fileline, string name, int value);
@@ -685,7 +690,7 @@ timeunits_declaration<nodep>: // ==IEEE: timeunits_declaration
package_declaration: // ==IEEE: package_declaration
packageFront package_itemListE yENDPACKAGE endLabelE
{ $1->modTrace(v3Global.opt.trace() && $1->fileline()->tracingOn()); // Stash for implicit wires, etc
{ $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); // Stash for implicit wires, etc
if ($2) $1->addStmtp($2);
SYMP->popScope($1);
GRAMMARP->endLabel($<fl>4,$1,$4); }
@@ -695,7 +700,7 @@ packageFront<modulep>:
yPACKAGE idAny ';'
{ $$ = new AstPackage($1,*$2);
$$->inLibrary(true); // packages are always libraries; don't want to make them a "top"
$$->modTrace(v3Global.opt.trace());
$$->modTrace(GRAMMARP->allTracingOn($$->fileline()));
PARSEP->rootp()->addModulep($$);
SYMP->pushNew($$); }
;
@@ -768,7 +773,7 @@ module_declaration: // ==IEEE: module_declaration
// // IEEE: module_nonansi_header + module_ansi_header
modFront importsAndParametersE portsStarE ';'
module_itemListE yENDMODULE endLabelE
{ $1->modTrace(v3Global.opt.trace() && $1->fileline()->tracingOn()); // Stash for implicit wires, etc
{ $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); // Stash for implicit wires, etc
if ($2) $1->addStmtp($2); if ($3) $1->addStmtp($3);
if ($5) $1->addStmtp($5);
SYMP->popScope($1);
@@ -778,6 +783,7 @@ module_declaration: // ==IEEE: module_declaration
{ $1->modTrace(false); // Stash for implicit wires, etc
if ($2) $1->addStmtp($2); if ($3) $1->addStmtp($3);
if ($5) $1->addStmtp($5);
GRAMMARP->m_tracingParse = true;
SYMP->popScope($1);
GRAMMARP->endLabel($<fl>7,$1,$7); }
//
@@ -790,7 +796,7 @@ modFront<modulep>:
// // any formal arguments, as the arguments must land in the new scope.
yMODULE lifetimeE idAny
{ $$ = new AstModule($1,*$3); $$->inLibrary(PARSEP->inLibrary()||PARSEP->inCellDefine());
$$->modTrace(v3Global.opt.trace());
$$->modTrace(GRAMMARP->allTracingOn($$->fileline()));
PARSEP->rootp()->addModulep($$);
SYMP->pushNew($$); }
;
@@ -806,7 +812,7 @@ udpFront<modulep>:
{ $$ = new AstPrimitive($1,*$3); $$->inLibrary(true);
$$->modTrace(false);
$$->addStmtp(new AstPragma($1,AstPragmaType::INLINE_MODULE));
PARSEP->fileline()->tracingOn(false);
GRAMMARP->m_tracingParse = false;
PARSEP->rootp()->addModulep($$);
SYMP->pushNew($$); }
;
@@ -1011,7 +1017,7 @@ program_declaration: // IEEE: program_declaration + program_nonansi_header + pr
// // timeunits_delcarationE is instead in program_item
pgmFront parameter_port_listE portsStarE ';'
program_itemListE yENDPROGRAM endLabelE
{ $1->modTrace(v3Global.opt.trace() && $1->fileline()->tracingOn()); // Stash for implicit wires, etc
{ $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); // Stash for implicit wires, etc
if ($2) $1->addStmtp($2); if ($3) $1->addStmtp($3);
if ($5) $1->addStmtp($5);
SYMP->popScope($1);
@@ -1023,7 +1029,7 @@ program_declaration: // IEEE: program_declaration + program_nonansi_header + pr
pgmFront<modulep>:
yPROGRAM lifetimeE idAny/*new_program*/
{ $$ = new AstModule($1,*$3); $$->inLibrary(PARSEP->inLibrary()||PARSEP->inCellDefine());
$$->modTrace(v3Global.opt.trace());
$$->modTrace(GRAMMARP->allTracingOn($$->fileline()));
PARSEP->rootp()->addModulep($$);
SYMP->pushNew($$); }
;
@@ -1594,8 +1600,9 @@ implicit_typeE<dtypep>: // IEEE: part of *data_type_or_implicit
type_declaration<nodep>: // ==IEEE: type_declaration
// // Use idAny, as we can redeclare a typedef on an existing typedef
yTYPEDEF data_type idAny variable_dimensionListE ';' { $$ = new AstTypedef($<fl>1, *$3, VFlagChildDType(), GRAMMARP->createArray($2,$4,false));
SYMP->reinsert($$); }
yTYPEDEF data_type idAny variable_dimensionListE dtypeAttrListE ';'
/**/ { $$ = new AstTypedef($<fl>1, *$3, $5, VFlagChildDType(), GRAMMARP->createArray($2,$4,false));
SYMP->reinsert($$); }
//UNSUP yTYPEDEF id/*interface*/ '.' idAny/*type*/ idAny/*type*/ ';' { $$ = NULL; $1->v3error("Unsupported: SystemVerilog 2005 typedef in this context"); } //UNSUP
// // Combines into above "data_type id" rule
// // Verilator: Not important what it is in the AST, just need to make sure the yaID__aTYPE gets returned
@@ -1606,6 +1613,20 @@ type_declaration<nodep>: // ==IEEE: type_declaration
//UNSUP yTYPEDEF yCLASS idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($<fl>1, *$3); SYMP->reinsert($$); }
;
dtypeAttrListE<nodep>:
/* empty */ { $$ = NULL; }
| dtypeAttrList { $$ = $1; }
;
dtypeAttrList<nodep>:
dtypeAttr { $$ = $1; }
| dtypeAttrList dtypeAttr { $$ = $1->addNextNull($2); }
;
dtypeAttr<nodep>:
yVL_PUBLIC { $$ = new AstAttrOf($1,AstAttrType::DT_PUBLIC); }
;
//************************************************
// Module Items
@@ -2017,9 +2038,11 @@ instnameList<nodep>:
| instnameList ',' instnameParen { $$ = $1->addNext($3); }
;
instnameParen<nodep>:
id instRangeE '(' cellpinList ')' { $$ = new AstCell($<fl>1,*$1,GRAMMARP->m_instModule,$4, GRAMMARP->m_instParamp,$2); }
| id instRangeE { $$ = new AstCell($<fl>1,*$1,GRAMMARP->m_instModule,NULL,GRAMMARP->m_instParamp,$2); }
instnameParen<cellp>:
id instRangeE '(' cellpinList ')' { $$ = new AstCell($<fl>1,*$1,GRAMMARP->m_instModule,$4, GRAMMARP->m_instParamp,$2);
$$->trace(GRAMMARP->allTracingOn($<fl>1)); }
| id instRangeE { $$ = new AstCell($<fl>1,*$1,GRAMMARP->m_instModule,NULL,GRAMMARP->m_instParamp,$2);
$$->trace(GRAMMARP->allTracingOn($<fl>1)); }
//UNSUP instRangeE '(' cellpinList ')' { UNSUP } // UDP
// // Adding above and switching to the Verilog-Perl syntax
// // causes a shift conflict due to use of idClassSel inside exprScope.
@@ -3783,7 +3806,7 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, string name, AstRange
// Propagate from current module tracing state
if (nodep->isGenVar()) nodep->trace(false);
else if (nodep->isParam() && !v3Global.opt.traceParams()) nodep->trace(false);
else nodep->trace(v3Global.opt.trace() && nodep->fileline()->tracingOn());
else nodep->trace(allTracingOn(nodep->fileline()));
// Remember the last variable created, so we can attach attributes to it in later parsing
GRAMMARP->m_varAttrp = nodep;
+23
View File
@@ -0,0 +1,23 @@
#!/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 (
v_flags2 => ["--stats"],
);
execute (
check_finished=>1,
);
if ($Self->{vlt}) {
file_grep ($Self->{stats}, qr/Optimizations, Gate assign merged\s+(\d+)/i, 28);
};
ok(1);
1;
+100
View File
@@ -0,0 +1,100 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2014 by Jie Xu.
//
// change these two parameters to see the speed differences
`define DATA_WIDTH 8
`define REP_COUNT4 `DATA_WIDTH/4
`define REP_COUNT2 `DATA_WIDTH/2
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
reg [3:0] count4 = 0;
reg [1:0] count2 = 0;
reg [`DATA_WIDTH-1:0] a = {`REP_COUNT4{4'b0000}};
reg [`DATA_WIDTH-1:0] b = {`REP_COUNT4{4'b1111}};
reg [`DATA_WIDTH-1:0] c = {`REP_COUNT4{4'b1111}};
reg [`DATA_WIDTH-1:0] d = {`REP_COUNT4{4'b1111}};
reg [`DATA_WIDTH-1:0] res1;
reg [`DATA_WIDTH-1:0] res2;
reg [`DATA_WIDTH-1:0] res3;
reg [`DATA_WIDTH-1:0] res4;
drv1 t_drv1 [`DATA_WIDTH-1:0] (.colSelA(a), .datao(res1));
drv2 t_drv2 [`DATA_WIDTH-1:0] (.colSelA(a), .colSelB(b), .datao(res2));
drv3 t_drv3 [`DATA_WIDTH-1:0] (.colSelA(a), .colSelB(b), .colSelC(c), .datao(res3));
drv4 t_drv4 [`DATA_WIDTH-1:0] (.colSelA(a), .colSelB(b), .colSelC(c), .colSelD(d), .datao(res4));
always@(posedge clk)
begin
count2 <= count2 + 1;
count4 <= count4 + 1;
a <= {`REP_COUNT4{count4}};
b <= {`REP_COUNT4{count4}};
c <= {`REP_COUNT2{count2}};
d <= {`REP_COUNT2{count2}};
if (res1 != (a)) begin
$stop;
end
if (res2 != (a&b)) begin
$stop;
end
if (res3 != (a&b&c)) begin
$stop;
end
if (res4 != (a&b&c&d)) begin
$stop;
end
if (count4 > 10) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module drv1
(input colSelA,
output datao
);
assign datao = colSelA;
endmodule
module drv2
(input colSelA,
input colSelB,
output datao
);
assign datao = colSelB & colSelA;
endmodule
module drv3
(input colSelA,
input colSelB,
input colSelC,
output datao
);
assign datao = colSelB & colSelA & colSelC;
endmodule
module drv4
(input colSelA,
input colSelB,
input colSelC,
input colSelD,
output datao
);
assign datao = colSelB & colSelA & colSelC & colSelD;
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 2004 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;
+71
View File
@@ -0,0 +1,71 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2004 by Jie Xu.
//
// The test was added together with the concat optimization.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc; initial cyc=1;
reg [31:0] in_a;
reg [31:0] in_b;
reg [31:0] in_c;
reg [31:0] in_d;
reg [31:0] in_e;
reg [15:0] in_f;
wire [31:0] in_g;
assign in_g = in_a << 4;
reg [31:0] out_x;
reg [31:0] out_y;
reg [31:0] out_z;
reg [31:0] out_o;
reg [31:0] out_p;
reg [31:0] out_q;
assign out_x = {in_a[31:16] & in_f, in_a[15:0] & in_f};
assign out_y = {in_a[31:18] & in_b[31:18], in_a[17:0] & in_b[17:0]};
assign out_z = {in_c[31:14] & in_d[31:14] & in_e[31:14], in_c[13:0] & in_d[13:0] & in_e[13:0]};
assign out_o = out_z | out_y;
assign out_p = {in_a[31:16] & in_f | in_e[31:16], in_a[15:0] & in_f | in_e[15:0]};
assign out_q = {{in_a[31:25] ^ in_g[31:25], in_a[24:16] ^ in_g[24:16]}, {in_a[15:5] ^ in_g[15:5], in_a[4:0] ^ in_g[4:0]}};
always @ (posedge clk) begin
if (cyc!=0) begin
cyc <= cyc + 1;
in_a <= cyc;
in_b <= cyc + 1;
in_c <= cyc + 3;
in_d <= cyc + 8;
in_e <= cyc;
in_f <= cyc[15:0];
if (out_x != (in_a & {2{in_f}}))
$stop;
if (out_y != (in_a&in_b))
$stop;
if (out_z != (in_e&in_d&in_c))
$stop;
if (out_o != (((in_a&in_b)|(in_c&in_e&in_d))))
$stop;
if (out_p != (in_a & {2{in_f}} | in_e))
$stop;
if (out_q != (in_a ^ in_g))
$stop;
if (cyc==100) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
end
endmodule
+26
View File
@@ -0,0 +1,26 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2006 by Wilson Snyder.
#include <verilated.h>
#include "Vt_enum_public.h"
#include "Vt_enum_public_p3.h"
#include "Vt_enum_public_p62.h"
int main (int argc, char *argv[]) {
Vt_enum_public *topp = new Vt_enum_public;
Verilated::debug(0);
// Make sure public tag worked
if (Vt_enum_public_p3::ZERO || Vt_enum_public_p3::ONE) {}
if (Vt_enum_public_p62::ZERO || Vt_enum_public_p62::ALLONE) {}
for (int i = 0; i < 10; i++) {
topp->eval();
}
}
+26
View File
@@ -0,0 +1,26 @@
#!/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.
if ($Self->{vlt}) {
compile (
verilator_flags2 => ["--exe $Self->{t_dir}/$Self->{name}.cpp"],
make_top_shell => 0,
make_main => 0,
);
} else {
compile (
);
}
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, 2009 by Wilson Snyder.
package p3;
typedef enum logic [2:0] {
ZERO = 3'b0,
ONE = 3'b1 } e3_t /*verilator public*/;
endpackage
package p62;
typedef enum logic [62:0] {
ZERO = '0,
ALLONE = '1 } e62_t /*verilator public*/;
endpackage
module t (/*AUTOARG*/);
enum integer {
EI_A,
EI_B,
EI_C
} m_state;
initial begin
m_state = EI_A;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+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 2008 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 (
v_flags2 => ["-f t/t_flag_define.vc"],
);
execute (
check_finished=>1,
);
ok(1);
1;
+61
View File
@@ -0,0 +1,61 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2014 by Wilson Snyder
`define STRINGIFY(x) `"x`"
module t;
initial begin
`ifdef D1A
if (`STRINGIFY(`D4B) !== "") $stop;
`else
$write("%%Error: Missing define\n"); $stop;
`endif
`ifdef D2A
if (`STRINGIFY(`D2A) !== "VALA") $stop;
`else
$write("%%Error: Missing define\n"); $stop;
`endif
`ifdef D3A
if (`STRINGIFY(`D4B) !== "") $stop;
`else
$write("%%Error: Missing define\n"); $stop;
`endif
`ifdef D3B
if (`STRINGIFY(`D4B) !== "") $stop;
`else
$write("%%Error: Missing define\n"); $stop;
`endif
`ifdef D4A
if (`STRINGIFY(`D4A) !== "VALA") $stop;
`else
$write("%%Error: Missing define\n"); $stop;
`endif
`ifdef D4B
if (`STRINGIFY(`D4B) !== "") $stop;
`else
$write("%%Error: Missing define\n"); $stop;
`endif
`ifdef D5A
if (`STRINGIFY(`D5A) !== "VALA") $stop;
`else
$write("%%Error: Missing define\n"); $stop;
`endif
`ifdef D5A
if (`STRINGIFY(`D5B) !== "VALB") $stop;
`else
$write("%%Error: Missing define\n"); $stop;
`endif
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+7
View File
@@ -0,0 +1,7 @@
+define+D1A
+define+D2A=VALA
+define+D3A+D3B
+define+D4A=VALA+D4B
+define+D5A=VALA+D5B=VALB
// Quotes do NOT escape the plus
//+define+D5A="VALA+D5B"+D5C
+11
View File
@@ -26,6 +26,7 @@
reg [5:0] w6_u;
reg [15:0] w16a_u;
reg [15:0] w16_u;
reg [31:0] w32_u;
real r;
reg signed [4:0] bug754_a;
@@ -162,6 +163,16 @@
w4_u = (w4_u >> w4_u) ^~ (w4_u >> w4_u);
`checkh(w4_u, 4'b1111);
// bug828
// verilator lint_off WIDTH
w32_u = 32'(signed'({4'b0001,5'b10000}) << 3);
`checkh(w32_u, 32'h0000_0180);
w32_u = 32'(signed'({4'b0011,5'b10000}) << 3);
`checkh(w32_u, 32'h0000_0380);
// verilator lint_on WIDTH
w32_u = 32'(signed'({4'b0011,5'b10000})) << 3; // Check no width warning
`checkh(w32_u, 32'h0000_0380);
if (fail) $stop;
$write("*-* All Finished *-*\n");
$finish;
+24
View File
@@ -0,0 +1,24 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2006 by Wilson Snyder.
#include <verilated.h>
#include "Vt_param_public.h"
#include "Vt_param_public_p.h"
int main (int argc, char *argv[]) {
Vt_param_public *topp = new Vt_param_public;
Verilated::debug(0);
// Make sure public tag worked
if (Vt_param_public_p::INPACK) {}
for (int i = 0; i < 10; i++) {
topp->eval();
}
}
+10 -2
View File
@@ -7,8 +7,16 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
if ($Self->{vlt}) {
compile (
verilator_flags2 => ["--exe $Self->{t_dir}/$Self->{name}.cpp"],
make_top_shell => 0,
make_main => 0,
);
} else {
compile (
);
}
execute (
check_finished=>1,
+5
View File
@@ -36,3 +36,8 @@ module b #(
initial if ($c32("TWO") != 2) $stop;
`endif
endmodule
//bug804
package p;
localparam INPACK /*verilator public*/ = 6;
endpackage
+5 -1
View File
@@ -788,6 +788,10 @@ module t;
initial $write("GOT='%s' EXP='%s'\n", "foo `A(bar) baz", "foo `A(bar) baz");
initial $write("Slashed=`%s'\n", "1//2.3");
endmodule
@@ -809,4 +813,4 @@ predef 1 1
predef 2 2
`line 544 "t/t_preproc.v" 2
`line 548 "t/t_preproc.v" 2
+4
View File
@@ -520,6 +520,10 @@ module t;
`define A(name) boo name hiss
initial $write("GOT='%s' EXP='%s'\n", `STR(`A(bar)), "foo `A(bar) baz");
`undef A `undef STR
//----
// bug845
`define SLASHED "1//2.3"
initial $write("Slashed=`%s'\n", `SLASHED);
endmodule
//======================================================================
// IEEE mandated predefines
+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;
+91
View File
@@ -0,0 +1,91 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2014 by Wilson Snyder.
// bug823
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=0;
reg [63:0] crc;
reg [63:0] sum;
// Take CRC data and apply to testblock inputs
wire [2:0] in = crc[2:0];
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire [3:0] mask; // From test of Test.v
wire [3:0] out; // From test of Test.v
// End of automatics
Test test (/*AUTOINST*/
// Outputs
.out (out[3:0]),
.mask (mask[3:0]),
// Inputs
.clk (clk),
.in (in[2:0]));
// Aggregate outputs into a single result vector
wire [63:0] result = {60'h0, out & mask};
// Test loop
always @ (posedge clk) begin
`ifdef TEST_VERBOSE
$write("[%0t] cyc==%0d crc=%x out=%b mask=%b\n",$time, cyc, crc, out, mask);
`endif
cyc <= cyc + 1;
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
sum <= result ^ {sum[62:0],sum[63]^sum[2]^sum[0]};
if (cyc==0) begin
// Setup
crc <= 64'h5aef0c8d_d70a4497;
sum <= '0;
end
else if (cyc<10) begin
sum <= '0;
end
else if (cyc<90) begin
end
else if (cyc==99) begin
$write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum);
if (crc !== 64'hc77bb9b3784ea091) $stop;
// What checksum will we end up with (above print should match)
`define EXPECTED_SUM 64'ha9d3a7a69d2bea75
if (sum !== `EXPECTED_SUM) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module Test (/*AUTOARG*/
// Outputs
out, mask,
// Inputs
clk, in
);
input clk;
input [2:0] in;
output reg [3:0] out;
output reg [3:0] mask;
localparam [15:5] p = 11'h1ac;
always @(posedge clk) begin
// verilator lint_off WIDTH
out <= p[15 + in -: 5];
// verilator lint_on WIDTH
mask[3] <= ((15 + in - 5) < 12);
mask[2] <= ((15 + in - 5) < 13);
mask[1] <= ((15 + in - 5) < 14);
mask[0] <= ((15 + in - 5) < 15);
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;
+91
View File
@@ -0,0 +1,91 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2014 by Wilson Snyder.
// bug823
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=0;
reg [63:0] crc;
reg [63:0] sum;
// Take CRC data and apply to testblock inputs
wire [6:0] in = crc[6:0];
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire [3:0] mask; // From test of Test.v
wire [3:0] out; // From test of Test.v
// End of automatics
Test test (/*AUTOINST*/
// Outputs
.out (out[3:0]),
.mask (mask[3:0]),
// Inputs
.clk (clk),
.in (in[6:0]));
// Aggregate outputs into a single result vector
wire [63:0] result = {60'h0, out & mask};
// Test loop
always @ (posedge clk) begin
`ifdef TEST_VERBOSE
$write("[%0t] cyc==%0d crc=%x out=%b mask=%b\n",$time, cyc, crc, out, mask);
`endif
cyc <= cyc + 1;
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
sum <= result ^ {sum[62:0],sum[63]^sum[2]^sum[0]};
if (cyc==0) begin
// Setup
crc <= 64'h5aef0c8d_d70a4497;
sum <= '0;
end
else if (cyc<10) begin
sum <= '0;
end
else if (cyc<90) begin
end
else if (cyc==99) begin
$write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum);
if (crc !== 64'hc77bb9b3784ea091) $stop;
// What checksum will we end up with (above print should match)
`define EXPECTED_SUM 64'h4e9d3a74e9d3f656
if (sum !== `EXPECTED_SUM) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module Test (/*AUTOARG*/
// Outputs
out, mask,
// Inputs
clk, in
);
input clk;
input [6:0] in; // Note much wider than any index
output reg [3:0] out;
output reg [3:0] mask;
localparam [15:5] p = 11'h1ac;
always @(posedge clk) begin
// verilator lint_off WIDTH
out <= p[15 + in -: 5];
// verilator lint_on WIDTH
mask[3] <= ((15 + in - 5) < 12);
mask[2] <= ((15 + in - 5) < 13);
mask[1] <= ((15 + in - 5) < 14);
mask[0] <= ((15 + in - 5) < 15);
end
endmodule
+1 -1
View File
@@ -66,7 +66,7 @@ module t (/*AUTOARG*/
8'd04: begin if ((to^from)!==80'h6d000000000000000000) $stop; end
8'd05: begin if (((to^from)&~80'hf)!==80'h90000000000000000000) $stop; end // Exceed bounds, verilator may write index 0
8'd06: begin if (((to^from)&~80'hf)!==80'h00000000000000000020) $stop; end // Exceed bounds, verilator may write index 0
8'd07: begin if (((to^from)&~80'hf)!==80'h0c000000000000000000) $stop; end
8'd07: begin if (((to^from)&~80'hf)!==80'h4c000000000000000000) $stop; end
8'd08: begin if ((to^from)!==80'h0004d000000000000000) $stop; end
8'd09: begin if (((to^from)&~80'hf)!==80'h00000000000000000000) $stop; end
default: $stop;
+21
View File
@@ -0,0 +1,21 @@
#!/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 => ['--cc --trace --trace-structs'],
);
execute (
check_finished=>1,
);
file_grep ("$Self->{obj_dir}/simx.vcd", qr/\$enddefinitions/x);
ok(1);
1;
+26
View File
@@ -0,0 +1,26 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2014 by Wilson Snyder.
module t (clk);
input clk;
integer cyc=0;
// Trace would overflow at 256KB which is 256 kb dump, 16 kb in a chunk
typedef struct packed {
logic [1024*1024:0] d;
} s1_t; // 128 b
s1_t biggie;
always @ (posedge clk) begin
cyc <= cyc + 1;
biggie [ cyc +: 32 ] <= 32'hfeedface;
if (cyc == 5) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
+8
View File
@@ -17,6 +17,10 @@ module t (/*AUTOARG*/
integer c_trace_on;
real r;
// verilator tracing_off
sub sub ();
// verilator tracing_on
always @ (posedge clk) begin
if (cyc!=0) begin
cyc <= cyc + 1;
@@ -34,3 +38,7 @@ module t (/*AUTOARG*/
end
endmodule
module sub;
integer inside_sub = 0;
endmodule
+1
View File
@@ -21,6 +21,7 @@ if ($Self->{vlt}) {
file_grep ("$Self->{obj_dir}/V$Self->{name}__Trace__Slow.cpp", qr/c_trace_on\"/x);
file_grep_not ("$Self->{obj_dir}/V$Self->{name}__Trace__Slow.cpp", qr/_trace_off\"/x);
file_grep ("$Self->{obj_dir}/simx.vcd", qr/\$enddefinitions/x);
file_grep_not ("$Self->{obj_dir}/simx.vcd", qr/inside_sub/x);
}
ok(1);
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2013 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 (
v_flags2 => ["--trace"],
);
execute (
check_finished=>1,
);
if ($Self->{vlt}) {
file_grep ("$Self->{obj_dir}/simx.vcd", "sub_t_i");
};
ok(1);
1;
+43
View File
@@ -0,0 +1,43 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2014 by Jie Xu.
module t
(
clk
);
input clk;
integer cyc; initial cyc = 0;
reg a;
reg b;
reg z;
sub_t sub_t_i (z, a, b);
always @ (posedge clk) begin
cyc <= cyc + 1;
a <= cyc[0];
b <= cyc[1];
if (cyc > 10) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
primitive CINV (a, b);
output b;
input a;
assign b = ~a;
endprimitive
module sub_t (z, x, y);
input x, y;
output z;
assign z = x & y;
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;
+29
View File
@@ -0,0 +1,29 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2004 by Wilson Snyder.
//bug830
module sub();
endmodule
function integer cdiv(input integer x);
begin
cdiv = 10;
end
endfunction
module t (/*AUTOARG*/);
genvar j;
generate
for (j = 0; j < cdiv(10); j=j+1)
sub sub();
endgenerate
initial begin
$write("*-* All Finished *-*\n");
$finish;
end
endmodule