Compare commits

...
47 Commits
Author SHA1 Message Date
Wilson Snyder 0abde90933 Version bump 2013-05-11 16:11:38 -04:00
Wilson Snyder e01b69198a driver: Fix if no forker. 2013-05-11 16:11:26 -04:00
Wilson Snyder 53cd9d2403 Fix nested union crash, bug643. 2013-05-10 21:02:48 -04:00
Wilson Snyder 3d0f5fc078 Fix packed array non-zero right index select crash, bug642. 2013-05-10 07:09:25 -04:00
Wilson Snyder 54eedcc739 Support signal[vec]++. 2013-05-06 08:02:16 -04:00
Wilson Snyder ae6f5844da Add Verilated::internalsDump() 2013-05-04 10:29:54 -04:00
Wilson Snyder 1bea845ceb Fix simulation error when inputs and MULTIDRIVEN, bug634. 2013-05-02 08:23:17 -04:00
Wilson Snyder d581582339 Add ALWCOMBORDER warning. 2013-04-30 22:55:28 -04:00
Wilson Snyder 4eabc1992e Fix gcc 4.1.2 compile warnings 2013-04-30 22:55:03 -04:00
Wilson Snyder 316eb24bbb Example test 2013-04-28 18:58:04 -04:00
Jeremy Bennett f0a8824efc Commentary, bug639.
Signed-off-by: Wilson Snyder <[email protected]>
2013-04-28 09:04:04 -04:00
Wilson Snyder 345a5d5646 Add --pins-sc-uint and --pins-sc-biguint, bug638. 2013-04-26 21:02:32 -04:00
Wilson Snyder 464679c78b Fix module resolution with __, bug631. 2013-03-12 07:27:17 -04:00
Wilson Snyder 28eeec1cf4 devel release 2013-03-09 16:48:10 -05:00
Wilson Snyder 7d0dce3267 Version bump 2013-03-09 16:44:48 -05:00
Wilson Snyder 9e29625207 Fix UNOPTFLAT circular array bounds crossing, bug630. 2013-03-08 19:25:20 -05:00
Wilson Snyder a767da4f3f Support <number>'() sized casts, bug628. 2013-03-05 22:13:22 -05:00
Wilson Snyder 7bd96c2876 Internals: Tristate commentary 2013-02-27 22:59:17 -05:00
Wilson Snyder 70fd64dcd6 IEEE 1800-2012 is now the default language. This adds 4 new keywords and updates the svdpi.h and vpi_user.h header files. 2013-02-26 23:01:19 -05:00
Jeremy Bennett bb2822f4b5 Add --report-unoptflat, bug611.
Signed-off-by: Wilson Snyder <[email protected]>
2013-02-26 22:26:47 -05:00
Wilson Snyder ad21108b63 Internals: Create graph clone methods. 2013-02-25 21:03:50 -05:00
Wilson Snyder e6808a787c Fix opening a VerilatedVcdC file multiple times, msg1021. 2013-02-23 21:10:25 -05:00
Wilson Snyder 1fb2762725 Tests: Clocking test to consider bug623. 2013-02-22 21:00:37 -05:00
Wilson Snyder cce55941d3 Makefile: Distribute .gdbinit 2013-02-22 17:24:15 -05:00
Wilson Snyder 6c8d95e0e2 Nice message on fopen with missing argument. 2013-02-22 17:14:27 -05:00
Wilson Snyder 216a178b28 Makefile: Distribute .gdbinit 2013-02-22 17:13:31 -05:00
Wilson Snyder 6594a54a95 Fix wrong dot resolution under inlining. 2013-02-21 23:38:29 -05:00
Wilson Snyder a9a4cf061a Fix tristate duplicate __Vcellinp declaration 2013-02-20 22:28:56 -05:00
Wilson Snyder b7f0e204cb Spelling fixes 2013-02-20 21:51:39 -05:00
Varun Koyyalagunta e6a15f233b Internals: GateDedupe: Use visitor per msg980.
Signed-off-by: Wilson Snyder <[email protected]>
2013-02-20 20:26:53 -05:00
Varun Koyyalagunta e0edb596ea Add duplicate clock gate optimization, msg980.
Experimental and disabled unless -OD or -O3 used (for now),
Please try it as may get some significant speedups.

Signed-off-by: Wilson Snyder <[email protected]>
2013-02-20 20:14:15 -05:00
Varun Koyyalagunta f2fb77c15a Internals: New Hashed/Graph functions towards msg980.
Signed-off-by: Wilson Snyder <[email protected]>
2013-02-19 18:49:36 -05:00
Wilson Snyder 772a3a97eb Internals: Functions in order. No functional change. 2013-02-18 12:15:50 -05:00
Wilson Snyder 6c310836a1 Internals: Track original signal name. No functional change. 2013-02-18 11:22:24 -05:00
Wilson Snyder 75416a3016 Commentary 2013-02-18 11:05:47 -05:00
Wilson Snyder ebef78a13e Tests 2013-02-18 10:17:34 -05:00
Wilson Snyder e71baca39b Internals: Make propagateAttrClocksFrom. No functional change. 2013-02-16 08:07:18 -05:00
Wilson Snyder 18eb210313 Support bind in , bug602. 2013-02-14 06:55:09 -05:00
Wilson Snyder 7d38a5e1f9 Test bug424. 2013-02-13 21:10:17 -05:00
Wilson Snyder 4386077e2d Support pattern assignments with data type labels, bug618. 2013-02-13 20:52:38 -05:00
Wilson Snyder 49dbfd2131 Support pattern assignments in function calls, bug617. 2013-02-13 20:32:25 -05:00
Wilson Snyder a80fce5ac1 Support pattern assignments to const variables, bug616. 2013-02-13 19:32:36 -05:00
Wilson Snyder 891b981cab Fix LITENDIAN on unpacked structures, bug614. 2013-02-13 19:03:10 -05:00
Rich Porter 2dd87b8384 Fix 32-bit OS VPI scan issue, bug615.
Signed-off-by: Wilson Snyder <[email protected]>
2013-02-11 07:17:18 -05:00
Jeremy Bennett 062eb85075 Fix DETECTARRAY on packed structures, bug610.
Signed-off-by: Wilson Snyder <[email protected]>
2013-02-10 09:54:27 -05:00
Wilson Snyder e1f6802f5f tests: Fix bootstrap wouldn't cd for test_regress/t/t_dist_portability.pl. 2013-02-10 09:29:35 -05:00
Wilson Snyder 6cfcd50f12 devel release 2013-02-04 22:19:37 -05:00
127 changed files with 6562 additions and 406 deletions
+47
View File
@@ -3,6 +3,53 @@ 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.847 2013-05-11
*** Add ALWCOMBORDER warning. [KC Buckenmaier]
*** Add --pins-sc-uint and --pins-sc-biguint, bug638. [Alex Hornung]
**** Support "signal[vec]++".
**** Fix simulation error when inputs and MULTIDRIVEN, bug634. [Ted Campbell]
**** Fix module resolution with __, bug631. [Jason McMullan]
**** Fix packed array non-zero right index select crash, bug642. [Krzysztof Jankowski]
**** Fix nested union crash, bug643. [Krzysztof Jankowski]
* Verilator 3.846 2013-03-09
** IEEE 1800-2012 is now the default language. This adds 4 new keywords
and updates the svdpi.h and vpi_user.h header files.
*** Add --report-unoptflat, bug611. [Jeremy Bennett]
*** Add duplicate clock gate optimization, msg980. [Varun Koyyalagunta]
Disabled unless -OD or -O3 used, please try it as may get some
significant speedups.
*** Fix wrong dot resolution under inlining. [Art Stamness]
**** Support pattern assignment features, bug616, bug617, bug618. [Ed Lander]
**** Support bind in $unit, bug602. [Ed Lander]
**** Support <number>'() sized casts, bug628. [Ed Lander]
**** Fix DETECTARRAY on packed structures, bug610. [Jeremy Bennett]
**** Fix LITENDIAN on unpacked structures, bug614. [Wai Sum Mong]
**** Fix 32-bit OS VPI scan issue, bug615. [Jeremy Bennett, Rich Porter]
**** Fix opening a VerilatedVcdC file multiple times, msg1021. [Frederic Requin]
**** Fix UNOPTFLAT circular array bounds crossing, bug630. [Jie Xu]
* Verilator 3.845 2013/02/04
*** Fix nested packed arrays and struct, bug600. [Jeremy Bennett]
+1 -1
View File
@@ -1,6 +1,5 @@
^CVS/
/CVS/
\.gdbinit$
\.git/
\.svn/
\.(bak|old)/
@@ -23,6 +22,7 @@
src/Makefile$
src/Makefile_obj$
include/verilated.mk$
test_regress/.gdbinit$
config.cache$
config.status$
verilator.log
+1
View File
@@ -121,6 +121,7 @@ DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING COPYING.LESSER \
include/vltstd/*.[chv]* \
.*attributes */.*attributes */*/.*attributes \
src/.*ignore src/*.in src/*.cpp src/*.[chly] src/astgen src/bisonpre src/*fix \
src/.gdbinit \
src/*.pl src/*.pod \
test_*/.*ignore test_*/Makefile* test_*/*.cpp \
test_*/*.pl test_*/*.v test_*/*.vc test_*/*.vh \
+78 -16
View File
@@ -245,6 +245,7 @@ descriptions in the next sections for more information.
+1364-2005ext+<ext> Use Verilog 2005 with file extension <ext>
+1800-2005ext+<ext> Use SystemVerilog 2005 with file extension <ext>
+1800-2009ext+<ext> Use SystemVerilog 2009 with file extension <ext>
+1800-2012ext+<ext> Use SystemVerilog 2012 with file extension <ext>
--assert Enable all assertions
--autoflush Flush streams after all $displays
--bbox-sys Blackbox unknown $system calls
@@ -301,6 +302,8 @@ descriptions in the next sections for more information.
--output-split <bytes> Split .cpp files into pieces
--output-split-cfuncs <statements> Split .ccp functions
--pins-bv <bits> Specify types for top level ports
--pins-sc-uint Specify types for top level ports
--pins-sc-biguint Specify types for top level ports
--pins-uint8 Specify types for top level ports
--pipe-filter <command> Filter all input through a script
--prefix <topname> Name of top level class
@@ -308,12 +311,13 @@ descriptions in the next sections for more information.
--private Debugging; see docs
--psl Enable PSL parsing
--public Debugging; see docs
--report-unoptflat Extra diagnostics for UNOPTFLAT
--savable Enable model save-restore
--sc Create SystemC output
--sp Create SystemPerl output
--stats Create statistics file
-sv Enable SystemVerilog parsing
+systemverilogext+<ext> Synonym for +1800-2009ext+<ext>
+systemverilogext+<ext> Synonym for +1800-2012ext+<ext>
--top-module <topname> Name of top level input module
--trace Enable waveform creation
--trace-depth <levels> Depth of tracing
@@ -373,6 +377,8 @@ with the --exe option.
=item +1800-2009ext+I<ext>
=item +1800-2012ext+I<ext>
Specifies the language standard to be used with a specific filename
extension, I<ext>.
@@ -584,7 +590,7 @@ C<--debug> is equivalent to C<--debugi 4>).
Select the language to be used by default when first processing each
Verilog file. The language value must be "1364-1995", "1364-2001",
"1364-2005", "1800-2005" or "1800-2009".
"1364-2005", "1800-2005", "1800-2009" or "1800-2012".
Any language associated with a particular file extension (see the various
+I<lang>ext+ options) will be used in preference to the language specified
@@ -597,7 +603,7 @@ legacy mixed language designs, the various +I<lang>ext+ options should be
used.
If no language is specified, either by this flag or +I<lang>ext+ options,
then the latest SystemVerilog language (IEEE 1800-2009) is used.
then the latest SystemVerilog language (IEEE 1800-2012) is used.
=item +define+I<var>+I<value>
@@ -816,6 +822,20 @@ wide should use sc_bv's instead of uint32/vluint64_t's. The default is
33". The more sc_bv is used, the worse for performance. Use the
"/*verilator sc_bv*/" attribute to select specific ports to be sc_bv.
=item --pins-sc-uint
Specifies SystemC inputs/outputs of greater than 2 bits wide should use
sc_uint between 2 and 64. When combined with the "--pins-sc-biguint"
combination, it results in sc_uint being used between 2 and 64 and
sc_biguint being used between 65 and 512.
=item --pins-sc-biguint
Specifies SystemC inputs/outputs of greater than 65 bits wide should use
sc_biguint between 65 and 512, and sc_bv from 513 upwards. When combined
with the "--pins-sc-uint" combination, it results in sc_uint being used
between 2 and 64 and sc_biguint being used between 65 and 512.
=item --pins-uint8
Specifies SystemC inputs/outputs that are smaller than the --pins-bv
@@ -877,6 +897,27 @@ inlining. This will also turn off inlining as if all modules had a
/*verilator public_module*/, unless the module specifically enabled it with
/*verilator inline_module*/.
=item --report-unoptflat
Extra diagnostics for UNOPTFLAT warnings. This includes for each loop, the
10 widest variables in the loop, and the 10 most fanned out variables in
the loop. These are candidates for splitting into multiple variables to
break the loop.
In addition produces a GraphViz DOT file of the entire strongly connected
components within the source associated with each loop. This is produced
irrespective of whether --dump-tree is set. Such graphs may help in
analysing the problem, but can be very large indeed.
Various commands exist for viewing and manipulating DOT files. For example
the I<dot> command can be used to convert a DOT file to a PDF for
printing. For example:
dot -Tpdf -O Vt_unoptflat_simple_2_35_unoptflat.dot
will generate a PDF Vt_unoptflat_simple_2_35_unoptflat.dot.pdf from the DOT
file.
=item --savable
Enable including save and restore functions in the generated model.
@@ -918,7 +959,7 @@ compatibility with other simulators.
=item +systemverilogext+I<ext>
A synonym for C<+1800-2009ext+>I<ext>.
A synonym for C<+1800-2012ext+>I<ext>.
=item --top-module I<topname>
@@ -1027,10 +1068,10 @@ Disable the specified warning message.
=item -Wno-lint
Disable all lint related warning messages, and all style warnings. This is
equivalent to "-Wno-CASEINCOMPLETE -Wno-CASEOVERLAP -Wno-CASEX
-Wno-CASEWITHX -Wno-CMPCONST -Wno-ENDLABEL -Wno-IMPLICIT -Wno-LITENDIAN
-Wno-PINMISSING -Wno-SYNCASYNCNET -Wno-UNDRIVEN -Wno-UNSIGNED -Wno-UNUSED
-Wno-WIDTH" plus the list shown for Wno-style.
equivalent to "-Wno-ALWCOMBORDER -Wno-CASEINCOMPLETE -Wno-CASEOVERLAP
-Wno-CASEX -Wno-CASEWITHX -Wno-CMPCONST -Wno-ENDLABEL -Wno-IMPLICIT
-Wno-LITENDIAN -Wno-PINMISSING -Wno-SYNCASYNCNET -Wno-UNDRIVEN
-Wno-UNSIGNED -Wno-UNUSED -Wno-WIDTH" plus the list shown for Wno-style.
It is strongly recommended you cleanup your code rather than using this
option, it is only intended to be use when running test-cases of code
@@ -1059,9 +1100,10 @@ Enables the specified warning message.
Enable all lint related warning messages (note by default they are already
enabled), but do not affect style messages. This is equivalent to
"-Wwarn-CASEINCOMPLETE -Wwarn-CASEOVERLAP -Wwarn-CASEX -Wwarn-CASEWITHX
-Wwarn-CMPCONST -Wwarn-ENDLABEL -Wwarn-IMPLICIT -Wwarn-LITENDIAN
-Wwarn-PINMISSING -Wwarn-REALCVT -Wwarn-UNSIGNED -Wwarn-WIDTH".
"-Wwarn-ALWCOMBORDER -Wwarn-CASEINCOMPLETE -Wwarn-CASEOVERLAP -Wwarn-CASEX
-Wwarn-CASEWITHX -Wwarn-CMPCONST -Wwarn-ENDLABEL -Wwarn-IMPLICIT
-Wwarn-LITENDIAN -Wwarn-PINMISSING -Wwarn-REALCVT -Wwarn-UNSIGNED
-Wwarn-WIDTH".
=item -Wwarn-style
@@ -1894,13 +1936,13 @@ It also supports .name and .* interconnection.
Verilator partially supports concurrent assert and cover statements; see
the enclosed coverage tests for the syntax which is allowed.
=head2 SystemVerilog 2009 (IEEE 1800-2009) Support
=head2 SystemVerilog 2012 (IEEE 1800-2012) Support
Verilator implements a full SystemVerilog 2009 preprocessor, including
Verilator implements a full SystemVerilog 2012 preprocessor, including
function call-like preprocessor defines, default define arguments,
`__FILE__, `__LINE__ and `undefineall.
Verilator currently has some support for SystemVerilog 2009 synthesis
Verilator currently has some support for SystemVerilog synthesis
constructs. As SystemVerilog features enter common usage they are added;
please file a bug if a feature you need is missing.
@@ -2673,6 +2715,20 @@ List of all warnings:
=over 4
=item ALWCOMBORDER
Warns that an always_comb block has a variable which is set after it is
used. This may cause simulation-synthesis mismatches, as not all
commercial simulators allow this ordering.
always_comb begin
a = b;
b = 1;
end
Ignoring this warning will only suppress the lint check, it will simulate
correctly.
=item ASSIGNIN
Error that an assignment is being made to an input signal. This is almost
@@ -2840,7 +2896,8 @@ correctly.
=item DETECTARRAY
Error when Verilator tries to deal with a combinatorial loop that could not be
flattened, and which involves a structure. This typically ocurrs when
flattened, and which involves a datatype which Verilator cannot handle, such
as an unpacked struct or a large unpacked array. This typically ocurrs when
-Wno-UNOPTFLAT has been used to override an UNOPTFLAT warning (see below).
The solution is to break the loop, as described for UNOPTFLAT.
@@ -2926,7 +2983,7 @@ simulators.
=item LITENDIAN
Warns that a vector is declared with little endian bit numbering
Warns that a packed vector is declared with little endian bit numbering
(i.e. [0:7]). Big endian bit numbering is now the overwhelming standard,
and little numbering is now thus often due to simple oversight instead of
intent.
@@ -3145,6 +3202,11 @@ The UNOPTFLAT warning may also occur where outputs from a block of logic
are independent, but occur in the same always block. To fix this, use the
isolate_assignments meta comment described above.
To assist in resolving UNOPTFLAT, the option C<--report-unoptflat> can be
used, which will provide suggestions for variables that can be split up,
and a graph of all the nodes connected in the loop. See the L<Arguments>
section for more details.
Ignoring this warning will only slow simulations, it will simulate
correctly.
+1 -1
View File
@@ -6,7 +6,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[3.845 2013-02-04])
AC_INIT([Verilator],[3.847 2013-05-11])
AC_CONFIG_HEADER(src/config_build.h)
AC_CONFIG_FILES(Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h)
+4
View File
@@ -1075,6 +1075,10 @@ const char* Verilated::commandArgsPlusMatch(const char* prefixp) {
return VerilatedImp::argPlusMatch(prefixp).c_str();
}
void Verilated::internalsDump() {
VerilatedImp::internalsDump();
}
void Verilated::scopesDump() {
VerilatedImp::scopesDump();
}
+34
View File
@@ -294,6 +294,11 @@ public:
static const char* productName() { return VERILATOR_PRODUCT; }
static const char* productVersion() { return VERILATOR_VERSION; }
/// For debugging, print much of the Verilator internal state.
/// The output of this function may change in future
/// releases - contact the authors before production use.
static void internalsDump();
/// For debugging, print text list of all scope names with
/// dpiImport/Export context. This function may change in future
/// releases - contact the authors before production use.
@@ -547,6 +552,7 @@ static inline void VL_ASSIGNBIT_WO(int, int bit, WDataOutP owp, IData) {
//===================================================================
// SYSTEMC OPERATORS
// Copying verilog format to systemc integers and bit vectors.
// Get a SystemC variable
#define VL_ASSIGN_ISI(obits,vvar,svar) { (vvar) = VL_CLEAN_II((obits),(obits),(svar).read()); }
#define VL_ASSIGN_QSQ(obits,vvar,svar) { (vvar) = VL_CLEAN_QQ((obits),(obits),(svar).read()); }
@@ -564,7 +570,21 @@ static inline void VL_ASSIGNBIT_WO(int, int bit, WDataOutP owp, IData) {
owp[words-1] &= VL_MASK_I(obits); \
}
#define VL_ASSIGN_ISU(obits,vvar,svar) { (vvar) = VL_CLEAN_II((obits),(obits),(svar).read().to_uint()); }
#define VL_ASSIGN_QSU(obits,vvar,svar) { (vvar) = VL_CLEAN_QQ((obits),(obits),(svar).read().to_uint64()); }
#define VL_ASSIGN_WSB(obits,owp,svar) { \
int words = VL_WORDS_I(obits); \
sc_biguint<obits> _butemp = (svar).read(); \
for (int i=0; i < words; i++) { \
int msb = ((i+1)*VL_WORDSIZE) - 1; \
msb = (msb >= obits) ? (obits-1) : msb; \
owp[i] = _butemp.range(msb,i*VL_WORDSIZE).to_uint(); \
} \
owp[words-1] &= VL_MASK_I(obits); \
}
// Copying verilog format from systemc integers and bit vectors.
// Set a SystemC variable
#define VL_ASSIGN_SII(obits,svar,vvar) { (svar).write(vvar); }
#define VL_ASSIGN_SQQ(obits,svar,vvar) { (svar).write(vvar); }
@@ -586,6 +606,20 @@ static inline void VL_ASSIGNBIT_WO(int, int bit, WDataOutP owp, IData) {
svar.write(_bvtemp); \
}
#define VL_ASSIGN_SUI(obits,svar,rd) { (svar).write(rd); }
#define VL_ASSIGN_SUQ(obits,svar,rd) { (svar).write(rd); }
#define VL_ASSIGN_SBI(obits,svar,rd) { (svar).write(rd); }
#define VL_ASSIGN_SBQ(obits,svar,rd) { (svar).write(rd); }
#define VL_ASSIGN_SBW(obits,svar,rwp) { \
sc_biguint<obits> _butemp; \
for (int i=0; i < VL_WORDS_I(obits); i++) { \
int msb = ((i+1)*VL_WORDSIZE) - 1; \
msb = (msb >= obits) ? (obits-1) : msb; \
_butemp.range(msb,i*VL_WORDSIZE) = rwp[i]; \
} \
svar.write(_butemp); \
}
//===================================================================
// Extending sizes
+28 -2
View File
@@ -78,6 +78,18 @@ public: // But only for verilated*.cpp
m_fdps[2] = stderr;
}
~VerilatedImp() {}
static void internalsDump() {
VL_PRINTF("internalsDump:\n");
VL_PRINTF(" Argv:");
for (ArgVec::iterator it=s_s.m_argVec.begin(); it!=s_s.m_argVec.end(); ++it) {
VL_PRINTF(" %s",it->c_str());
}
VL_PRINTF("\n");
VL_PRINTF(" Version: %s %s\n", Verilated::productName(), Verilated::productVersion());
scopesDump();
exportsDump();
userDump();
}
// METHODS - arguments
static void commandArgs(int argc, const char** argv) {
@@ -129,6 +141,14 @@ private:
}
}
}
static void userDump() {
bool first = true;
for (UserMap::iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ++it) {
if (first) { VL_PRINTF(" userDump:\n"); first=false; }
VL_PRINTF(" DPI_USER_DATA scope %p key %p: %p\n",
it->first.first, it->first.second, it->second);
}
}
public: // But only for verilated*.cpp
// METHODS - scope name
@@ -150,9 +170,8 @@ public: // But only for verilated*.cpp
ScopeNameMap::iterator it=s_s.m_nameMap.find(scopep->name());
if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it);
}
static void scopesDump() {
VL_PRINTF("scopesDump:\n");
VL_PRINTF(" scopesDump:\n");
for (ScopeNameMap::iterator it=s_s.m_nameMap.begin(); it!=s_s.m_nameMap.end(); ++it) {
const VerilatedScope* scopep = it->second;
scopep->scopeDump();
@@ -194,6 +213,13 @@ public: // But only for verilated*.cpp
}
return "*UNKNOWN*";
}
static void exportsDump() {
bool first = true;
for (ExportNameMap::iterator it=s_s.m_exportMap.begin(); it!=s_s.m_exportMap.end(); ++it) {
if (first) { VL_PRINTF(" exportDump:\n"); first=false; }
VL_PRINTF(" DPI_EXPORT_NAME %05d: %s\n", it->second, it->first);
}
}
// We don't free up m_exportMap until the end, because we can't be sure
// what other models are using the assigned funcnum's.
+9 -2
View File
@@ -157,6 +157,8 @@ void VerilatedVcd::openNext (bool incFilename) {
void VerilatedVcd::makeNameMap() {
// Take signal information from each module and build m_namemapp
deleteNameMap();
m_nextCode = 1;
m_namemapp = new NameMap;
for (vluint32_t ent = 0; ent< m_callbacks.size(); ent++) {
VerilatedVcdCallInfo *cip = m_callbacks[ent];
@@ -183,15 +185,20 @@ void VerilatedVcd::makeNameMap() {
newname += hiername;
newmapp->insert(make_pair(newname,decl));
}
delete m_namemapp; m_namemapp=NULL;
deleteNameMap();
m_namemapp = newmapp;
}
}
void VerilatedVcd::deleteNameMap() {
if (m_namemapp) { delete m_namemapp; m_namemapp=NULL; }
}
VerilatedVcd::~VerilatedVcd() {
close();
if (m_wrBufp) { delete[] m_wrBufp; m_wrBufp=NULL; }
if (m_sigs_oldvalp) { delete[] m_sigs_oldvalp; m_sigs_oldvalp=NULL; }
deleteNameMap();
// Remove from list of traces
vector<VerilatedVcd*>::iterator pos = find(s_vcdVecp.begin(), s_vcdVecp.end(), this);
if (pos != s_vcdVecp.end()) { s_vcdVecp.erase(pos); }
@@ -414,7 +421,7 @@ void VerilatedVcd::dumpHeader () {
assert (m_modDepth==0);
// Reclaim storage
delete m_namemapp;
deleteNameMap();
}
void VerilatedVcd::module (string name) {
+7 -1
View File
@@ -57,7 +57,8 @@ typedef void (*VerilatedVcdCallback_t)(VerilatedVcd* vcdp, void* userthis, vluin
//=============================================================================
// VerilatedVcd
/// Create a SystemPerl VCD dump
/// Base class to create a Verilator VCD dump
/// This is an internally used class - see VerilatedVcdC for what to call from applications
class VerilatedVcd {
private:
@@ -100,6 +101,7 @@ private:
void closeErr();
void openNext();
void makeNameMap();
void deleteNameMap();
void printIndent (int levelchange);
void printStr (const char* str);
void printQuad (vluint64_t n);
@@ -400,8 +402,12 @@ public:
bool isOpen() const { return m_sptrace.isOpen(); }
// METHODS
/// Open a new VCD file
/// This includes a complete header dump each time it is called,
/// just as if this object was deleted and reconstructed.
void open (const char* filename) { m_sptrace.open(filename); }
/// Continue a VCD dump by rotating to a new file name
/// The header is only in the first file created, this allows
/// "cat" to be used to combine the header plus any number of data files.
void openNext (bool incFilename=true) { m_sptrace.openNext(incFilename); }
/// Set size in megabytes after which new file should be created
void rolloverMB(size_t rolloverMB) { m_sptrace.rolloverMB(rolloverMB); };
+3 -3
View File
@@ -839,7 +839,7 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
case VLVT_UINT8 : snprintf(outStr, outStrSz+1, "%hhu", (unsigned int)*((CData*)(vop->varDatap()))); return;
case VLVT_UINT16: snprintf(outStr, outStrSz+1, "%hu", (unsigned int)*((SData*)(vop->varDatap()))); return;
case VLVT_UINT32: snprintf(outStr, outStrSz+1, "%u", (unsigned int)*((IData*)(vop->varDatap()))); return;
case VLVT_UINT64: snprintf(outStr, outStrSz+1, "%lu", (unsigned long)*((QData*)(vop->varDatap()))); return;
case VLVT_UINT64: snprintf(outStr, outStrSz+1, "%llu", (unsigned long long)*((QData*)(vop->varDatap()))); return;
default:
strcpy(outStr, "-1");
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Unsupported format (%s) for %s, maximum limit is 64 bits",
@@ -1096,8 +1096,8 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value value_p,
}
} else if (value_p->format == vpiDecStrVal) {
char remainder[16];
unsigned long val;
int success = sscanf(value_p->value.str, "%30lu%15s", &val, remainder);
unsigned long long val;
int success = sscanf(value_p->value.str, "%30llu%15s", &val, remainder);
if (success < 1) {
_VL_VPI_ERROR(__FILE__, __LINE__, "%s: Parsing failed for '%s' as value %s for %s",
VL_FUNC, value_p->value.str, VerilatedVpiError::strFromVpiVal(value_p->format), vop->fullname());
+5 -5
View File
@@ -7,7 +7,7 @@
* This file contains the constant definitions, structure definitions,
* and routine declarations used by SystemVerilog DPI.
*
* This file is from the SystemVerilog IEEE 1800-2009 Annex I.
* This file is from the SystemVerilog IEEE 1800-2012 Annex I.
*/
#ifndef INCLUDED_SVDPI
@@ -35,18 +35,18 @@ typedef signed __int8 int8_t;
#include <sys/types.h>
#endif
/* Use to export a symbol from application */
/* Use to import a symbol into dll */
#ifndef DPI_DLLISPEC
#if defined (_MSC_VER)
#if (defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__))
#define DPI_DLLISPEC __declspec(dllimport)
#else
#define DPI_DLLISPEC
#endif
#endif
/* Use to import a symbol into application */
/* Use to export a symbol from dll */
#ifndef DPI_DLLESPEC
#if defined (_MSC_VER)
#if (defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__))
#define DPI_DLLESPEC __declspec(dllexport)
#else
#define DPI_DLLESPEC
+21 -21
View File
@@ -1,7 +1,7 @@
/*******************************************************************************
* vpi_user.h
*
* IEEE Std 1800 Programming Language Interface (PLI)
* IEEE Std 1800-2012 Programming Language Interface (PLI)
*
* This file contains the constant definitions, structure definitions, and
* routine declarations used by the SystemVerilog Verification Procedural
@@ -61,9 +61,9 @@ typedef char PLI_BYTE8;
typedef unsigned char PLI_UBYTE8;
#endif
/* Use to export a symbol */
/* Use to import a symbol */
#if WIN32
#if (defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__))
#ifndef PLI_DLLISPEC
#define PLI_DLLISPEC __declspec(dllimport)
#define VPI_USER_DEFINED_DLLISPEC 1
@@ -74,9 +74,9 @@ typedef unsigned char PLI_UBYTE8;
#endif
#endif
/* Use to import a symbol */
/* Use to export a symbol */
#if WIN32
#if (defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__))
#ifndef PLI_DLLESPEC
#define PLI_DLLESPEC __declspec(dllexport)
#define VPI_USER_DEFINED_DLLESPEC 1
@@ -438,12 +438,12 @@ typedef PLI_UINT32 *vpiHandle;
#define vpiPlusOp 2 /* unary plus */
#define vpiNotOp 3 /* unary not */
#define vpiBitNegOp 4 /* bitwise negation */
#define vpiUnaryAndOp 5 /* bitwise reduction and */
#define vpiUnaryNandOp 6 /* bitwise reduction nand */
#define vpiUnaryOrOp 7 /* bitwise reduction or */
#define vpiUnaryNorOp 8 /* bitwise reduction nor */
#define vpiUnaryXorOp 9 /* bitwise reduction xor */
#define vpiUnaryXNorOp 10 /* bitwise reduction xnor */
#define vpiUnaryAndOp 5 /* bitwise reduction AND */
#define vpiUnaryNandOp 6 /* bitwise reduction NAND */
#define vpiUnaryOrOp 7 /* bitwise reduction OR */
#define vpiUnaryNorOp 8 /* bitwise reduction NOR */
#define vpiUnaryXorOp 9 /* bitwise reduction XOR */
#define vpiUnaryXNorOp 10 /* bitwise reduction XNOR */
#define vpiSubOp 11 /* binary subtraction */
#define vpiDivOp 12 /* binary division */
#define vpiModOp 13 /* binary modulus */
@@ -459,17 +459,17 @@ typedef PLI_UINT32 *vpiHandle;
#define vpiRShiftOp 23 /* binary right shift */
#define vpiAddOp 24 /* binary addition */
#define vpiMultOp 25 /* binary multiplication */
#define vpiLogAndOp 26 /* binary logical and */
#define vpiLogOrOp 27 /* binary logical or */
#define vpiBitAndOp 28 /* binary bitwise and */
#define vpiBitOrOp 29 /* binary bitwise or */
#define vpiBitXorOp 30 /* binary bitwise xor */
#define vpiBitXNorOp 31 /* binary bitwise xnor */
#define vpiLogAndOp 26 /* binary logical AND */
#define vpiLogOrOp 27 /* binary logical OR */
#define vpiBitAndOp 28 /* binary bitwise AND */
#define vpiBitOrOp 29 /* binary bitwise OR */
#define vpiBitXorOp 30 /* binary bitwise XOR */
#define vpiBitXNorOp 31 /* binary bitwise XNOR */
#define vpiBitXnorOp vpiBitXNorOp /* added with 1364-2001 */
#define vpiConditionOp 32 /* ternary conditional */
#define vpiConcatOp 33 /* n-ary concatenation */
#define vpiMultiConcatOp 34 /* repeated concatenation */
#define vpiEventOrOp 35 /* event or */
#define vpiEventOrOp 35 /* event OR */
#define vpiNullOp 36 /* null operation */
#define vpiListOp 37 /* list of expressions */
#define vpiMinTypMaxOp 38 /* min:typ:max: delay expression */
@@ -536,7 +536,7 @@ typedef PLI_UINT32 *vpiHandle;
same subtypes as vpiNetType */
#define vpiSaveRestartID 62 /* unique ID for save/restart data */
#define vpiSaveRestartLocation 63 /* name of save/restart data file */
/* vpiValid,vpiValidTrue,vpiValidFalse are deprecated in 1800-2009 */
/* vpiValid,vpiValidTrue,vpiValidFalse were deprecated in 1800-2009 */
#define vpiValid 64 /* reentrant task/func frame or automatic
variable is valid */
#define vpiValidFalse 0
@@ -661,7 +661,7 @@ typedef struct t_vpi_arrayvalue
{
PLI_INT32 *integers; /* integer values */
PLI_INT16 *shortints; /* short integer values */
PLI_INT16 *longints; /* long integer values */
PLI_INT64 *longints; /* long integer values */
PLI_BYTE8 *rawvals; /* 2/4-state vector elements */
struct t_vpi_vecval *vectors; /* 4-state vector elements */
struct t_vpi_time *times; /* time values */
@@ -944,7 +944,7 @@ XXTERN PLI_INT32 vpi_compare_objects PROTO_PARAMS((vpiHandle object1,
vpiHandle object2));
XXTERN PLI_INT32 vpi_chk_error PROTO_PARAMS((p_vpi_error_info
error_info_p));
/* vpi_free_object() is deprecated in 1800-2009 */
/* vpi_free_object() was deprecated in 1800-2009 */
XXTERN PLI_INT32 vpi_free_object PROTO_PARAMS((vpiHandle object));
XXTERN PLI_INT32 vpi_release_handle PROTO_PARAMS((vpiHandle object));
XXTERN PLI_INT32 vpi_get_vlog_info PROTO_PARAMS((p_vpi_vlog_info
+56 -5
View File
@@ -366,10 +366,8 @@ AST.
=head1 TESTING
To write a test see the BUGS section of the Verilator primary manual, and
the documentation in:
test_regress/t/driver.pl --help
For an overview of how to write a test see the BUGS section of the
Verilator primary manual.
It is important to add tests for failures as well as success (for example to
check that an error message is correctly triggered).
@@ -378,7 +376,60 @@ Tests that fail should by convenition have the suffix C<_bad> in their name,
and include C<fails =E<gt> 1> in either their C<compile> or C<execute> step as
appropriate.
Developers will also want to configure with two extra flags:
=head2 Controlling the Test Driver
Test drivers are written in PERL. All invoke the main test driver script,
which can provide detailed help on all the features available when writing
a test driver.
test_regress/t/driver.pl --help
For convenience, a summary of the most commonly used features is provided
here. All drivers require a call to C<compile> subroutine to compile the
test. For run-time tests, this is followed by a call to the C<execute>
subroutine. Both of these functions can optionally be provided with a hash
table as argument specifying additonal options.
The test driver assumes by default that the source Verilog file name
matches the PERL driver name. So a test whose driver is C<t/t_mytest.pl>
will expect a Verilog source file C<t/t_mytest.v>. This can be changed
using the C<top_filename> subroutine, for example
top_filename("t/t_myothertest.v");
By default all tests will run with major simulators (Icarus Verilog, NC,
VCS, ModelSim) as well as Verilator, to allow results to be
compared. However if you wish a test only to be used with Verilator, you
can use the following:
$Self->{vlt} or $Self->skip("Verilator only test");
Of the many options that can be set through arguments to C<compiler> and
C<execute>, the following are particularly useful:
=over 4
=item C<verilator_flags2>
A list of flags to be passed to verilator when compiling.
=item C<fails>
Set to 1 to indicate that the compilation or execution is intended to fail.
=back
For example the following would specify that compilation requires two
defines and is expected to fail.
compile (
verilator_flags2 => ["-DSMALL_CLOCK -DGATED_COMMENT"],
fails => 1,
);
=head2 Regression Testing for Developers
Developers will also want to call ./configure with two extra flags:
=over 4
+1
View File
@@ -137,6 +137,7 @@ private:
if (nodep->castPslAssert()) ifp->branchPred(AstBranchPred::BP_UNLIKELY);
//
AstNode* newp = new AstAlways (nodep->fileline(),
VAlwaysKwd::ALWAYS,
sentreep,
bodysp);
// Install it
+26
View File
@@ -467,6 +467,30 @@ public:
//######################################################################
class VAlwaysKwd {
public:
enum en {
ALWAYS,
ALWAYS_FF,
ALWAYS_LATCH,
ALWAYS_COMB
};
enum en m_e;
inline VAlwaysKwd () : m_e(ALWAYS) {}
inline VAlwaysKwd (en _e) : m_e(_e) {}
explicit inline VAlwaysKwd (int _e) : m_e(static_cast<en>(_e)) {}
operator en () const { return m_e; }
const char* ascii() const {
static const char* names[] = {
"always","always_ff","always_latch","always_comb"};
return names[m_e]; }
};
inline bool operator== (VAlwaysKwd lhs, VAlwaysKwd rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (VAlwaysKwd lhs, VAlwaysKwd::en rhs) { return (lhs.m_e == rhs); }
inline bool operator== (VAlwaysKwd::en lhs, VAlwaysKwd rhs) { return (lhs == rhs.m_e); }
//######################################################################
class AstCaseType {
public:
enum en {
@@ -1136,6 +1160,7 @@ public:
virtual bool isPure() const { return true; } // Else a $display, etc, that must be ordered with other displays
virtual bool isBrancher() const { return false; } // Changes control flow, disable some optimizations
virtual bool isGateOptimizable() const { return true; } // Else a AstTime etc that can't be pushed out
virtual bool isGateDedupable() const { return isGateOptimizable(); } // GateDedupable is a slightly larger superset of GateOptimzable (eg, AstNodeIf)
virtual bool isSubstOptimizable() const { return true; } // Else a AstTime etc that can't be substituted out
virtual bool isPredictOptimizable() const { return true; } // Else a AstTime etc which output can't be predicted from input
virtual bool isOutputter() const { return false; } // Else creates output or exits, etc, not unconsumed
@@ -1389,6 +1414,7 @@ public:
void addIfsp(AstNode* newp) { addOp2p(newp); }
void addElsesp(AstNode* newp) { addOp3p(newp); }
virtual bool isGateOptimizable() const { return false; }
virtual bool isGateDedupable() const { return true; }
virtual int instrCount() const { return instrCountBranch(); }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(AstNode* samep) const { return true; }
+25 -8
View File
@@ -103,13 +103,21 @@ bool AstVar::isSigPublic() const {
}
bool AstVar::isScQuad() const {
return (isSc() && isQuad() && !isScBv());
return (isSc() && isQuad() && !isScBv() && !isScBigUint());
}
bool AstVar::isScBv() const {
return ((isSc() && width() >= v3Global.opt.pinsBv()) || m_attrScBv);
}
bool AstVar::isScUint() const {
return ((isSc() && v3Global.opt.pinsScUint() && width() >= 2 && width() <= 64) && !isScBv());
}
bool AstVar::isScBigUint() const {
return ((isSc() && v3Global.opt.pinsScBigUint() && width() >= 65 && width() <= 512) && !isScBv());
}
void AstVar::combineType(AstVarType type) {
// These flags get combined with the existing settings of the flags.
// We don't test varType for certain types, instead set flags since
@@ -278,7 +286,11 @@ string AstVar::dpiArgType(bool named, bool forReturn) const {
}
string AstVar::scType() const {
if (isScBv()) {
if (isScBigUint()) {
return (string("sc_biguint<")+cvtToStr(widthMin())+"> "); // Keep the space so don't get >>
} else if (isScUint()) {
return (string("sc_uint<")+cvtToStr(widthMin())+"> "); // Keep the space so don't get >>
} else if (isScBv()) {
return (string("sc_bv<")+cvtToStr(widthMin())+"> "); // Keep the space so don't get >>
} else if (widthMin() == 1) {
return "bool";
@@ -665,6 +677,11 @@ void AstNode::dump(ostream& str) {
if (name()!="") str<<" "<<AstNode::quoteName(name());
}
void AstAlways::dump(ostream& str) {
this->AstNode::dump(str);
if (keyword() != VAlwaysKwd::ALWAYS) str<<" ["<<keyword().ascii()<<"]";
}
void AstArraySel::dump(ostream& str) {
this->AstNode::dump(str);
str<<" [start:"<<start()<<"] [length:"<<length()<<"]";
@@ -695,18 +712,18 @@ void AstDisplay::dump(ostream& str) {
this->AstNode::dump(str);
//str<<" "<<displayType().ascii();
}
void AstJumpGo::dump(ostream& str) {
this->AstNode::dump(str);
str<<" -> ";
if (labelp()) { labelp()->dump(str); }
else { str<<"%Error:UNLINKED"; }
}
void AstEnumItemRef::dump(ostream& str) {
this->AstNode::dump(str);
str<<" -> ";
if (itemp()) { itemp()->dump(str); }
else { str<<"UNLINKED"; }
}
void AstJumpGo::dump(ostream& str) {
this->AstNode::dump(str);
str<<" -> ";
if (labelp()) { labelp()->dump(str); }
else { str<<"%Error:UNLINKED"; }
}
void AstPin::dump(ostream& str) {
this->AstNode::dump(str);
if (modVarp()) { str<<" -> "; modVarp()->dump(str); }
+40 -12
View File
@@ -815,6 +815,7 @@ struct AstVar : public AstNode {
// A variable (in/out/wire/reg/param) inside a module
private:
string m_name; // Name of variable
string m_origName; // Original name before dot addition
AstVarType m_varType; // Type of variable
bool m_input:1; // Input or inout
bool m_output:1; // Output or inout
@@ -858,7 +859,7 @@ private:
public:
AstVar(FileLine* fl, AstVarType type, const string& name, VFlagChildDType, AstNodeDType* dtp)
:AstNode(fl)
, m_name(name) {
, m_name(name), m_origName(name) {
init();
combineType(type);
childDTypep(dtp); // Only for parser
@@ -866,7 +867,7 @@ public:
}
AstVar(FileLine* fl, AstVarType type, const string& name, AstNodeDType* dtp)
:AstNode(fl)
, m_name(name) {
, m_name(name), m_origName(name) {
init();
combineType(type);
UASSERT(dtp,"AstVar created with no dtype");
@@ -874,21 +875,21 @@ public:
}
AstVar(FileLine* fl, AstVarType type, const string& name, VFlagLogicPacked, int wantwidth)
:AstNode(fl)
, m_name(name) {
, m_name(name), m_origName(name) {
init();
combineType(type);
dtypeSetLogicSized(wantwidth,wantwidth,AstNumeric::UNSIGNED);
}
AstVar(FileLine* fl, AstVarType type, const string& name, VFlagBitPacked, int wantwidth)
:AstNode(fl)
, m_name(name) {
, m_name(name), m_origName(name) {
init();
combineType(type);
dtypeSetLogicSized(wantwidth,wantwidth,AstNumeric::UNSIGNED);
}
AstVar(FileLine* fl, AstVarType type, const string& name, AstVar* examplep)
:AstNode(fl)
, m_name(name) {
, m_name(name), m_origName(name) {
init();
combineType(type);
if (examplep->childDTypep()) {
@@ -898,10 +899,13 @@ public:
}
ASTNODE_NODE_FUNCS(Var, VAR)
virtual void dump(ostream& str);
virtual string name() const { return m_name; } // * = Var name
virtual string name() const { return m_name; } // * = Var name
virtual bool hasDType() const { return true; }
virtual bool maybePointedTo() const { return true; }
AstVarType varType() const { return m_varType; } // * = Type of variable
string origName() const { return m_origName; } // * = Original name
void origName(const string& name) { m_origName = name; }
AstVarType varType() const { return m_varType; } // * = Type of variable
void varType(AstVarType type) { m_varType = type; }
void varType2Out() { m_tristate=0; m_input=0; m_output=1; }
void varType2In() { m_tristate=0; m_input=1; m_output=0; }
string scType() const; // Return SysC type: bool, uint32_t, uint64_t, sc_bv
@@ -975,6 +979,8 @@ public:
bool isSc() const { return m_sc; }
bool isScQuad() const;
bool isScBv() const;
bool isScUint() const;
bool isScBigUint() const;
bool isScSensitive() const { return m_scSensitive; }
bool isSigPublic() const;
bool isSigModPublic() const { return m_sigModPublic; }
@@ -1617,15 +1623,19 @@ public:
};
struct AstAlways : public AstNode {
AstAlways(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp)
: AstNode(fl) {
VAlwaysKwd m_keyword;
public:
AstAlways(FileLine* fl, VAlwaysKwd keyword, AstSenTree* sensesp, AstNode* bodysp)
: AstNode(fl), m_keyword(keyword) {
addNOp1p(sensesp); addNOp2p(bodysp);
}
ASTNODE_NODE_FUNCS(Always, ALWAYS)
//
virtual void dump(ostream& str);
AstSenTree* sensesp() const { return op1p()->castSenTree(); } // op1 = Sensitivity list
AstNode* bodysp() const { return op2p()->castNode(); } // op2 = Statements to evaluate
void addStmtp(AstNode* nodep) { addOp2p(nodep); }
VAlwaysKwd keyword() const { return m_keyword; }
// Special accessors
bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); }
};
@@ -1696,7 +1706,7 @@ struct AstAssignW : public AstNodeAssign {
AstAlways* convertToAlways() {
AstNode* lhs1p = lhsp()->unlinkFrBack();
AstNode* rhs1p = rhsp()->unlinkFrBack();
AstAlways* newp = new AstAlways (fileline(), NULL,
AstAlways* newp = new AstAlways (fileline(), VAlwaysKwd::ALWAYS, NULL,
new AstAssign (fileline(), lhs1p, rhs1p));
replaceWith(newp); // User expected to then deleteTree();
return newp;
@@ -3180,6 +3190,20 @@ struct AstCast : public AstNode {
AstNodeDType* childDTypep() const { return op2p()->castNodeDType(); }
};
struct AstCastSize : public AstNode {
// Cast to specific size; signed/twostate inherited from lower element per IEEE
AstCastSize(FileLine* fl, AstNode* lhsp, AstConst* rhsp) : AstNode(fl) {
setOp1p(lhsp); setOp2p(rhsp);
}
ASTNODE_NODE_FUNCS(CastSize, CASTSIZE)
virtual string emitVerilog() { return "((%r)'(%l))"; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual bool cleanOut() { V3ERROR_NA; return true;} virtual bool cleanLhs() {return true;}
virtual bool sizeMattersLhs() {return false;}
AstNode* lhsp() const { return op1p(); }
AstNode* rhsp() const { return op2p(); }
};
struct AstCCast : public AstNodeUniop {
// Cast to C-based data type
private:
@@ -3999,7 +4023,7 @@ struct AstPattern : public AstNodeMath {
// Parents: AstNodeAssign, AstPattern, ...
// Children: expression, AstPattern, AstPatReplicate
AstPattern(FileLine* fl, AstNode* itemsp) : AstNodeMath(fl) {
addNOp1p(itemsp);
addNOp2p(itemsp);
}
ASTNODE_NODE_FUNCS(Pattern, PATTERN)
virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially
@@ -4008,7 +4032,11 @@ struct AstPattern : public AstNodeMath {
virtual string emitSimpleOperator() { V3ERROR_NA; return "";}
virtual bool cleanOut() {V3ERROR_NA; return "";}
virtual int instrCount() const { return widthInstrs(); }
AstNode* itemsp() const { return op1p(); } // op1 = AstPatReplicate, AstPatMember, etc
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(); }
AstNode* itemsp() const { return op2p(); } // op2 = AstPatReplicate, AstPatMember, etc
};
struct AstPatMember : public AstNodeMath {
// Verilog '{a} or '{a{b}}
+7 -6
View File
@@ -87,15 +87,16 @@ private:
AstVar* varp = vscp->varp();
vscp->v3warn(IMPERFECTSCH,"Imperfect scheduling of variable: "<<vscp);
AstUnpackArrayDType* arrayp = varp->dtypeSkipRefp()->castUnpackArrayDType();
AstStructDType *structp = varp->dtypeSkipRefp()->castStructDType();
bool isArray = arrayp;
int msb = isArray ? arrayp->msb() : 0;
int lsb = isArray ? arrayp->lsb() : 0;
if (isArray && ((msb - lsb + 1) > DETECTARRAY_MAX_INDEXES)) {
bool isStruct = structp && structp->packed();
int elements = isArray ? arrayp->elementsConst() : 1;
if (isArray && (elements > DETECTARRAY_MAX_INDEXES)) {
vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect more than "<<cvtToStr(DETECTARRAY_MAX_INDEXES)
<<" array indexes (probably with UNOPTFLAT warning suppressed): "<<varp->prettyName()<<endl
<<vscp->warnMore()
<<"... Could recompile with DETECTARRAY_MAX_INDEXES increased to at least "<<cvtToStr(msb-lsb+1));
} else if (!isArray
<<"... Could recompile with DETECTARRAY_MAX_INDEXES increased to at least "<<cvtToStr(elements));
} else if (!isArray && !isStruct
&& !varp->dtypeSkipRefp()->castBasicDType()) {
if (debug()) varp->dumpTree(cout,"-DETECTARRAY-");
vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable (probably with UNOPTFLAT warning suppressed): "<<varp->prettyName());
@@ -109,7 +110,7 @@ private:
m_topModp->addStmtp(newvarp);
AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp);
m_scopetopp->addVarp(newvscp);
for (int index=lsb; index<=msb; ++index) {
for (int index=0; index<elements; ++index) {
AstChangeDet* changep
= new AstChangeDet (vscp->fileline(),
aselIfNeeded(isArray, index,
+1
View File
@@ -684,6 +684,7 @@ class GaterVisitor : public GaterBaseVisitor {
AstNode* bodyp = nodep->bodysp()->cloneTree(true);
AstAlways* alwp = new AstAlways(nodep->fileline(),
nodep->keyword(),
sensesp,
bodyp);
+27 -6
View File
@@ -79,7 +79,10 @@ public:
puts (nodep->isWide()?"W":(nodep->isQuad()?"Q":"I"));
}
void emitScIQW(AstVar* nodep) {
puts (nodep->isScBv()?"SW":(nodep->isScQuad()?"SQ":"SI"));
puts (nodep->isScBigUint() ? "SB"
: nodep->isScUint() ? "SU"
: nodep->isScBv() ? "SW"
: (nodep->isScQuad() ? "SQ" : "SI"));
}
void emitOpName(AstNode* nodep, const string& format,
AstNode* lhsp, AstNode* rhsp, AstNode* thsp);
@@ -1699,7 +1702,7 @@ void EmitCStmts::emitVarList(AstNode* firstp, EisWhich which, const string& pref
if (varp->isUsedClock() && varp->widthMin()==1) sortbytes = 0;
else if (varp->dtypeSkipRefp()->castUnpackArrayDType()) sortbytes=8;
else if (varp->basicp() && varp->basicp()->isOpaque()) sortbytes=7;
else if (varp->isScBv()) sortbytes=6;
else if (varp->isScBv() || varp->isScBigUint()) sortbytes=6;
else if (sigbytes==8) sortbytes=5;
else if (sigbytes==4) sortbytes=4;
else if (sigbytes==2) sortbytes=2;
@@ -2172,6 +2175,21 @@ class EmitCTrace : EmitCStmts {
AstVar* varp = varrefp->varp();
return varp->isSc() && varp->isScBv();
}
bool emitTraceIsScBigUint(AstTraceInc* nodep) {
AstVarRef* varrefp = nodep->valuep()->castVarRef();
if (!varrefp) return false;
AstVar* varp = varrefp->varp();
return varp->isSc() && varp->isScBigUint();
}
bool emitTraceIsScUint(AstTraceInc* nodep) {
AstVarRef* varrefp = nodep->valuep()->castVarRef();
if (!varrefp) return false;
AstVar* varp = varrefp->varp();
return varp->isSc() && varp->isScUint();
}
void emitTraceInitOne(AstTraceDecl* nodep) {
if (nodep->isDouble()) {
puts("vcdp->declDouble");
@@ -2207,7 +2225,7 @@ class EmitCTrace : EmitCStmts {
? "full":"chg");
if (nodep->isDouble()) {
puts("vcdp->"+full+"Double");
} else if (nodep->isWide() || emitTraceIsScBv(nodep)) {
} else if (nodep->isWide() || emitTraceIsScBv(nodep) || emitTraceIsScBigUint(nodep)) {
puts("vcdp->"+full+"Array");
} else if (nodep->isQuad()) {
puts("vcdp->"+full+"Quad ");
@@ -2221,7 +2239,7 @@ class EmitCTrace : EmitCStmts {
puts(",");
emitTraceValue(nodep, arrayindex);
if (!nodep->isDouble() // When float/double no longer have widths this can go
&& (nodep->declp()->left() || nodep->declp()->right() || emitTraceIsScBv(nodep))) {
&& (nodep->declp()->left() || nodep->declp()->right() || emitTraceIsScBv(nodep) || emitTraceIsScBigUint(nodep))) {
puts(","+cvtToStr(nodep->declp()->widthMin()));
}
puts(");\n");
@@ -2231,7 +2249,8 @@ class EmitCTrace : EmitCStmts {
AstVarRef* varrefp = nodep->valuep()->castVarRef();
AstVar* varp = varrefp->varp();
puts("(");
if (emitTraceIsScBv(nodep)) puts("VL_SC_BV_DATAP(");
if (emitTraceIsScBigUint(nodep)) puts("(vluint32_t*)");
else if (emitTraceIsScBv(nodep)) puts("VL_SC_BV_DATAP(");
varrefp->iterate(*this); // Put var name out
// Tracing only supports 1D arrays
if (varp->dtypeSkipRefp()->castUnpackArrayDType()) {
@@ -2240,7 +2259,9 @@ class EmitCTrace : EmitCStmts {
else puts("["+cvtToStr(arrayindex)+"]");
}
if (varp->isSc()) puts(".read()");
if (emitTraceIsScBv(nodep)) puts(")");
if (emitTraceIsScUint(nodep)) puts(nodep->isQuad() ? ".to_uint64()" : ".to_uint()");
else if (emitTraceIsScBigUint(nodep)) puts(".get_raw()");
else if (emitTraceIsScBv(nodep)) puts(")");
puts(")");
} else {
puts("(");
+1 -1
View File
@@ -102,7 +102,7 @@ class EmitCSyms : EmitCBaseVisitor {
if (rsvd != "") {
// Generally V3Name should find all of these and throw SYMRSVDWORD.
// We'll still check here because the compiler errors resulting if we miss this warning are SO nasty
nodep->v3error("Symbol matching "+rsvd+" reserved word reached emitter, should have hit SYMRSVDWORD: '"<<nodep->name()<<"'");
nodep->v3error("Symbol matching "+rsvd+" reserved word reached emitter, should have hit SYMRSVDWORD: '"<<nodep->prettyName()<<"'");
}
}
}
+4 -2
View File
@@ -57,6 +57,7 @@ public:
// Warning codes:
EC_FIRST_WARN, // Just a code so the program knows where to start warnings
//
ALWCOMBORDER, // Always_comb with unordered statements
ASSIGNDLY, // Assignment delays
ASSIGNIN, // Assigning to input
BLKANDNBLK, // Blocked and non-blocking assignments to same variable
@@ -116,7 +117,7 @@ public:
"BLKLOOPINIT", "DETECTARRAY", "MULTITOP", "TASKNSVAR",
// Warnings
" EC_FIRST_WARN",
"ASSIGNDLY", "ASSIGNIN",
"ALWCOMBORDER", "ASSIGNDLY", "ASSIGNIN",
"BLKANDNBLK", "BLKSEQ",
"CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CDCRSTLOGIC", "CMPCONST",
"COMBDLY", "DEFPARAM", "DECLFILENAME",
@@ -146,7 +147,8 @@ public:
bool mentionManual() const { return ( m_e==EC_FATALSRC || pretendError() ); }
// Warnings that are lint only
bool lintError() const { return ( m_e==CASEINCOMPLETE || m_e==CASEOVERLAP
bool lintError() const { return ( m_e==ALWCOMBORDER
|| m_e==CASEINCOMPLETE || m_e==CASEOVERLAP
|| m_e==CASEWITHX || m_e==CASEX
|| m_e==CMPCONST
|| m_e==ENDLABEL
+320 -19
View File
@@ -41,6 +41,7 @@
#include "V3Graph.h"
#include "V3Const.h"
#include "V3Stats.h"
#include "V3Hashed.h"
typedef list<AstNodeVarRef*> GateVarRefList;
@@ -55,21 +56,34 @@ public:
}
};
//######################################################################
class GateLogicVertex;
class GateVarVertex;
class GateGraphBaseVisitor {
public:
virtual AstNUser* visit(GateLogicVertex* vertexp, AstNUser* vup=NULL) =0;
virtual AstNUser* visit(GateVarVertex* vertexp, AstNUser* vup=NULL) =0;
virtual ~GateGraphBaseVisitor() {}
};
//######################################################################
// Support classes
class GateEitherVertex : public V3GraphVertex {
AstScope* m_scopep;
bool m_reducible; // True if this node should be able to be eliminated
bool m_dedupable; // True if this node should be able to be deduped
bool m_consumed; // Output goes to something meaningful
public:
GateEitherVertex(V3Graph* graphp, AstScope* scopep)
: V3GraphVertex(graphp), m_scopep(scopep), m_reducible(true), m_consumed(false) {}
: V3GraphVertex(graphp), m_scopep(scopep), m_reducible(true), m_dedupable(true), m_consumed(false) {}
virtual ~GateEitherVertex() {}
// Accessors
// ACCESSORS
virtual string dotStyle() const { return m_consumed?"":"dotted"; }
AstScope* scopep() const { return m_scopep; }
bool reducible() const { return m_reducible; }
bool dedupable() const { return m_dedupable; }
void setConsumed(const char* consumedReason) {
m_consumed = true;
//UINFO(0,"\t\tSetConsumed "<<consumedReason<<" "<<this<<endl);
@@ -79,6 +93,23 @@ public:
m_reducible = false;
//UINFO(0," NR: "<<nonReducibleReason<<" "<<name()<<endl);
}
void clearDedupable(const char* nonDedupableReason) {
m_dedupable = false;
//UINFO(0," ND: "<<nonDedupableReason<<" "<<name()<<endl);
}
void clearReducibleAndDedupable(const char* nonReducibleReason) {
clearReducible(nonReducibleReason);
clearDedupable(nonReducibleReason);
}
virtual AstNUser* accept(GateGraphBaseVisitor& v, AstNUser* vup=NULL) =0;
// Returns only the result from the LAST vertex iterated over
AstNUser* iterateInEdges(GateGraphBaseVisitor& v, AstNUser* vup=NULL) {
AstNUser* retp = NULL;
for (V3GraphEdge* edgep = inBeginp(); edgep; edgep = edgep->inNextp()) {
retp = dynamic_cast<GateEitherVertex*>(edgep->fromp())->accept(v, vup);
}
return retp;
}
};
class GateVarVertex : public GateEitherVertex {
@@ -92,7 +123,7 @@ public:
: GateEitherVertex(graphp, scopep), m_varScp(varScp), m_isTop(false)
, m_isClock(false), m_rstSyncNodep(NULL), m_rstAsyncNodep(NULL) {}
virtual ~GateVarVertex() {}
// Accessors
// ACCESSORS
AstVarScope* varScp() const { return m_varScp; }
virtual string name() const { return (cvtToStr((void*)m_varScp)+" "+varScp()->name()); }
virtual string dotColor() const { return "blue"; }
@@ -104,6 +135,16 @@ public:
void rstSyncNodep(AstNode* nodep) { m_rstSyncNodep=nodep; }
AstNode* rstAsyncNodep() const { return m_rstAsyncNodep; }
void rstAsyncNodep(AstNode* nodep) { m_rstAsyncNodep=nodep; }
// METHODS
void propagateAttrClocksFrom(GateVarVertex* fromp) {
// Propagate clock and general attribute onto this node
varScp()->varp()->propagateAttrFrom(fromp->varScp()->varp());
if (fromp->isClock()) {
varScp()->varp()->usedClock(true);
setIsClock();
}
}
AstNUser* accept(GateGraphBaseVisitor& v, AstNUser* vup=NULL) { return v.visit(this,vup); }
};
class GateLogicVertex : public GateEitherVertex {
@@ -114,12 +155,13 @@ public:
GateLogicVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep, AstActive* activep, bool slow)
: GateEitherVertex(graphp,scopep), m_nodep(nodep), m_activep(activep), m_slow(slow) {}
virtual ~GateLogicVertex() {}
// Accessors
// ACCESSORS
virtual string name() const { return (cvtToStr((void*)m_nodep)+"@"+scopep()->prettyName()); }
virtual string dotColor() const { return "yellow"; }
AstNode* nodep() const { return m_nodep; }
AstActive* activep() const { return m_activep; }
bool slow() const { return m_slow; }
AstNUser* accept(GateGraphBaseVisitor& v, AstNUser* vup=NULL) { return v.visit(this,vup); }
};
//######################################################################
@@ -134,6 +176,7 @@ private:
// STATE
bool m_buffersOnly; // Set when we only allow simple buffering, no equations (for clocks)
AstNodeVarRef* m_lhsVarRef; // VarRef on lhs of assignment (what we're replacing)
bool m_dedupe; // Set when we use isGateDedupable instead of isGateOptimizable
// METHODS
void clearSimple(const char* because) {
@@ -193,7 +236,7 @@ private:
virtual void visit(AstNode* nodep, AstNUser*) {
// *** Special iterator
if (!m_isSimple) return; // Fastpath
if (!nodep->isGateOptimizable()
if (!(m_dedupe ? nodep->isGateDedupable() : nodep->isGateOptimizable())
|| !nodep->isPure()
|| nodep->isBrancher()) {
UINFO(5, "Non optimizable type: "<<nodep<<endl);
@@ -203,11 +246,12 @@ private:
}
public:
// CONSTUCTORS
GateOkVisitor(AstNode* nodep, bool buffersOnly) {
GateOkVisitor(AstNode* nodep, bool buffersOnly, bool dedupe) {
m_isSimple = true;
m_substTreep = NULL;
m_buffersOnly = buffersOnly;
m_lhsVarRef = NULL;
m_dedupe = dedupe;
// Iterate
nodep->accept(*this);
// Check results
@@ -258,6 +302,7 @@ private:
bool m_inSlow; // Inside a slow structure
V3Double0 m_statSigs; // Statistic tracking
V3Double0 m_statRefs; // Statistic tracking
V3Double0 m_statDedupLogic; // Statistic tracking
// METHODS
void iterateNewStmt(AstNode* nodep, const char* nonReducibleReason, const char* consumeReason) {
@@ -265,9 +310,10 @@ private:
UINFO(4," STMT "<<nodep<<endl);
// m_activep is null under AstCFunc's, that's ok.
m_logicVertexp = new GateLogicVertex(&m_graph, m_scopep, nodep, m_activep, m_inSlow);
if (!m_activeReducible) nonReducibleReason="Block Unreducible";
if (nonReducibleReason) {
m_logicVertexp->clearReducible(nonReducibleReason);
m_logicVertexp->clearReducibleAndDedupable(nonReducibleReason);
} else if (!m_activeReducible) {
m_logicVertexp->clearReducible("Block Unreducible"); // Sequential logic is dedupable
}
if (consumeReason) m_logicVertexp->setConsumed(consumeReason);
if (nodep->castSenItem()) m_logicVertexp->setConsumed("senItem");
@@ -284,13 +330,13 @@ private:
varscp->user1p(vertexp);
if (varscp->varp()->isSigPublic()) {
// Public signals shouldn't be changed, pli code might be messing with them
vertexp->clearReducible("SigPublic");
vertexp->clearReducibleAndDedupable("SigPublic");
vertexp->setConsumed("SigPublic");
}
if (varscp->varp()->isIO() && varscp->scopep()->isTop()) {
// We may need to convert to/from sysc/reg sigs
vertexp->setIsTop();
vertexp->clearReducible("isTop");
vertexp->clearReducibleAndDedupable("isTop");
vertexp->setConsumed("isTop");
}
if (varscp->varp()->isUsedClock()) vertexp->setConsumed("clock");
@@ -305,6 +351,7 @@ private:
void consumedMarkRecurse(GateEitherVertex* vertexp);
void consumedMove();
void replaceAssigns();
void dedupe();
// VISITORS
virtual void visit(AstNetlist* nodep, AstNUser*) {
@@ -319,6 +366,8 @@ private:
optimizeSignals(false);
// Then propagate more complicated equations
optimizeSignals(true);
// Remove redundant logic
if (v3Global.opt.oDedupe()) dedupe();
// Warn
warnSignals();
consumedMark();
@@ -443,6 +492,7 @@ private:
public:
// CONSTUCTORS
GateVisitor(AstNode* nodep) {
AstNode::user1ClearTree();
m_logicVertexp = NULL;
m_scopep = NULL;
m_modp = NULL;
@@ -455,6 +505,7 @@ public:
virtual ~GateVisitor() {
V3Stats::addStat("Optimizations, Gate sigs deleted", m_statSigs);
V3Stats::addStat("Optimizations, Gate inputs replaced", m_statRefs);
V3Stats::addStat("Optimizations, Gate sigs deduped", m_statDedupLogic);
}
};
@@ -464,7 +515,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
if (vvertexp->inEmpty()) {
vvertexp->clearReducible("inEmpty"); // Can't deal with no sources
vvertexp->clearReducibleAndDedupable("inEmpty"); // Can't deal with no sources
if (!vvertexp->isTop() // Ok if top inputs are driverless
&& !vvertexp->varScp()->varp()->valuep()
&& !vvertexp->varScp()->varp()->isSigPublic()) {
@@ -480,7 +531,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
}
}
else if (!vvertexp->inSize1()) {
vvertexp->clearReducible("size!1"); // Can't deal with more than one src
vvertexp->clearReducibleAndDedupable("size!1"); // Can't deal with more than one src
}
// Reduce it?
if (!vvertexp->reducible()) {
@@ -493,7 +544,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
AstNode* logicp = logicVertexp->nodep();
if (logicVertexp->reducible()) {
// Can we eliminate?
GateOkVisitor okVisitor(logicp, vvertexp->isClock());
GateOkVisitor okVisitor(logicp, vvertexp->isClock(), false);
bool multiInputs = okVisitor.rhsVarRefs().size() > 1;
// Was it ok?
bool doit = okVisitor.isSimple();
@@ -548,12 +599,8 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
UINFO(9," Point-to-new vertex "<<newvarscp<<endl);
GateVarVertex* varvertexp = makeVarVertex(newvarscp);
new V3GraphEdge(&m_graph, varvertexp, consumeVertexp, 1);
newvarscp->varp()->propagateAttrFrom(vvertexp->varScp()->varp());
if (vvertexp->isClock()) {
// Propagate clock attribute onto generating node
newvarscp->varp()->usedClock(true);
varvertexp->setIsClock();
}
// Propagate clock attribute onto generating node
varvertexp->propagateAttrClocksFrom(vvertexp);
}
// Remove the edge
edgep->unlinkDelete(); edgep=NULL;
@@ -725,6 +772,8 @@ private:
// However a VARREF should point to the original as it's otherwise confusing
// to throw warnings that point to a PIN rather than where the pin us used.
if (substp->castVarRef()) substp->fileline(nodep->fileline());
// Make the substp an rvalue like nodep. This facilitate the hashing in dedupe.
if (AstNodeVarRef* varrefp = substp->castNodeVarRef()) varrefp->lvalue(false);
nodep->replaceWith(substp);
nodep->deleteTree(); nodep=NULL;
}
@@ -756,6 +805,258 @@ void GateVisitor::optimizeElimVar(AstVarScope* varscp, AstNode* substp, AstNode*
}
}
//######################################################################
// Auxiliary hash class for GateDedupeVarVisitor
class GateDedupeHash : public V3HashedUserCheck {
private:
// NODE STATE
// Ast*::user2p -> parent AstNodeAssign* for this rhsp
// Ast*::user3p -> AstNode* checked in test for duplicate
// Ast*::user5p -> AstNode* checked in test for duplicate
// AstUser2InUse m_inuser2; (Allocated for use in GateVisitor)
AstUser3InUse m_inuser3;
AstUser5InUse m_inuser5;
V3Hashed m_hashed; // Hash, contains rhs of assigns
void hash(AstNode* nodep) {
// !NULL && the object is hashable
if (nodep && !nodep->sameHash().isIllegal()) {
m_hashed.hash(nodep);
}
}
bool sameHash(AstNode* node1p, AstNode* node2p) {
return (node1p && node2p
&& !node1p->sameHash().isIllegal()
&& !node2p->sameHash().isIllegal()
&& m_hashed.sameNodes(node1p,node2p));
}
bool same(AstNUser* node1p, AstNUser* node2p) {
return node1p == node2p || sameHash((AstNode*)node1p,(AstNode*)node2p);
}
public:
bool check(AstNode* node1p,AstNode* node2p) {
return same(node1p->user3p(),node2p->user3p()) && same(node1p->user5p(),node2p->user5p())
&& node1p->user2p()->castNode()->type() == node2p->user2p()->castNode()->type()
;
}
AstNodeAssign* hashAndFindDupe(AstNodeAssign* assignp, AstNode* extra1p, AstNode* extra2p) {
AstNode *rhsp = assignp->rhsp();
rhsp->user2p(assignp);
rhsp->user3p(extra1p);
rhsp->user5p(extra2p);
hash(extra1p);
hash(extra2p);
V3Hashed::iterator inserted = m_hashed.hashAndInsert(rhsp);
V3Hashed::iterator dupit = m_hashed.findDuplicate(rhsp, this);
// Even though rhsp was just inserted, V3Hashed::findDuplicate doesn't
// return anything in the hash that has the same pointer (V3Hashed.cpp::findDuplicate)
// So dupit is either a different, duplicate rhsp, or the end of the hash.
if (dupit != m_hashed.end()) {
m_hashed.erase(inserted);
return m_hashed.iteratorNodep(dupit)->user2p()->castNode()->castNodeAssign();
}
return NULL;
}
};
//######################################################################
// Have we seen the rhs of this assign before?
class GateDedupeVarVisitor : public GateBaseVisitor {
// Given a node, it is visited to try to find the AstNodeAssign under it that can used for dedupe.
// Right now, only the following node trees are supported for dedupe.
// 1. AstNodeAssign
// 2. AstAlways -> AstNodeAssign
// (Note, the assign must also be the only node under the always)
// 3. AstAlways -> AstNodeIf -> AstNodeAssign
// (Note, the IF must be the only node under the always,
// and the assign must be the only node under the if, other than the ifcond)
// Any other ordering or node type, except for an AstComment, makes it not dedupable
private:
// STATE
GateDedupeHash m_hash; // Hash used to find dupes of rhs of assign
AstNodeAssign* m_assignp; // Assign found for dedupe
AstNode* m_ifCondp; // IF condition that assign is under
bool m_always; // Assign is under an always
bool m_dedupable; // Determined the assign to be dedupable
// VISITORS
virtual void visit(AstNodeAssign* assignp, AstNUser*) {
if (m_dedupable) {
// I think we could safely dedupe an always block with multiple non-blocking statements, but erring on side of caution here
if (!m_assignp) {
m_assignp = assignp;
} else {
m_dedupable = false;
}
}
}
virtual void visit(AstAlways* alwaysp, AstNUser*) {
if (m_dedupable) {
if (!m_always) {
m_always = true;
alwaysp->bodysp()->iterateAndNext(*this);
} else {
m_dedupable = false;
}
}
}
// Ugly support for latches of the specific form -
// always @(...)
// if (...)
// foo = ...; // or foo <= ...;
virtual void visit(AstNodeIf* ifp, AstNUser*) {
if (m_dedupable) {
if (m_always && !m_ifCondp && !ifp->elsesp()) { //we're under an always, this is the first IF, and there's no else
m_ifCondp = ifp->condp();
ifp->ifsp()->iterateAndNext(*this);
} else {
m_dedupable = false;
}
}
}
virtual void visit(AstComment*, AstNUser*) {} // NOP
//--------------------
// Default
virtual void visit(AstNode*, AstNUser*) {
m_dedupable = false;
}
public:
// CONSTUCTORS
GateDedupeVarVisitor() {}
// PUBLIC METHODS
AstNodeVarRef* findDupe(AstNode* nodep, AstVarScope* consumerVarScopep, AstActive* activep) {
m_assignp = NULL;
m_ifCondp = NULL;
m_always = false;
m_dedupable = true;
nodep->accept(*this);
if (m_dedupable && m_assignp) {
AstNode* lhsp = m_assignp->lhsp();
// Possible todo, handle more complex lhs expressions
if (AstNodeVarRef* lhsVarRefp = lhsp->castNodeVarRef()) {
if (lhsVarRefp->varScopep() != consumerVarScopep) consumerVarScopep->v3fatalSrc("Consumer doesn't match lhs of assign");
if (AstNodeAssign* dup = m_hash.hashAndFindDupe(m_assignp,activep,m_ifCondp)) {
return (AstNodeVarRef*) dup->lhsp();
}
}
}
return NULL;
}
};
//######################################################################
// Recurse through the graph, looking for duplicate expressions on the rhs of an assign
class GateDedupeGraphVisitor : public GateGraphBaseVisitor {
private:
// NODE STATE
// AstVarScope::user2p -> bool: already visited
// AstUser2InUse m_inuser2; (Allocated for use in GateVisitor)
V3Double0 m_numDeduped; // Statistic tracking
GateDedupeVarVisitor m_varVisitor; // Looks for a dupe of the logic
virtual AstNUser* visit(GateVarVertex *vvertexp, AstNUser*) {
// Check that we haven't been here before
if (vvertexp->varScp()->user2()) return NULL;
vvertexp->varScp()->user2(true);
AstNodeVarRef* dupVarRefp = (AstNodeVarRef*) vvertexp->iterateInEdges(*this, (AstNUser*) vvertexp);
if (dupVarRefp && vvertexp->inSize1()) {
V3GraphEdge* edgep = vvertexp->inBeginp();
GateLogicVertex* lvertexp = (GateLogicVertex*)edgep->fromp();
if (!vvertexp->dedupable()) vvertexp->varScp()->v3fatalSrc("GateLogicVertex* visit should have returned NULL if consumer var vertex is not dedupable.");
GateOkVisitor okVisitor(lvertexp->nodep(), false, true);
if (okVisitor.isSimple()) {
AstVarScope* dupVarScopep = dupVarRefp->varScopep();
GateVarVertex* dupVvertexp = (GateVarVertex*) (dupVarScopep->user1p());
UINFO(4,"replacing " << vvertexp << " with " << dupVvertexp << endl);
m_numDeduped++;
// Replace all of this varvertex's consumers with dupVarRefp
for (V3GraphEdge* outedgep = vvertexp->outBeginp();outedgep;) {
GateLogicVertex* consumeVertexp = dynamic_cast<GateLogicVertex*>(outedgep->top());
AstNode* consumerp = consumeVertexp->nodep();
GateElimVisitor elimVisitor(consumerp,vvertexp->varScp(),dupVarRefp);
outedgep = outedgep->relinkFromp(dupVvertexp);
}
// Propogate attributes
dupVvertexp->propagateAttrClocksFrom(vvertexp);
// Remove inputs links
while (V3GraphEdge* inedgep = vvertexp->inBeginp()) {
inedgep->unlinkDelete(); inedgep=NULL;
}
// replaceAssigns() does the deleteTree on lvertexNodep in a later step
AstNode* lvertexNodep = lvertexp->nodep();
lvertexNodep->unlinkFrBack();
vvertexp->varScp()->valuep(lvertexNodep);
lvertexNodep = NULL;
vvertexp->user(true);
lvertexp->user(true);
}
}
return NULL;
}
// Returns a varref that has the same logic input
virtual AstNUser* visit(GateLogicVertex* lvertexp, AstNUser* vup) {
lvertexp->iterateInEdges(*this);
GateVarVertex* consumerVvertexpp = (GateVarVertex*) vup;
if (lvertexp->dedupable() && consumerVvertexpp->dedupable()) {
AstNode* nodep = lvertexp->nodep();
AstVarScope* consumerVarScopep = consumerVvertexpp->varScp();
// TODO: Doing a simple pointer comparison of activep won't work
// optimally for statements under generated clocks. Statements under
// different generated clocks will never compare as equal, even if the
// generated clocks are deduped into one clock.
AstActive* activep = lvertexp->activep();
return (AstNUser*) m_varVisitor.findDupe(nodep, consumerVarScopep, activep);
}
return NULL;
}
public:
GateDedupeGraphVisitor() {}
void dedupeTree(GateVarVertex* vvertexp) {
vvertexp->accept(*this);
}
V3Double0 numDeduped() { return m_numDeduped; }
};
//----------------------------------------------------------------------
void GateVisitor::dedupe() {
AstNode::user2ClearTree();
GateDedupeGraphVisitor deduper;
// Traverse starting from each of the clocks
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
if (vvertexp->isClock()) {
deduper.dedupeTree(vvertexp);
}
}
}
// Traverse starting from each of the outputs
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
if (vvertexp->isTop() && vvertexp->varScp()->varp()->isOutput()) {
deduper.dedupeTree(vvertexp);
}
}
}
m_statDedupLogic += deduper.numDeduped();
}
//######################################################################
// Convert VARSCOPE(ASSIGN(default, VARREF)) to just VARSCOPE(default)
+23 -5
View File
@@ -39,9 +39,14 @@ int V3Graph::debug() { return max(V3Error::debugDefault(), s_debug); }
//######################################################################
// Vertices
V3GraphVertex::V3GraphVertex(V3Graph* graphp, const V3GraphVertex& old)
: m_fanout(old.m_fanout), m_color(old.m_color), m_rank(old.m_rank) {
m_userp = NULL;
verticesPushBack(graphp);
}
V3GraphVertex::V3GraphVertex(V3Graph* graphp)
: m_fanout(0), m_color(0), m_rank(0)
{
: m_fanout(0), m_color(0), m_rank(0) {
m_userp = NULL;
verticesPushBack(graphp);
}
@@ -125,9 +130,9 @@ ostream& operator<<(ostream& os, V3GraphVertex* vertexp) {
//######################################################################
// Edges
V3GraphEdge::V3GraphEdge(V3Graph* graphp,
V3GraphVertex* fromp, V3GraphVertex* top, int weight,
bool cutable) {
void V3GraphEdge::init(V3Graph* graphp,
V3GraphVertex* fromp, V3GraphVertex* top, int weight,
bool cutable) {
UASSERT(fromp, "Null from pointer\n");
UASSERT(top, "Null to pointer\n");
m_fromp = fromp;
@@ -140,6 +145,14 @@ V3GraphEdge::V3GraphEdge(V3Graph* graphp,
inPushBack();
}
V3GraphEdge* V3GraphEdge::relinkFromp(V3GraphVertex* newFromp) {
V3GraphEdge *oldNxt = outNextp();
m_outs.unlink(m_fromp->m_outs, this);
m_fromp = newFromp;
outPushBack();
return oldNxt;
}
void V3GraphEdge::unlinkDelete() {
// Unlink from side
m_outs.unlink(m_fromp->m_outs, this);
@@ -267,6 +280,11 @@ void V3Graph::dumpDotFilePrefixed(const string& nameComment, bool colorAsSubgrap
}
}
//! Variant of dumpDotFilePrefixed without --dump option check
void V3Graph::dumpDotFilePrefixedAlways(const string& nameComment, bool colorAsSubgraph) {
dumpDotFile(v3Global.debugFilename(nameComment)+".dot", colorAsSubgraph);
}
void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) {
// This generates a file used by graphviz, http://www.graphviz.org
// "hardcoded" parameters:
+29 -7
View File
@@ -119,13 +119,17 @@ public:
/// Remove any redundant edges, weights become SUM of any other weight
void removeRedundantEdgesSum(V3EdgeFuncP edgeFuncp);
/// Call loopsVertexCb on any loops starting where specified
/// Call loopsVertexCb on any one loop starting where specified
void reportLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp);
/// Build a subgraph of all loops starting where specified
void subtreeLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp, V3Graph* loopGraphp);
/// Debugging
void dump(ostream& os=cout);
void dumpDotFile(const string& filename, bool colorAsSubgraph);
void dumpDotFilePrefixed(const string& nameComment, bool colorAsSubgraph=false);
void dumpDotFilePrefixedAlways(const string& nameComment, bool colorAsSubgraph=false);
void userClearVertices();
void userClearEdges();
static void test();
@@ -159,12 +163,18 @@ protected:
void rank(uint32_t rank) { m_rank = rank; }
void inUnlink() { m_ins.reset(); } // Low level; normally unlinkDelete is what you want
void outUnlink() { m_outs.reset(); } // Low level; normally unlinkDelete is what you want
protected:
// CONSTRUCTORS
V3GraphVertex(V3Graph* graphp, const V3GraphVertex& old);
public:
// CONSTRUCTION
V3GraphVertex(V3Graph* graphp);
//! Clone copy constructor. Doesn't copy edges or user/userp.
virtual V3GraphVertex* clone(V3Graph* graphp) const {
return new V3GraphVertex(graphp, *this); }
virtual ~V3GraphVertex() {}
void unlinkEdges(V3Graph* graphp);
void unlinkDelete(V3Graph* graphp);
// ACCESSORS
virtual string name() const { return ""; }
virtual string dotColor() const { return "black"; }
@@ -207,6 +217,9 @@ ostream& operator<<(ostream& os, V3GraphVertex* vertexp);
class V3GraphEdge {
// Wires/variables aren't edges. Edges have only a single to/from vertex
public:
// ENUMS
enum Cuttable { NOT_CUTABLE = false, CUTABLE = true }; // For passing to V3GraphEdge
protected:
friend class V3Graph; friend class V3GraphVertex;
friend class GraphAcyc; friend class GraphAcycEdge;
@@ -222,15 +235,23 @@ protected:
uint32_t m_user; // Marker for some algorithms
};
// METHODS
void init(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight, bool cutable=false);
void cut() { m_weight = 0; } // 0 weight is same as disconnected
void outPushBack();
void inPushBack();
// CONSTRUCTORS
protected:
V3GraphEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, const V3GraphEdge& old) {
init(graphp, fromp, top, old.m_weight, old.m_cutable);
}
public:
// ENUMS
enum Cuttable { NOT_CUTABLE = false, CUTABLE = true }; // For passing to V3GraphEdge
// CONSTRUCTION
// Add DAG from one node to the specified node
V3GraphEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight, bool cutable=false);
//! Add DAG from one node to the specified node
V3GraphEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight, bool cutable=false) {
init(graphp, fromp, top, weight, cutable);
}
//! Clone copy constructor. Doesn't copy existing vertices or user/userp.
virtual V3GraphEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const {
return new V3GraphEdge(graphp, fromp, top, *this); }
virtual ~V3GraphEdge() {}
// METHODS
virtual string name() const { return m_fromp->name()+"->"+m_top->name(); }
@@ -242,6 +263,7 @@ public:
return top()->sortCmp(rhsp->top());
}
void unlinkDelete();
V3GraphEdge* relinkFromp(V3GraphVertex* newFromp);
// ACCESSORS
int weight() const { return m_weight; }
void weight(int weight) { m_weight=weight; }
+55 -1
View File
@@ -376,6 +376,58 @@ void V3Graph::reportLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp) {
GraphAlgRLoops (this, edgeFuncp, vertexp);
}
//######################################################################
//######################################################################
// Algorithms - subtrees
class GraphAlgSubtrees : GraphAlg {
private:
V3Graph* m_loopGraphp;
//! Iterate through all connected nodes of a graph with a loop or loops.
V3GraphVertex* vertexIterateAll(V3GraphVertex* vertexp) {
if (V3GraphVertex* newVertexp = (V3GraphVertex*)vertexp->userp()) {
return newVertexp;
} else {
newVertexp = vertexp->clone(m_loopGraphp);
vertexp->userp(newVertexp);
for (V3GraphEdge* edgep = vertexp->outBeginp();
edgep; edgep=edgep->outNextp()) {
if (followEdge(edgep)) {
V3GraphEdge* newEdgep = (V3GraphEdge*)edgep->userp();
if (!newEdgep) {
V3GraphVertex* newTop = vertexIterateAll(edgep->top());
newEdgep = edgep->clone(m_loopGraphp, newVertexp,
newTop);
edgep->userp(newEdgep);
}
}
}
return newVertexp;
}
}
public:
GraphAlgSubtrees(V3Graph* graphp, V3Graph* loopGraphp,
V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp)
: GraphAlg(graphp, edgeFuncp), m_loopGraphp (loopGraphp) {
// Vertex::m_userp - New vertex if we have seen this vertex already
// Edge::m_userp - New edge if we have seen this edge already
m_graphp->userClearVertices();
m_graphp->userClearEdges();
(void) vertexIterateAll(vertexp);
}
~GraphAlgSubtrees() {}
};
//! Report the entire connected graph with a loop or loops
void V3Graph::subtreeLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp,
V3Graph* loopGraphp) {
GraphAlgSubtrees (this, loopGraphp, edgeFuncp, vertexp);
}
//######################################################################
//######################################################################
// Algorithms - make non cutable
@@ -465,7 +517,9 @@ void V3Graph::order() {
}
}
// Sort list of vertices by rank, then fanout
// Sort list of vertices by rank, then fanout. Fanout is a bit of a
// misnomer. It is the sum of all the fanouts of nodes reached from a node
// *plus* the count of edges in to that node.
sortVertices();
// Sort edges by rank then fanout of node they point to
sortEdges();
+19 -2
View File
@@ -105,12 +105,16 @@ public:
//######################################################################
// Hashed class functions
void V3Hashed::hashAndInsert(AstNode* nodep) {
V3Hashed::iterator V3Hashed::hashAndInsert(AstNode* nodep) {
hash(nodep);
return m_hashMmap.insert(make_pair(nodeHash(nodep), nodep));
}
void V3Hashed::hash(AstNode* nodep) {
UINFO(8," hashI "<<nodep<<endl);
if (!nodep->user4p()) {
HashedVisitor visitor (nodep);
}
m_hashMmap.insert(make_pair(nodeHash(nodep), nodep));
}
bool V3Hashed::sameNodes(AstNode* node1p, AstNode* node2p) {
@@ -189,3 +193,16 @@ V3Hashed::iterator V3Hashed::findDuplicate(AstNode* nodep) {
return end();
}
V3Hashed::iterator V3Hashed::findDuplicate(AstNode* nodep, V3HashedUserCheck* checkp) {
UINFO(8," findD "<<nodep<<endl);
if (!nodep->user4p()) nodep->v3fatalSrc("Called findDuplicate on non-hashed node");
pair <HashMmap::iterator,HashMmap::iterator> eqrange = mmap().equal_range(nodeHash(nodep));
for (HashMmap::iterator eqit = eqrange.first; eqit != eqrange.second; ++eqit) {
AstNode* node2p = eqit->second;
if (nodep != node2p && checkp->check(nodep,node2p) && sameNodes(nodep, node2p)) {
return eqit;
}
}
return end();
}
+10 -1
View File
@@ -45,6 +45,13 @@ public:
//============================================================================
struct V3HashedUserCheck {
// Functor for V3Hashed::findDuplicate
virtual bool check(AstNode*,AstNode*) =0;
V3HashedUserCheck() {}
virtual ~V3HashedUserCheck() {}
};
class V3Hashed : public VHashedBase {
// NODE STATE
// AstNode::user4() -> V3Hash. Hash value of this node (hash of 0 is illegal)
@@ -70,10 +77,12 @@ public:
// METHODS
void clear() { m_hashMmap.clear(); AstNode::user4ClearTree(); }
void hashAndInsert(AstNode* nodep); // Hash the node, and insert into map
iterator hashAndInsert(AstNode* nodep); // Hash the node, and insert into map. Return iterator to inserted
void hash(AstNode* nodep); // Only hash the node
bool sameNodes(AstNode* node1p, AstNode* node2p); // After hashing, and tell if identical
void erase(iterator it); // Remove node from structures
iterator findDuplicate(AstNode* nodep); // Return duplicate in hash, if any
iterator findDuplicate(AstNode* nodep, V3HashedUserCheck* checkp); // Extra user checks for sameness
AstNode* iteratorNodep(iterator it) { return it->second; }
void dumpFile(const string& filename, bool tree);
void dumpFilePrefixed(const string& nameComment, bool tree=false);
+6 -5
View File
@@ -266,10 +266,11 @@ AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstNodeModu
// Done. Constant.
} else {
// Make a new temp wire
//if (1||debug()>=9) { pinp->dumpTree(cout,"in_pin:"); }
//if (1||debug()>=9) { pinp->dumpTree(cout,"-in_pin:"); }
AstNode* pinexprp = pinp->exprp()->unlinkFrBack();
string newvarname = ((pinVarp->isOutput() ? "__Vcellout__" : "__Vcellinp__")
+cellp->name()+"__"+pinp->name());
string newvarname = ((string)(pinVarp->isOutput() ? "__Vcellout" : "__Vcellinp")
+(forTristate?"t":"") // Prevent name conflict if both tri & non-tri add signals
+"__"+cellp->name()+"__"+pinp->name());
AstVar* newvarp = new AstVar (pinVarp->fileline(), AstVarType::MODULETEMP, newvarname, pinVarp);
// Important to add statement next to cell, in case there is a generate with same named cell
cellp->addNextHere(newvarp);
@@ -298,8 +299,8 @@ AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstNodeModu
pinp->exprp(new AstVarRef (pinexprp->fileline(), newvarp, false));
}
if (assignp) cellp->addNextHere(assignp);
//if (1||debug()) { pinp->dumpTree(cout," out:"); }
//if (1||debug()) { assignp->dumpTree(cout," aout:"); }
//if (debug()) { pinp->dumpTree(cout,"- out:"); }
//if (debug()) { assignp->dumpTree(cout,"- aout:"); }
}
return assignp;
}
+5 -3
View File
@@ -41,6 +41,7 @@ public:
L1364_2005,
L1800_2005,
L1800_2009,
L1800_2012,
// ***Add new elements below also***
_ENUM_END
};
@@ -52,12 +53,13 @@ public:
"1364-2001",
"1364-2005",
"1800-2005",
"1800-2009"
"1800-2009",
"1800-2012"
};
return names[m_e];
};
static V3LangCode mostRecent() { return V3LangCode(L1800_2009); }
bool systemVerilog() const { return m_e == L1800_2005 || m_e == L1800_2009; }
static V3LangCode mostRecent() { return V3LangCode(L1800_2012); }
bool systemVerilog() const { return m_e == L1800_2005 || m_e == L1800_2009 || m_e == L1800_2012; }
bool legal() const { return m_e != L_ERROR; }
//
enum en m_e;
+6 -4
View File
@@ -75,7 +75,7 @@ public:
void LinkCellsGraph::loopsMessageCb(V3GraphVertex* vertexp) {
if (LinkCellsVertex* vvertexp = dynamic_cast<LinkCellsVertex*>(vertexp)) {
vvertexp->modp()->v3error("Recursive module (module instantiates itself): "
<<vvertexp->modp()->name());
<<vvertexp->modp()->prettyName());
V3Error::abortIfErrors();
} else { // Everything should match above, but...
v3fatalSrc("Recursive instantiations");
@@ -128,15 +128,17 @@ private:
// Read-subfile
// If file not found, make AstNotFoundModule, rather than error out.
// We'll throw the error when we know the module will really be needed.
string prettyName = AstNode::prettyName(modName);
V3Parse parser (v3Global.rootp(), m_filterp, m_parseSymp);
parser.parseFile(nodep->fileline(), modName, false, "");
parser.parseFile(nodep->fileline(), prettyName, false, "");
V3Error::abortIfErrors();
// We've read new modules, grab new pointers to their names
readModNames();
// Check again
modp = m_mods.rootp()->findIdFallback(modName)->nodep()->castNodeModule();
if (!modp) {
nodep->v3error("Can't resolve module reference: "<<modName);
// This shouldn't throw a message as parseFile will create a AstNotFoundModule for us
nodep->v3error("Can't resolve module reference: "<<prettyName);
}
}
return modp;
@@ -188,7 +190,7 @@ private:
<<"' does not match "<<nodep->typeName()<<" name: "<<nodep->prettyName());
}
}
bool topMatch = (v3Global.opt.topModule()==nodep->name());
bool topMatch = (v3Global.opt.topModule()==nodep->prettyName());
if (topMatch) {
m_topVertexp = vertex(nodep);
UINFO(2,"Link --top-module: "<<nodep<<endl);
+11 -5
View File
@@ -698,7 +698,7 @@ private:
&& (!m_ftaskp || m_ftaskp != foundp->nodep()) // Not the function's variable hiding function
&& !nodep->fileline()->warnIsOff(V3ErrorCode::VARHIDDEN)
&& !foundp->nodep()->fileline()->warnIsOff(V3ErrorCode::VARHIDDEN)) {
nodep->v3warn(VARHIDDEN,"Declaration of signal hides declaration in upper scope: "<<nodep->name()<<endl
nodep->v3warn(VARHIDDEN,"Declaration of signal hides declaration in upper scope: "<<nodep->prettyName()<<endl
<<foundp->nodep()->warnMore()<<"... Location of original declaration");
}
ins = true;
@@ -744,7 +744,7 @@ private:
// User can disable the message at either point
if (!nodep->fileline()->warnIsOff(V3ErrorCode::VARHIDDEN)
&& !foundp->nodep()->fileline()->warnIsOff(V3ErrorCode::VARHIDDEN)) {
nodep->v3warn(VARHIDDEN,"Declaration of enum value hides declaration in upper scope: "<<nodep->name()<<endl
nodep->v3warn(VARHIDDEN,"Declaration of enum value hides declaration in upper scope: "<<nodep->prettyName()<<endl
<<foundp->nodep()->warnMore()<<"... Location of original declaration");
}
ins = true;
@@ -858,7 +858,7 @@ private:
}
virtual void visit(AstDefParam* nodep, AstNUser*) {
nodep->iterateChildren(*this);
nodep->v3warn(DEFPARAM,"Suggest replace defparam with Verilog 2001 #(."<<nodep->name()<<"(...etc...))");
nodep->v3warn(DEFPARAM,"Suggest replace defparam with Verilog 2001 #(."<<nodep->prettyName()<<"(...etc...))");
VSymEnt* foundp = m_statep->getNodeSym(nodep)->findIdFallback(nodep->path());
AstCell* cellp = foundp->nodep()->castCell();
if (!cellp) {
@@ -1114,10 +1114,14 @@ private:
}
virtual void visit(AstScope* nodep, AstNUser*) {
UINFO(8," "<<nodep<<endl);
VSymEnt* oldModSymp = m_modSymp;
VSymEnt* oldCurSymp = m_curSymp;
checkNoDot(nodep);
m_ds.m_dotSymp = m_curSymp = m_statep->getScopeSym(nodep);
m_ds.m_dotSymp = m_curSymp = m_modSymp = m_statep->getScopeSym(nodep);
nodep->iterateChildren(*this);
m_ds.m_dotSymp = m_curSymp = NULL;
m_ds.m_dotSymp = m_curSymp = m_modSymp = NULL;
m_modSymp = oldModSymp;
m_curSymp = oldCurSymp;
}
virtual void visit(AstCellInline* nodep, AstNUser*) {
checkNoDot(nodep);
@@ -1320,6 +1324,7 @@ private:
newp = new AstVarRef(nodep->fileline(), nodep->name(), false); // lvalue'ness computed later
newp->varp(varp);
newp->packagep(foundp->packagep());
UINFO(9," new "<<newp<<endl);
}
nodep->replaceWith(newp); pushDeletep(nodep); nodep = NULL;
m_ds.m_dotPos = DP_MEMBER;
@@ -1442,6 +1447,7 @@ private:
AstVarRef* newvscp = new AstVarRef(nodep->fileline(), vscp, nodep->lvalue());
nodep->replaceWith(newvscp);
nodep->deleteTree(); nodep=NULL;
UINFO(9," new "<<newvscp<<endl); // Also prints taskp
}
}
}
+1 -1
View File
@@ -227,7 +227,7 @@ private:
}
}
//if (debug()>=9) { UINFO(0,"\n"); beginp->dumpTree(cout," labeli: "); }
if (!beginp) { nodep->v3error("disable isn't underneath a begin with name: "<<nodep->name()); }
if (!beginp) { nodep->v3error("disable isn't underneath a begin with name: "<<nodep->prettyName()); }
else {
// Jump to the end of the named begin
AstJumpLabel* labelp = findAddLabel(beginp, false);
+1 -1
View File
@@ -66,7 +66,7 @@ private:
} else {
string rsvd = m_words.isKeyword(nodep->name());
if (rsvd != "") {
nodep->v3warn(SYMRSVDWORD,"Symbol matches "+rsvd+": '"<<nodep->name()<<"'");
nodep->v3warn(SYMRSVDWORD,"Symbol matches "+rsvd+": '"<<nodep->prettyName()<<"'");
string newname = (string)"__SYM__"+nodep->name();
nodep->name(newname);
}
+9 -2
View File
@@ -673,14 +673,15 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
else if ( !strncmp (sw, "+incdir+", 8)) {
addIncDirUser (parseFileArg(optdir, string (sw+strlen("+incdir+"))));
}
else if (parseLangExt(sw, "+systemverilogext+", V3LangCode::L1800_2009)
else if (parseLangExt(sw, "+systemverilogext+", V3LangCode::L1800_2012)
|| parseLangExt(sw, "+verilog1995ext+", V3LangCode::L1364_1995)
|| parseLangExt(sw, "+verilog2001ext+", V3LangCode::L1364_2001)
|| parseLangExt(sw, "+1364-1995ext+", V3LangCode::L1364_1995)
|| parseLangExt(sw, "+1364-2001ext+", V3LangCode::L1364_2001)
|| parseLangExt(sw, "+1364-2005ext+", V3LangCode::L1364_2005)
|| parseLangExt(sw, "+1800-2005ext+", V3LangCode::L1800_2005)
|| parseLangExt(sw, "+1800-2009ext+", V3LangCode::L1800_2009)) {
|| parseLangExt(sw, "+1800-2009ext+", V3LangCode::L1800_2009)
|| parseLangExt(sw, "+1800-2012ext+", V3LangCode::L1800_2012)) {
// Nothing to do here - all done in the test
}
@@ -736,11 +737,14 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
else if ( onoff (sw, "-lint-only", flag/*ref*/) ) { m_lintOnly = flag; }
else if ( !strcmp (sw, "-no-pins64") ) { m_pinsBv = 33; }
else if ( !strcmp (sw, "-pins64") ) { m_pinsBv = 65; }
else if ( onoff (sw, "-pins-sc-uint", flag/*ref*/) ){ m_pinsScUint = flag; if (!m_pinsScBigUint) m_pinsBv = 65; }
else if ( onoff (sw, "-pins-sc-biguint", flag/*ref*/) ){ m_pinsScBigUint = flag; m_pinsBv = 513; }
else if ( onoff (sw, "-pins-uint8", flag/*ref*/) ){ m_pinsUint8 = flag; }
else if ( !strcmp (sw, "-private") ) { m_public = false; }
else if ( onoff (sw, "-profile-cfuncs", flag/*ref*/) ) { m_profileCFuncs = flag; }
else if ( onoff (sw, "-psl", flag/*ref*/) ) { m_psl = flag; }
else if ( onoff (sw, "-public", flag/*ref*/) ) { m_public = flag; }
else if ( onoff (sw, "-report-unoptflat", flag/*ref*/) ) { m_reportUnoptflat = flag; }
else if ( onoff (sw, "-savable", flag/*ref*/) ) { m_savable = flag; }
else if ( !strcmp (sw, "-sc") ) { m_outFormatOk = true; m_systemC = true; m_systemPerl = false; }
else if ( onoff (sw, "-skip-identical", flag/*ref*/) ) { m_skipIdentical = flag; }
@@ -765,6 +769,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
case 'a': m_oTable = flag; break;
case 'b': m_oCombine = flag; break;
case 'c': m_oConst = flag; break;
case 'd': m_oDedupe = flag; break;
case 'e': m_oCase = flag; break;
case 'f': m_oFlopGater = flag; break;
case 'g': m_oGate = flag; break;
@@ -1212,6 +1217,7 @@ V3Options::V3Options() {
m_traceDups = false;
m_traceUnderscore = false;
m_underlineZero = false;
m_reportUnoptflat = false;
m_xInitialEdge = false;
m_xmlOnly = false;
@@ -1301,6 +1307,7 @@ void V3Options::optimize(int level) {
m_oSubst = flag;
m_oSubstConst = flag;
m_oTable = flag;
m_oDedupe = level >= 3;
// And set specific optimization levels
if (level >= 3) {
m_inlineMult = -1; // Maximum inlining
+8
View File
@@ -76,6 +76,8 @@ class V3Options {
bool m_lintOnly; // main switch: --lint-only
bool m_outFormatOk; // main switch: --cc, --sc or --sp was specified
bool m_warnFatal; // main switch: --warnFatal
bool m_pinsScUint; // main switch: --pins-sc-uint
bool m_pinsScBigUint;// main switch: --pins-sc-biguint
bool m_pinsUint8; // main switch: --pins-uint8
bool m_profileCFuncs;// main switch: --profile-cfuncs
bool m_psl; // main switch: --psl
@@ -89,6 +91,7 @@ class V3Options {
bool m_traceDups; // main switch: --trace-dups
bool m_traceUnderscore;// main switch: --trace-underscore
bool m_underlineZero;// main switch: --underline-zero; undocumented old Verilator 2
bool m_reportUnoptflat; // main switch: --report-unoptflat
bool m_xInitialEdge; // main switch: --x-initial-edge
bool m_xmlOnly; // main switch: --xml-netlist
@@ -131,6 +134,7 @@ class V3Options {
bool m_oCase; // main switch: -Oe: case tree conversion
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_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
@@ -213,6 +217,8 @@ class V3Options {
bool outFormatOk() const { return m_outFormatOk; }
bool keepTempFiles() const { return (V3Error::debugDefault()!=0); }
bool warnFatal() const { return m_warnFatal; }
bool pinsScUint() const { return m_pinsScUint; }
bool pinsScBigUint() const { return m_pinsScBigUint; }
bool pinsUint8() const { return m_pinsUint8; }
bool profileCFuncs() const { return m_profileCFuncs; }
bool psl() const { return m_psl; }
@@ -221,6 +227,7 @@ class V3Options {
bool lintOnly() const { return m_lintOnly; }
bool ignc() const { return m_ignc; }
bool inhibitSim() const { return m_inhibitSim; }
bool reportUnoptflat() const { return m_reportUnoptflat; }
bool xInitialEdge() const { return m_xInitialEdge; }
bool xmlOnly() const { return m_xmlOnly; }
@@ -266,6 +273,7 @@ class V3Options {
bool oCase() const { return m_oCase; }
bool oCombine() const { return m_oCombine; }
bool oConst() const { return m_oConst; }
bool oDedupe() const { return m_oDedupe; }
bool oExpand() const { return m_oExpand; }
bool oFlopGater() const { return m_oFlopGater; }
bool oGate() const { return m_oGate; }
+154 -13
View File
@@ -232,6 +232,26 @@ public:
~OrderUser() {}
};
//######################################################################
// Comparator classes
//! Comparator for width of associated variable
struct OrderVarWidthCmp {
bool operator() (OrderVarStdVertex* vsv1p, OrderVarStdVertex* vsv2p) {
return vsv1p->varScp()->varp()->width()
> vsv2p->varScp()->varp()->width();
}
};
//! Comparator for fanout of vertex
struct OrderVarFanoutCmp {
bool operator() (OrderVarStdVertex* vsv1p, OrderVarStdVertex* vsv2p) {
return vsv1p->fanout() > vsv2p->fanout();
}
};
//######################################################################
// Order class functions
@@ -285,6 +305,7 @@ private:
protected:
friend class OrderMoveDomScope;
V3List<OrderMoveDomScope*> m_pomReadyDomScope; // List of ready domain/scope pairs, by loopId
vector<OrderVarStdVertex*> m_unoptflatVars; // Vector of variables in UNOPTFLAT loop
private:
// STATS
@@ -354,8 +375,10 @@ private:
void processBrokeLoop();
#endif
void processCircular();
typedef deque<OrderEitherVertex*> VertexVec;
void processInputs();
void processInputsIterate(OrderEitherVertex* vertexp);
void processInputsInIterate(OrderEitherVertex* vertexp, VertexVec& todoVec);
void processInputsOutIterate(OrderEitherVertex* vertexp, VertexVec& todoVec);
void processSensitive();
void processDomains();
void processDomainsIterate(OrderEitherVertex* vertexp);
@@ -418,10 +441,99 @@ private:
if (tempWeight) edgep->weight(1); // Else the below loop detect can't see the loop
m_graph.reportLoops(&OrderEdge::followComboConnected, vertexp); // calls OrderGraph::loopsVertexCb
if (tempWeight) edgep->weight(0);
if (v3Global.opt.reportUnoptflat()) {
// Report candidate variables for splitting
reportLoopVars(vertexp);
// Do a subgraph for the UNOPTFLAT loop
OrderGraph loopGraph;
m_graph.subtreeLoops(&OrderEdge::followComboConnected,
vertexp, &loopGraph);
loopGraph.dumpDotFilePrefixedAlways("unoptflat");
}
}
}
}
//! Find all variables in an UNOPTFLAT loop
//!
//! Ignore vars that are 1-bit wide and don't worry about generated
//! variables (PRE and POST vars, __Vdly__, __Vcellin__ and __VCellout).
//! What remains are candidates for splitting to break loops.
//!
//! node->user3 is used to mark if we have done a particular variable.
//! vertex->user is used to mark if we have seen this vertex before.
//!
//! @todo We could be cleverer in the future and consider just
//! the width that is generated/consumed.
void reportLoopVars(OrderVarVertex* vertexp) {
m_graph.userClearVertices();
AstNode::user3ClearTree();
m_unoptflatVars.clear();
reportLoopVarsIterate (vertexp, vertexp->color());
AstNode::user3ClearTree();
m_graph.userClearVertices();
// May be very large vector, so only report the "most important"
// elements. Up to 10 of the widest
cerr<<V3Error::msgPrefix()
<<" Widest candidate vars to split:"<<endl;
sort (m_unoptflatVars.begin(), m_unoptflatVars.end(), OrderVarWidthCmp());
int lim = m_unoptflatVars.size() < 10 ? m_unoptflatVars.size() : 10;
for (int i = 0; i < lim; i++) {
OrderVarStdVertex* vsvertexp = m_unoptflatVars[i];
AstVar* varp = vsvertexp->varScp()->varp();
cerr<<V3Error::msgPrefix()<<" "
<<varp->fileline()<<" "<<varp->prettyName()<<dec
<<", width "<<varp->width()<<", fanout "
<<vsvertexp->fanout()<<endl;
}
// Up to 10 of the most fanned out
cerr<<V3Error::msgPrefix()
<<" Most fanned out candidate vars to split:"<<endl;
sort (m_unoptflatVars.begin(), m_unoptflatVars.end(),
OrderVarFanoutCmp());
lim = m_unoptflatVars.size() < 10 ? m_unoptflatVars.size() : 10;
for (int i = 0; i < lim; i++) {
OrderVarStdVertex* vsvertexp = m_unoptflatVars[i];
AstVar* varp = vsvertexp->varScp()->varp();
cerr<<V3Error::msgPrefix()<<" "
<<varp->fileline()<<" "<<varp->prettyName()
<<", width "<<dec<<varp->width()
<<", fanout "<<vsvertexp->fanout()<<endl;
}
m_unoptflatVars.clear();
}
void reportLoopVarsIterate(V3GraphVertex* vertexp, uint32_t color) {
if (vertexp->user()) return; // Already done
vertexp->user(1);
if (OrderVarStdVertex* vsvertexp = dynamic_cast<OrderVarStdVertex*>(vertexp)) {
// Only reporting on standard variable vertices
AstVar* varp = vsvertexp->varScp()->varp();
if (!varp->user3()) {
string name = varp->prettyName();
if ((varp->width() != 1)
&& (name.find("__Vdly") == string::npos)
&& (name.find("__Vcell") == string::npos)) {
// Variable to report on and not yet done
m_unoptflatVars.push_back(vsvertexp);
}
varp->user3Inc();
}
}
// Iterate through all the to and from vertices of the same color
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep;
edgep = edgep->outNextp()) {
if (edgep->top()->color() == color) {
reportLoopVarsIterate(edgep->top(), color);
}
}
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep;
edgep = edgep->inNextp()) {
if (edgep->fromp()->color() == color) {
reportLoopVarsIterate(edgep->fromp(), color);
}
}
}
// VISITORS
virtual void visit(AstNetlist* nodep, AstNUser*) {
{
@@ -949,28 +1061,33 @@ void OrderVisitor::processBrokeLoop() {
// Clock propagation
void OrderVisitor::processInputs() {
m_graph.userClearVertices(); // Vertex::user() // true if processed
m_graph.userClearVertices(); // Vertex::user() // 1 if input recursed, 2 if marked as input, 3 if out-edges recursed
// Start at input vertex, process from input-to-output order
VertexVec todoVec; // List of newly-input marked vectors we need to process
todoVec.push_front(m_inputsVxp);
m_inputsVxp->isFromInput(true); // By definition
processInputsIterate(m_inputsVxp);
while (!todoVec.empty()) {
OrderEitherVertex* vertexp = todoVec.back(); todoVec.pop_back();
processInputsOutIterate(vertexp, todoVec);
}
}
void OrderVisitor::processInputsIterate(OrderEitherVertex* vertexp) {
void OrderVisitor::processInputsInIterate(OrderEitherVertex* vertexp, VertexVec& todoVec) {
// Propagate PrimaryIn through simple assignments
if (vertexp->user()) return; // Already processed
if (0 && debug()>=9) {
UINFO(9," InIt "<<vertexp<<endl);
UINFO(9," InIIter "<<vertexp<<endl);
if (OrderLogicVertex* vvertexp = dynamic_cast<OrderLogicVertex*>(vertexp)) {
vvertexp->nodep()->dumpTree(cout,"- TT: ");
}
}
vertexp->user(true); // Processing
vertexp->user(1); // Processing
// First handle all inputs to this vertex, in most cases they'll be already processed earlier
// Also, determine if this vertex is an input
int inonly = 1; // 0=no, 1=maybe, 2=yes until a no
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) {
OrderEitherVertex* frVertexp = (OrderEitherVertex*)edgep->fromp();
processInputsIterate(frVertexp);
processInputsInIterate(frVertexp, todoVec);
if (frVertexp->isFromInput()) {
if (inonly==1) inonly = 2;
} else if (dynamic_cast<OrderVarPostVertex*>(frVertexp)) {
@@ -981,20 +1098,38 @@ void OrderVisitor::processInputsIterate(OrderEitherVertex* vertexp) {
break;
}
}
if (inonly == 2) { // Set it. Note may have already been set earlier, too
if (inonly == 2 && vertexp->user()<2) { // Set it. Note may have already been set earlier, too
UINFO(9," Input reassignment: "<<vertexp<<endl);
vertexp->isFromInput(true);
vertexp->user(2); // 2 means on list
// Can't work on out-edges of a node we know is an input immediately,
// as it might visit other nodes before their input state is resolved.
// So push to list and work on it later when all in-edges known resolved
todoVec.push_back(vertexp);
}
// If we're still an input, process all targets of this vertex
if (vertexp->isFromInput()) {
//UINFO(9," InIdone "<<vertexp<<endl);
}
void OrderVisitor::processInputsOutIterate(OrderEitherVertex* vertexp, VertexVec& todoVec) {
if (vertexp->user()==3) return; // Already out processed
//UINFO(9," InOIter "<<vertexp<<endl);
// First make sure input path is fully recursed
processInputsInIterate(vertexp, todoVec);
// Propagate PrimaryIn through simple assignments
if (!vertexp->isFromInput()) v3fatalSrc("processInputsOutIterate only for input marked vertexes");
vertexp->user(3); // out-edges processed
{
// Propagate PrimaryIn through simple assignments, followint target of vertex
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
OrderEitherVertex* toVertexp = (OrderEitherVertex*)edgep->top();
if (OrderVarStdVertex* vvertexp = dynamic_cast<OrderVarStdVertex*>(toVertexp)) {
processInputsIterate(vvertexp);
processInputsInIterate(vvertexp, todoVec);
}
if (OrderLogicVertex* vvertexp = dynamic_cast<OrderLogicVertex*>(toVertexp)) {
if (vvertexp->nodep()->castNodeAssign()) {
processInputsIterate(vvertexp);
processInputsInIterate(vvertexp, todoVec);
}
}
}
@@ -1600,7 +1735,10 @@ void OrderVisitor::process() {
m_graph.acyclic(&V3GraphEdge::followAlwaysTrue);
m_graph.dumpDotFilePrefixed("orderg_preasn_done", true);
#else
// Break cycles
// Break cycles. Each strongly connected subgraph (including cutable
// edges) will have its own color, and corresponds to a loop in the
// original graph. However the new graph will be acyclic (the removed
// edges are actually still there, just with weight 0).
UINFO(2," Acyclic & Order...\n");
m_graph.acyclic(&V3GraphEdge::followAlwaysTrue);
m_graph.dumpDotFilePrefixed("orderg_acyc");
@@ -1611,6 +1749,9 @@ void OrderVisitor::process() {
m_graph.order();
m_graph.dumpDotFilePrefixed("orderg_order");
// This finds everything that can be traced from an input (which by
// definition are the source clocks). After this any vertex which was
// traced has isFromInput() true.
UINFO(2," Process Clocks...\n");
processInputs(); // must be before processCircular
+107 -41
View File
@@ -123,6 +123,15 @@ public:
virtual void loopsVertexCb(V3GraphVertex* vertexp);
};
//! Graph for UNOPTFLAT loops
class UnoptflatGraph : public OrderGraph {
public:
UnoptflatGraph() {}
virtual ~UnoptflatGraph() {}
// Methods
virtual void loopsVertexCb(V3GraphVertex* vertexp);
};
//######################################################################
// Vertex types
@@ -131,12 +140,16 @@ class OrderEitherVertex : public V3GraphVertex {
AstSenTree* m_domainp; // Clock domain (NULL = to be computed as we iterate)
OrderLoopId m_inLoop; // Loop number vertex is in
bool m_isFromInput; // From input, or derrived therefrom (conservatively false)
protected:
OrderEitherVertex(V3Graph* graphp, const OrderEitherVertex& old)
: V3GraphVertex(graphp, old), m_scopep(old.m_scopep), m_domainp(old.m_domainp)
, m_inLoop(old.m_inLoop), m_isFromInput(old.m_isFromInput) {}
public:
OrderEitherVertex(V3Graph* graphp, AstScope* scopep, AstSenTree* domainp)
: V3GraphVertex(graphp), m_scopep(scopep), m_domainp(domainp)
, m_inLoop(LOOPID_UNKNOWN), m_isFromInput(false) {
}
, m_inLoop(LOOPID_UNKNOWN), m_isFromInput(false) {}
virtual ~OrderEitherVertex() {}
virtual OrderEitherVertex* clone(V3Graph* graphp) const = 0;
// Methods
virtual OrderVEdgeType type() const = 0;
virtual bool domainMatters() = 0; // Must be in same domain when cross edge to this vertex
@@ -152,12 +165,16 @@ public:
};
class OrderInputsVertex : public OrderEitherVertex {
OrderInputsVertex(V3Graph* graphp, const OrderInputsVertex& old)
: OrderEitherVertex(graphp, old) {}
public:
OrderInputsVertex(V3Graph* graphp, AstSenTree* domainp)
: OrderEitherVertex(graphp, NULL, domainp) {
isFromInput(true); // By definition
}
virtual ~OrderInputsVertex() {}
virtual OrderInputsVertex* clone(V3Graph* graphp) const {
return new OrderInputsVertex(graphp, *this); }
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_INPUTS; }
virtual string name() const { return "*INPUTS*"; }
virtual string dotColor() const { return "green"; }
@@ -166,10 +183,14 @@ public:
};
class OrderSettleVertex : public OrderEitherVertex {
OrderSettleVertex(V3Graph* graphp, const OrderSettleVertex& old)
: OrderEitherVertex(graphp, old) {}
public:
OrderSettleVertex(V3Graph* graphp, AstSenTree* domainp)
: OrderEitherVertex(graphp, NULL, domainp) {}
virtual ~OrderSettleVertex() {}
virtual OrderSettleVertex* clone(V3Graph* graphp) const {
return new OrderSettleVertex(graphp, *this); }
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_SETTLE; }
virtual string name() const { return "*SETTLE*"; }
virtual string dotColor() const { return "green"; }
@@ -180,10 +201,15 @@ public:
class OrderLogicVertex : public OrderEitherVertex {
AstNode* m_nodep;
OrderMoveVertex* m_moveVxp;
protected:
OrderLogicVertex(V3Graph* graphp, const OrderLogicVertex& old)
: OrderEitherVertex(graphp, old), m_nodep(old.m_nodep), m_moveVxp(old.m_moveVxp) {}
public:
OrderLogicVertex(V3Graph* graphp, AstScope* scopep, AstSenTree* domainp, AstNode* nodep)
: OrderEitherVertex(graphp, scopep, domainp), m_nodep(nodep), m_moveVxp(NULL) {}
virtual ~OrderLogicVertex() {}
virtual OrderLogicVertex* clone(V3Graph* graphp) const {
return new OrderLogicVertex(graphp, *this); }
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_LOGIC; }
virtual bool domainMatters() { return true; }
// Accessors
@@ -198,11 +224,14 @@ class OrderVarVertex : public OrderEitherVertex {
AstVarScope* m_varScp;
OrderVarVertex* m_pilNewVertexp; // for processInsLoopNewVar
bool m_isClock; // Used as clock
protected:
OrderVarVertex(V3Graph* graphp, const OrderVarVertex& old)
: OrderEitherVertex(graphp, old)
, m_varScp(old.m_varScp), m_pilNewVertexp(old.m_pilNewVertexp), m_isClock(old.m_isClock) {}
public:
OrderVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
: OrderEitherVertex(graphp, scopep, NULL), m_varScp(varScp)
, m_pilNewVertexp(NULL), m_isClock(false)
{}
, m_pilNewVertexp(NULL), m_isClock(false) {}
virtual ~OrderVarVertex() {}
virtual OrderVarVertex* clone (V3Graph* graphp) const = 0;
virtual OrderVEdgeType type() const = 0;
@@ -215,66 +244,71 @@ public:
};
class OrderVarStdVertex : public OrderVarVertex {
OrderVarStdVertex(V3Graph* graphp, const OrderVarStdVertex& old)
: OrderVarVertex(graphp, old) {}
public:
OrderVarStdVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
: OrderVarVertex(graphp, scopep,varScp) {}
: OrderVarVertex(graphp, scopep, varScp) {}
virtual ~OrderVarStdVertex() {}
virtual OrderVarStdVertex* clone(V3Graph* graphp) const {
return new OrderVarStdVertex(graphp, *this); }
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_VARSTD; }
virtual OrderVarVertex* clone (V3Graph* graphp) const {
return new OrderVarStdVertex(graphp, scopep(), varScp());
}
virtual string name() const { return (cvtToStr((void*)varScp())+"\\n "+varScp()->name());}
virtual string dotColor() const { return "skyblue"; }
virtual bool domainMatters() { return true; }
};
class OrderVarPreVertex : public OrderVarVertex {
OrderVarPreVertex(V3Graph* graphp, const OrderVarPreVertex& old)
: OrderVarVertex(graphp, old) {}
public:
OrderVarPreVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
: OrderVarVertex(graphp, scopep,varScp) {}
virtual ~OrderVarPreVertex() {}
virtual OrderVarPreVertex* clone(V3Graph* graphp) const {
return new OrderVarPreVertex(graphp, *this); }
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_VARPRE; }
virtual OrderVarVertex* clone (V3Graph* graphp) const {
return new OrderVarPreVertex(graphp, scopep(), varScp());
}
virtual string name() const { return (cvtToStr((void*)varScp())+" PRE\\n "+varScp()->name());}
virtual string dotColor() const { return "lightblue"; }
virtual bool domainMatters() { return false; }
};
class OrderVarPostVertex : public OrderVarVertex {
OrderVarPostVertex(V3Graph* graphp, const OrderVarPostVertex& old)
: OrderVarVertex(graphp, old) {}
public:
OrderVarPostVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
: OrderVarVertex(graphp, scopep,varScp) {}
virtual OrderVarPostVertex* clone(V3Graph* graphp) const {
return new OrderVarPostVertex(graphp, *this); }
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_VARPOST; }
virtual ~OrderVarPostVertex() {}
virtual OrderVarVertex* clone (V3Graph* graphp) const {
return new OrderVarPostVertex(graphp, scopep(), varScp());
}
virtual string name() const { return (cvtToStr((void*)varScp())+" POST\\n "+varScp()->name());}
virtual string dotColor() const { return "CadetBlue"; }
virtual bool domainMatters() { return false; }
};
class OrderVarPordVertex : public OrderVarVertex {
OrderVarPordVertex(V3Graph* graphp, const OrderVarPordVertex& old)
: OrderVarVertex(graphp, old) {}
public:
OrderVarPordVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
: OrderVarVertex(graphp, scopep,varScp) {}
virtual OrderVarVertex* clone (V3Graph* graphp) const {
return new OrderVarPordVertex(graphp, scopep(), varScp());
}
virtual ~OrderVarPordVertex() {}
virtual OrderVarPordVertex* clone(V3Graph* graphp) const {
return new OrderVarPordVertex(graphp, *this); }
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_VARPORD; }
virtual string name() const { return (cvtToStr((void*)varScp())+" PORD\\n "+varScp()->name());}
virtual string dotColor() const { return "NavyBlue"; }
virtual bool domainMatters() { return false; }
};
class OrderVarSettleVertex : public OrderVarVertex {
OrderVarSettleVertex(V3Graph* graphp, const OrderVarSettleVertex& old)
: OrderVarVertex(graphp, old) {}
public:
OrderVarSettleVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
: OrderVarVertex(graphp, scopep,varScp) {}
virtual ~OrderVarSettleVertex() {}
virtual OrderVarSettleVertex* clone(V3Graph* graphp) const {
return new OrderVarSettleVertex(graphp, *this); }
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_VARSETTLE; }
virtual OrderVarVertex* clone (V3Graph* graphp) const {
return new OrderVarSettleVertex(graphp, scopep(), varScp());
}
virtual string name() const { return (cvtToStr((void*)varScp())+" STL\\n "+varScp()->name());}
virtual string dotColor() const { return "PowderBlue"; }
virtual bool domainMatters() { return false; }
@@ -288,13 +322,18 @@ class OrderLoopBeginVertex : public OrderLogicVertex {
// However, a LoopBeginVertex is not "under" the loop per se, and it may be under another loop.
OrderLoopId m_loopId; // Arbitrary # to ID this loop
uint32_t m_loopColor; // Color # of loop (for debug)
OrderLoopBeginVertex(V3Graph* graphp, const OrderLoopBeginVertex& old)
: OrderLogicVertex(graphp, *this)
, m_loopId(old.m_loopId), m_loopColor(old.m_loopColor) {}
public:
OrderLoopBeginVertex(V3Graph* graphp, AstScope* scopep, AstSenTree* domainp, AstUntilStable* nodep,
OrderLoopId loopId, uint32_t loopColor)
: OrderLogicVertex(graphp, scopep, domainp, nodep)
, m_loopId(loopId), m_loopColor(loopColor) {
}
, m_loopId(loopId), m_loopColor(loopColor) {}
virtual ~OrderLoopBeginVertex() {}
virtual OrderLoopBeginVertex* clone(V3Graph* graphp) const {
return new OrderLoopBeginVertex(graphp, *this);
}
// Methods
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_LOOPBEGIN; }
virtual string name() const { return "LoopBegin_"+cvtToStr(loopId())+"_c"+cvtToStr(loopColor()); }
@@ -306,17 +345,22 @@ public:
};
class OrderLoopEndVertex : public OrderLogicVertex {
// A end vertex points to the *same nodep* as the Begin,
// as we need it to be a logic vertex for moving, but don't need a permanent node.
// We won't add to the output graph though, so it shouldn't matter.
// A end vertex points to the *same nodep* as the Begin, as we need it to
// be a logic vertex for moving, but don't need a permanent node. We
// won't add to the output graph though, so it shouldn't matter.
OrderLoopBeginVertex* m_beginVertexp; // Corresponding loop begin
OrderLoopEndVertex(V3Graph* graphp, const OrderLoopEndVertex& old)
: OrderLogicVertex(graphp, old), m_beginVertexp(old.m_beginVertexp) {}
public:
OrderLoopEndVertex(V3Graph* graphp, OrderLoopBeginVertex* beginVertexp)
: OrderLogicVertex(graphp, beginVertexp->scopep(), beginVertexp->domainp(), beginVertexp->nodep())
: OrderLogicVertex(graphp, beginVertexp->scopep(),
beginVertexp->domainp(), beginVertexp->nodep())
, m_beginVertexp(beginVertexp) {
inLoop(beginVertexp->loopId());
}
virtual ~OrderLoopEndVertex() {}
virtual OrderLoopEndVertex* clone(V3Graph* graphp) const {
return new OrderLoopEndVertex(graphp, *this); }
// Methods
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_LOOPEND; }
virtual string name() const { return "LoopEnd_"+cvtToStr(inLoop())+"_c"+cvtToStr(loopColor()); }
@@ -342,10 +386,17 @@ protected:
// for the head of the list, see the same var name under OrderVisitor
V3ListEnt<OrderMoveVertex*> m_pomWaitingE; // List of nodes needing inputs to become ready
V3ListEnt<OrderMoveVertex*> m_readyVerticesE;// List of ready under domain/scope
// CONSTRUCTORS
OrderMoveVertex(V3Graph* graphp, const OrderMoveVertex& old)
: V3GraphVertex(graphp, old), m_logicp(old.m_logicp), m_state(old.m_state)
, m_domScopep(old.m_domScopep) {}
public:
OrderMoveVertex(V3Graph* graphp, OrderLogicVertex* logicp)
: V3GraphVertex(graphp), m_logicp(logicp), m_state(POM_WAIT), m_domScopep(NULL) {}
virtual ~OrderMoveVertex() {}
virtual OrderMoveVertex* clone(V3Graph* graphp) const {
return new OrderMoveVertex(graphp, *this);
}
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_MOVE; }
virtual string dotColor() const { return logicp()->dotColor(); }
virtual string name() const {
@@ -376,18 +427,22 @@ public:
// Edge types
class OrderEdge : public V3GraphEdge {
protected:
OrderEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top,
const OrderEdge& old)
: V3GraphEdge(graphp, fromp, top, old) {}
public:
OrderEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top,
int weight, bool cutable=false)
: V3GraphEdge(graphp, fromp, top, weight, cutable) {}
virtual ~OrderEdge() {}
virtual OrderVEdgeType type() const { return OrderVEdgeType::EDGE_STD; }
virtual OrderEdge* clone (V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const {
return new OrderEdge(graphp, fromp, top, *this);
}
// When ordering combo blocks with stronglyConnected, follow edges not involving pre/pos variables
virtual bool followComboConnected() const { return true; }
virtual bool followSequentConnected() const { return true; }
virtual OrderEdge* clone (V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const {
return new OrderEdge(graphp, fromp, top, weight(), cutable());
}
static bool followComboConnected(const V3GraphEdge* edgep) {
const OrderEdge* oedgep = dynamic_cast<const OrderEdge*>(edgep);
if (!oedgep) v3fatalSrc("Following edge of non-OrderEdge type");
@@ -403,14 +458,17 @@ public:
class OrderChangeDetEdge : public OrderEdge {
// Edge created from variable to OrderLoopEndVertex
// Indicates a change detect will be required for this loop construct
OrderChangeDetEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top,
const OrderChangeDetEdge& old)
: OrderEdge(graphp, fromp, top, old) {}
public:
OrderChangeDetEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top)
: OrderEdge(graphp, fromp, top, WEIGHT_MEDIUM, false) {}
virtual OrderVEdgeType type() const { return OrderVEdgeType::EDGE_CHANGEDET; }
virtual OrderEdge* clone (V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const {
return new OrderChangeDetEdge(graphp, fromp, top);
}
virtual ~OrderChangeDetEdge() {}
virtual OrderChangeDetEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const {
return new OrderChangeDetEdge(graphp, fromp, top, *this);
}
virtual string dotColor() const { return "blue"; }
};
@@ -418,14 +476,17 @@ class OrderComboCutEdge : public OrderEdge {
// Edge created from output of combo logic
// Breakable if the output var is also a input,
// in which case we'll need a change detect loop around this var.
OrderComboCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top,
const OrderComboCutEdge& old)
: OrderEdge(graphp, fromp, top, old) {}
public:
OrderComboCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top)
: OrderEdge(graphp, fromp, top, WEIGHT_COMBO, CUTABLE) {}
virtual OrderVEdgeType type() const { return OrderVEdgeType::EDGE_COMBOCUT; }
virtual OrderEdge* clone (V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const {
return new OrderComboCutEdge(graphp, fromp, top);
}
virtual ~OrderComboCutEdge() {}
virtual OrderComboCutEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const {
return new OrderComboCutEdge(graphp, fromp, top, *this);
}
virtual string dotColor() const { return "yellowGreen"; }
virtual bool followComboConnected() const { return true; }
virtual bool followSequentConnected() const { return true; }
@@ -435,14 +496,17 @@ class OrderPostCutEdge : public OrderEdge {
// Edge created from output of post assignment
// Breakable if the output var feeds back to input combo logic or another clock pin
// in which case we'll need a change detect loop around this var.
OrderPostCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top,
const OrderPostCutEdge& old)
: OrderEdge(graphp, fromp, top, old) {}
public:
OrderPostCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top)
: OrderEdge(graphp, fromp, top, WEIGHT_COMBO, CUTABLE) {}
virtual OrderVEdgeType type() const { return OrderVEdgeType::EDGE_POSTCUT; }
virtual OrderEdge* clone (V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const {
return new OrderPostCutEdge(graphp, fromp, top);
}
virtual ~OrderPostCutEdge() {}
virtual OrderPostCutEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const {
return new OrderPostCutEdge(graphp, fromp, top, *this);
}
virtual string dotColor() const { return "PaleGreen"; }
virtual bool followComboConnected() const { return false; }
virtual bool followSequentConnected() const { return true; }
@@ -452,16 +516,18 @@ class OrderPreCutEdge : public OrderEdge {
// Edge created from var_PREVAR->consuming logic vertex
// Always breakable, just results in performance loss
// in which case we can't optimize away the pre/post delayed assignments
OrderPreCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top,
const OrderPreCutEdge& old)
: OrderEdge(graphp, fromp, top, old) {}
public:
OrderPreCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top)
: OrderEdge(graphp, fromp, top, WEIGHT_PRE, CUTABLE) {}
virtual OrderVEdgeType type() const { return OrderVEdgeType::EDGE_PRECUT; }
virtual OrderEdge* clone (V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const {
return new OrderPreCutEdge(graphp, fromp, top);
virtual OrderPreCutEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const {
return new OrderPreCutEdge(graphp, fromp, top, *this);
}
virtual ~OrderPreCutEdge() {}
virtual string dotColor() const { return "khaki"; }
virtual bool followComboConnected() const { return false; }
virtual bool followSequentConnected() const { return false; }
};
+1
View File
@@ -77,6 +77,7 @@ struct V3ParseBisonYYSType {
AstPackageRef* packagerefp;
AstParseRef* parserefp;
AstPatMember* patmemberp;
AstPattern* patternp;
AstPin* pinp;
AstRange* rangep;
AstSenTree* sentreep;
+1 -1
View File
@@ -416,7 +416,7 @@ private:
}
if (splitAlwaysp) {
++m_statSplits;
AstAlways* alwaysp = new AstAlways(newListp->fileline(), NULL, NULL);
AstAlways* alwaysp = new AstAlways(newListp->fileline(), VAlwaysKwd::ALWAYS, NULL, NULL);
addAfterp->addNextHere(alwaysp); addAfterp=alwaysp;
alwaysp->addStmtp(newListp);
} else {
+41 -37
View File
@@ -20,7 +20,7 @@
// V3Tristate's Transformations:
//
// Modify the design to expand tristate logic into its
// corresponding two state reprasentation. At the lowest levels,
// corresponding two state representation. At the lowest levels,
//
// In detail:
//
@@ -46,12 +46,15 @@
// logic that they may go through until they hit the module level. At
// the module level, all the output enable signals from what can be
// many tristate drivers are combined together to produce a single
// driver and output enable. If the signal propigates up into higher
// driver and output enable. If the signal propagates up into higher
// modules, then new ports are created with for the signal with
// suffixes __en and __out. The original port is turned from an inout
// to an input and the __out port carries the output driver signal and
// the __en port carried the output enable for that driver.
//
// Note 1800-2012 adds user defined resolution functions. This suggests
// long term this code should be scoped-based and resolve all nodes at once
// rather than hierarchically.
//*************************************************************************
#include "config_build.h"
@@ -222,6 +225,7 @@ public:
}
}
m_graph.clear();
AstNode::user5ClearTree(); // Wipe all node user5p's that point to vertexes
}
void graphWalk(AstNodeModule* nodep) {
//if (debug()>=9) m_graph.dumpDotFilePrefixed("tri_pre__"+nodep->name());
@@ -252,7 +256,7 @@ public:
TristateVertex* vertexp = (TristateVertex*)(nodep->user5p());
if (!vertexp) {
// Not v3errorSrc as no reason to stop the world
nodep->v3error("Unsupported tristate constuct (not in propagation graph): "<<nodep->prettyTypeName());
nodep->v3error("Unsupported tristate construct (not in propagation graph): "<<nodep->prettyTypeName());
} else {
// We don't warn if no vertexp->isTristate() as the creation process makes midling nodes that don't have it set
vertexp->processed(true);
@@ -445,7 +449,7 @@ class TristateVisitor : public TristateBaseVisitor {
} else {
if (oldpullp->direction() != pullp->direction()) {
pullp->v3error("Unsupported: Conflicting pull directions.");
oldpullp->v3error("... Location of conflicing pull.");
oldpullp->v3error("... Location of conflicting pull.");
}
}
}
@@ -494,6 +498,7 @@ class TristateVisitor : public TristateBaseVisitor {
// Now go through the lhs driver map and generate the output
// enable logic for any tristates.
// Note there might not be any drivers.
for (VarMap::iterator nextit, it = m_lhsmap.begin(); it != m_lhsmap.end(); it = nextit) {
nextit = it; ++nextit;
AstVar* invarp = (*it).first;
@@ -518,8 +523,8 @@ class TristateVisitor : public TristateBaseVisitor {
// if this is the top level so that we can force the final
// tristate resolution at the top.
AstVar* envarp = NULL;
AstVar* outvarp = NULL;
AstVar* lhsp = invarp;
AstVar* outvarp = NULL; // __out
AstVar* lhsp = invarp; // Variable to assign drive-value to (<in> or __out)
if (!nodep->isTop() && invarp->isIO()) {
// This var becomes an input
invarp->varType2In(); // convert existing port to type input
@@ -589,12 +594,10 @@ class TristateVisitor : public TristateBaseVisitor {
undrivenp = ((!undrivenp) ? tmp
: new AstAnd(nodep->fileline(), tmp, undrivenp));
}
if (!undrivenp) { // No drivers on the bus
V3Number ones(nodep->fileline(), lhsp->width()); ones.setAllBits1();
undrivenp = new AstConst(nodep->fileline(), ones);
}
if (!outvarp) {
// This is the final resolution of the tristate, so we apply
// the pull direction to any undriven pins.
@@ -617,7 +620,7 @@ class TristateVisitor : public TristateBaseVisitor {
new AstVarRef(envarp->fileline(),
envarp, true), enp));
}
// __out (child) or <in> (parent) = drive-value expression
AstNode* assp = new AstAssignW(lhsp->fileline(),
new AstVarRef(lhsp->fileline(),
lhsp,
@@ -661,7 +664,7 @@ class TristateVisitor : public TristateBaseVisitor {
AstConst* enp = new AstConst(fl, numz0);
nodep->replaceWith(newconstp);
pushDeletep(nodep); nodep = NULL;
newconstp->user1p(enp);
newconstp->user1p(enp); // propagate up constant with non-Z bits as 1
}
}
}
@@ -698,7 +701,7 @@ class TristateVisitor : public TristateBaseVisitor {
// two expressions with the same conditional.
AstNode* enp = new AstCond(nodep->fileline(), condp->cloneTree(false), en1p, en2p);
UINFO(9," newcond "<<enp<<endl);
nodep->user1p(enp);
nodep->user1p(enp); // propagate up COND(lhsp->enable, rhsp->enable)
expr1p->user1p(NULL);
expr2p->user1p(NULL);
}
@@ -735,7 +738,7 @@ class TristateVisitor : public TristateBaseVisitor {
AstNode* enp = new AstSel(nodep->fileline(), en1p,
nodep->lsbp()->cloneTree(true), nodep->widthp()->cloneTree(true));
UINFO(9," newsel "<<enp<<endl);
nodep->user1p(enp);
nodep->user1p(enp); // propagate up SEL(fromp->enable, value)
m_tgraph.didProcess(nodep);
}
}
@@ -783,7 +786,7 @@ class TristateVisitor : public TristateBaseVisitor {
AstNode* en2p = getEnp(expr2p);
AstNode* enp = new AstConcat(nodep->fileline(), en1p, en2p);
UINFO(9," newconc "<<enp<<endl);
nodep->user1p(enp);
nodep->user1p(enp); // propagate up CONCAT(lhsp->enable, rhsp->enable)
expr1p->user1p(NULL);
expr2p->user1p(NULL);
}
@@ -925,14 +928,14 @@ class TristateVisitor : public TristateBaseVisitor {
checkUnhandled(nodep);
// Unsupported: A === 3'b000 should compare with the enables, but we don't do
// so at present, we only compare if there is a z in the equation.
// Otherwise we'd need to attach an enable to every signal, then optimize then
// Otherwise we'd need to attach an enable to every signal, then optimize them
// away later when we determine the signal has no tristate
nodep->iterateChildren(*this);
UINFO(9,dbgState()<<nodep<<endl);
AstConst* constp = nodep->lhsp()->castConst(); // Constification always moves const to LHS
AstVarRef* varrefp = nodep->rhsp()->castVarRef(); // Input variable
if (constp && constp->user1p() && varrefp) {
// 3'b1z0 -> ((3'b101 == __en) && (3'b100 == __in))
// 3'b1z0 -> ((3'b101 == in__en) && (3'b100 == in))
varrefp->unlinkFrBack();
FileLine* fl = nodep->fileline();
V3Number oneIfEn = constp->user1p()->castNode()->castConst()->num(); // visit(AstConst) already split into en/ones
@@ -1021,19 +1024,20 @@ class TristateVisitor : public TristateBaseVisitor {
// ENABLE: -> (VARREF(trisig__pinen)
// Added complication is the signal may be an output/inout or just input with tie off (or not) up top
// PIN PORT NEW PORTS AND CONNECTIONS
// N/C input in(from-resolver), __out(to-resolver-only), __en(to-resolver-only)
// N/C input in(from-resolver), __en(to-resolver-only), __out(to-resolver-only)
// N/C inout Spec says illegal
// N/C output Unsupported; Illegal?
// wire input in(from-resolver-with-wire-value), __out(to-resolver-only), __en(to-resolver-only)
// wire inout in, __out, __en
// wire output in, __out, __en
// const input in(from-resolver-with-const-value), __out(to-resolver-only), __en(to-resolver-only)
// const inout Spec says illegal
// const output Unsupported; Illegal?
// wire input in(from-resolver-with-wire-value), __en(from-resolver-wire), __out(to-resolver-only)
// wire inout in, __en, __out
// wire output in, __en, __out
// const input in(from-resolver-with-const-value), __en(from-resolver-const), __out(to-resolver-only)
// const inout Spec says illegal
// const output Unsupported; Illegal?
virtual void visit(AstPin* nodep, AstNUser*) {
if (m_graphing) {
if (nodep->user2() & U2_GRAPHING) return; // This pin is already expanded
nodep->user2(U2_GRAPHING);
// Find child module's new variables.
AstVar* enModVarp = (AstVar*) nodep->modVarp()->user1p();
if (!enModVarp) {
if (nodep->exprp()) {
@@ -1048,7 +1052,7 @@ class TristateVisitor : public TristateBaseVisitor {
if (debug()>=9) nodep->dumpTree(cout,"-pin-pre: ");
// Empty/in-only; need Z to propagate
bool inOnlyProcessing = (nodep->exprp()
bool inDeclProcessing = (nodep->exprp()
&& nodep->modVarp()->isInOnly()
// Need to consider the original state instead of current state
// as we converted tristates to inputs, which do not want to have this.
@@ -1060,7 +1064,7 @@ class TristateVisitor : public TristateBaseVisitor {
nodep->modVarp()->isOutput()));
m_tgraph.setTristate(ucVarp);
// We don't need a driver on the wire; the lack of one will default to tristate
} else if (inOnlyProcessing) { // Not an input that was a converted tristate
} else if (inDeclProcessing) { // Not an input that was a converted tristate
// Input only may have driver in underneath module which would stomp
// the input value. So make a temporary connection.
AstAssignW* reAssignp = V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp, true, true);
@@ -1077,7 +1081,7 @@ class TristateVisitor : public TristateBaseVisitor {
AstVar* enVarp = new AstVar(nodep->fileline(),
AstVarType::MODULETEMP,
nodep->name() + "__en" + cvtToStr(m_unique++),
VFlagLogicPacked(), enModVarp->width());
VFlagBitPacked(), enModVarp->width());
UINFO(9," newenv "<<enVarp<<endl);
AstPin* enpinp = new AstPin(nodep->fileline(),
nodep->pinNum(),
@@ -1107,9 +1111,9 @@ class TristateVisitor : public TristateBaseVisitor {
outpinp->user2(U2_BOTH); // don't iterate the pin later
nodep->addNextHere(outpinp);
// Simplify
if (inOnlyProcessing) { // Not an input that was a converted tristate
if (inDeclProcessing) { // Not an input that was a converted tristate
// The pin is an input, but we need an output
// The if() above is neded because the Visitor is simple, it will flip ArraySel's and such,
// The if() above is needed because the Visitor is simple, it will flip ArraySel's and such,
// but if the pin is an input the earlier reconnectSimple made it a VarRef without any ArraySel, etc
TristatePinVisitor visitor (outexprp, m_tgraph, true);
}
@@ -1127,29 +1131,29 @@ class TristateVisitor : public TristateBaseVisitor {
if (debug()>=9 && inAssignp) inAssignp->dumpTree(cout,"-pin-as: ");
// Connect enable to output signal
AstVarRef* outrefp;
AstVarRef* exprrefp; // Tristate variable that the Pin's expression refers to
if (!outAssignp) {
outrefp = outpinp->exprp()->castVarRef();
exprrefp = outpinp->exprp()->castVarRef();
} else {
outrefp = outAssignp->rhsp()->castVarRef(); // This should be the same var as the output pin
exprrefp = outAssignp->rhsp()->castVarRef(); // This should be the same var as the output pin
}
if (!outrefp) { // deal with simple varref port
if (!exprrefp) { // deal with simple varref port
// pinReconnect should have converted this
nodep->v3error("Unsupported tristate port expression: "<<nodep->exprp()->prettyTypeName());
} else {
UINFO(9,"outref "<<outrefp<<endl);
outrefp->user1p(enrefp); // Mark as now tristated; iteration will pick it up from there
UINFO(9,"outref "<<exprrefp<<endl);
exprrefp->user1p(enrefp); // Mark as now tristated; iteration will pick it up from there
if (!outAssignp) {
mapInsertLhsVarRef(outrefp); // insertTristates will convert
mapInsertLhsVarRef(exprrefp); // insertTristates will convert
// // to a varref to the __out# variable
} // else the assignment deals with the connection
}
// Propagate any pullups/pulldowns upwards if necessary
if (outrefp) {
if (exprrefp) {
if (AstPull* pullp = (AstPull*) nodep->modVarp()->user3p()) {
UINFO(9, "propagate pull on "<<outrefp<<endl);
setPullDirection(outrefp->varp(), pullp);
UINFO(9, "propagate pull on "<<exprrefp<<endl);
setPullDirection(exprrefp->varp(), pullp);
}
}
+89 -27
View File
@@ -133,6 +133,17 @@ public:
}
}
}
bool isUsedNotDrivenBit (int bit, int width) const {
for (int i=0; i<width; i++) {
if (bitNumOk(bit+i)
&& (m_usedWhole || m_flags[(bit+i)*FLAGS_PER_BIT + FLAG_USED])
&& !(m_drivenWhole || m_flags[(bit+i)*FLAGS_PER_BIT + FLAG_DRIVEN])) return true;
}
return false;
}
bool isUsedNotDrivenAny () const {
return isUsedNotDrivenBit(0, m_flags.size()/FLAGS_PER_BIT);
}
bool unusedMatch(AstVar* nodep) {
const char* regexpp = v3Global.opt.unusedRegexp().c_str();
if (!regexpp || !*regexpp) return false;
@@ -213,11 +224,13 @@ private:
// NODE STATE
// AstVar::user1p -> UndrivenVar* for usage var, 0=not set yet
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
// STATE
vector<UndrivenVarEntry*> m_entryps; // Nodes to delete when we are finished
vector<UndrivenVarEntry*> m_entryps[3]; // Nodes to delete when we are finished
bool m_markBoth; // Mark as driven+used
AstNodeFTask* m_taskp; // Current task
AstAlways* m_alwaysp; // Current always
// METHODS
static int debug() {
@@ -226,31 +239,45 @@ private:
return level;
}
UndrivenVarEntry* getEntryp(AstVar* nodep) {
if (!nodep->user1p()) {
UndrivenVarEntry* getEntryp(AstVar* nodep, int which_user) {
if (!(which_user==1 ? nodep->user1p() : nodep->user2p())) {
UndrivenVarEntry* entryp = new UndrivenVarEntry (nodep);
m_entryps.push_back(entryp);
nodep->user1p(entryp);
//UINFO(9," Associate u="<<which_user<<" "<<(void*)this<<" "<<nodep->name()<<endl);
m_entryps[which_user].push_back(entryp);
if (which_user==1) nodep->user1p(entryp);
else if (which_user==2) nodep->user2p(entryp);
else nodep->v3fatalSrc("Bad case");
return entryp;
} else {
UndrivenVarEntry* entryp = (UndrivenVarEntry*)(nodep->user1p());
UndrivenVarEntry* entryp = (UndrivenVarEntry*)(which_user==1 ? nodep->user1p() : nodep->user2p());
return entryp;
}
}
void warnAlwCombOrder(AstVarRef* nodep) {
AstVar* varp = nodep->varp();
if (!varp->isParam() && !varp->isGenVar() && !varp->isUsedLoopIdx()
&& !varp->fileline()->warnIsOff(V3ErrorCode::ALWCOMBORDER)) { // Warn only once per variable
nodep->v3warn(ALWCOMBORDER, "Always_comb variable driven after use: "<<nodep->prettyName());
varp->fileline()->modifyWarnOff(V3ErrorCode::ALWCOMBORDER, true); // Complain just once for any usage
}
}
// VISITORS
virtual void visit(AstVar* nodep, AstNUser*) {
UndrivenVarEntry* entryp = getEntryp (nodep);
if (nodep->isInput()
|| nodep->isSigPublic() || nodep->isSigUserRWPublic()
|| (m_taskp && (m_taskp->dpiImport() || m_taskp->dpiExport()))) {
entryp->drivenWhole();
}
if (nodep->isOutput()
|| nodep->isSigPublic() || nodep->isSigUserRWPublic()
|| nodep->isSigUserRdPublic()
|| (m_taskp && (m_taskp->dpiImport() || m_taskp->dpiExport()))) {
entryp->usedWhole();
for (int usr=1; usr<(m_alwaysp?3:2); ++usr) {
UndrivenVarEntry* entryp = getEntryp (nodep, usr);
if (nodep->isInput()
|| nodep->isSigPublic() || nodep->isSigUserRWPublic()
|| (m_taskp && (m_taskp->dpiImport() || m_taskp->dpiExport()))) {
entryp->drivenWhole();
}
if (nodep->isOutput()
|| nodep->isSigPublic() || nodep->isSigUserRWPublic()
|| nodep->isSigUserRdPublic()
|| (m_taskp && (m_taskp->dpiImport() || m_taskp->dpiExport()))) {
entryp->usedWhole();
}
}
// Discover variables used in bit definitions, etc
nodep->iterateChildren(*this);
@@ -263,10 +290,19 @@ private:
AstVarRef* varrefp = nodep->fromp()->castVarRef();
AstConst* constp = nodep->lsbp()->castConst();
if (varrefp && constp && !constp->num().isFourState()) {
UndrivenVarEntry* entryp = getEntryp (varrefp->varp());
int lsb = constp->toUInt();
if (m_markBoth || varrefp->lvalue()) entryp->drivenBit(lsb, nodep->width());
if (m_markBoth || !varrefp->lvalue()) entryp->usedBit(lsb, nodep->width());
for (int usr=1; usr<(m_alwaysp?3:2); ++usr) {
UndrivenVarEntry* entryp = getEntryp (varrefp->varp(), usr);
int lsb = constp->toUInt();
if (m_markBoth || varrefp->lvalue()) {
// Don't warn if already driven earlier as "a=0; if(a) a=1;" is fine.
if (usr==2 && m_alwaysp && entryp->isUsedNotDrivenBit(lsb, nodep->width())) {
UINFO(9," Select. Entryp="<<(void*)entryp<<endl);
warnAlwCombOrder(varrefp);
}
entryp->drivenBit(lsb, nodep->width());
}
if (m_markBoth || !varrefp->lvalue()) entryp->usedBit(lsb, nodep->width());
}
} else {
// else other varrefs handled as unknown mess in AstVarRef
nodep->iterateChildren(*this);
@@ -274,10 +310,18 @@ private:
}
virtual void visit(AstVarRef* nodep, AstNUser*) {
// Any variable
UndrivenVarEntry* entryp = getEntryp (nodep->varp());
bool fdrv = nodep->lvalue() && nodep->varp()->attrFileDescr(); // FD's are also being read from
if (m_markBoth || nodep->lvalue()) entryp->drivenWhole();
if (m_markBoth || !nodep->lvalue() || fdrv) entryp->usedWhole();
for (int usr=1; usr<(m_alwaysp?3:2); ++usr) {
UndrivenVarEntry* entryp = getEntryp (nodep->varp(), usr);
bool fdrv = nodep->lvalue() && nodep->varp()->attrFileDescr(); // FD's are also being read from
if (m_markBoth || nodep->lvalue()) {
if (usr==2 && m_alwaysp && entryp->isUsedNotDrivenAny()) {
UINFO(9," Full bus. Entryp="<<(void*)entryp<<endl);
warnAlwCombOrder(nodep);
}
entryp->drivenWhole();
}
if (m_markBoth || !nodep->lvalue() || fdrv) entryp->usedWhole();
}
}
// Don't know what black boxed calls do, assume in+out
@@ -288,6 +332,19 @@ private:
m_markBoth = prevMark;
}
virtual void visit(AstAlways* nodep, AstNUser*) {
AstAlways* prevAlwp = m_alwaysp;
{
AstNode::user2ClearTree();
if (nodep->keyword() == VAlwaysKwd::ALWAYS_COMB) UINFO(9," "<<nodep<<endl);
if (nodep->keyword() == VAlwaysKwd::ALWAYS_COMB) m_alwaysp = nodep;
else m_alwaysp = NULL;
nodep->iterateChildren(*this);
if (nodep->keyword() == VAlwaysKwd::ALWAYS_COMB) UINFO(9," Done "<<nodep<<endl);
}
m_alwaysp = prevAlwp;
}
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
AstNodeFTask* prevTaskp = m_taskp;
m_taskp = nodep;
@@ -315,12 +372,17 @@ public:
UndrivenVisitor(AstNetlist* nodep) {
m_markBoth = false;
m_taskp = NULL;
m_alwaysp = NULL;
nodep->accept(*this);
}
virtual ~UndrivenVisitor() {
for (vector<UndrivenVarEntry*>::iterator it = m_entryps.begin(); it != m_entryps.end(); ++it) {
for (vector<UndrivenVarEntry*>::iterator it = m_entryps[1].begin(); it != m_entryps[1].end(); ++it) {
(*it)->reportViolations();
delete (*it);
}
for (int usr=1; usr<3; ++usr) {
for (vector<UndrivenVarEntry*>::iterator it = m_entryps[usr].begin(); it != m_entryps[usr].end(); ++it) {
delete (*it);
}
}
}
};
+1 -1
View File
@@ -115,7 +115,7 @@ private:
m_forVarp = initAssp->lhsp()->castVarRef()->varp();
m_forVscp = initAssp->lhsp()->castVarRef()->varScopep();
if (nodep->castGenFor() && !m_forVarp->isGenVar()) {
nodep->v3error("Non-genvar used in generate for: "<<m_forVarp->name()<<endl);
nodep->v3error("Non-genvar used in generate for: "<<m_forVarp->prettyName()<<endl);
}
if (m_generate) V3Const::constifyParamsEdit(initAssp->rhsp()); // rhsp may change
AstConst* constInitp = initAssp->rhsp()->castConst();
+53 -25
View File
@@ -95,7 +95,9 @@ public:
WidthVP(int width, int widthMin, Stage stage)
: m_width(width), m_widthMin(widthMin), m_dtypep(NULL), m_stage(stage) {}
WidthVP(AstNodeDType* dtypep, Stage stage)
: m_width(0), m_widthMin(0), m_dtypep(dtypep), m_stage(stage) {}
: m_width(dtypep->width()), m_widthMin(dtypep->widthMin()), m_dtypep(dtypep), m_stage(stage) {}
WidthVP(AstNodeDType* dtypep, int width, int widthMin, Stage stage)
: m_width(width), m_widthMin(widthMin), m_dtypep(dtypep), m_stage(stage) {}
int width() const { return m_width; }
int widthMin() const { return m_widthMin?m_widthMin:m_width; }
AstNodeDType* dtypep() const { return m_dtypep; }
@@ -118,7 +120,6 @@ private:
AstFunc* m_funcp; // Current function
AstInitial* m_initialp; // Current initial block
AstAttrOf* m_attrp; // Current attribute
AstNodeDType* m_assDTypep; // Assign LHS data type for assignment pattern
bool m_doGenerate; // Do errors later inside generate statement
int m_dtTables; // Number of created data type tables
@@ -386,7 +387,7 @@ private:
int width = nodep->elementsConst();
if (width > (1<<28)) nodep->v3error("Width of bit range is huge; vector of over 1billion bits: 0x"<<hex<<width);
// Note width() not set on range; use elementsConst()
if (nodep->littleEndian()) {
if (nodep->littleEndian() && !nodep->backp()->castUnpackArrayDType()) {
nodep->v3warn(LITENDIAN,"Little bit endian vector: MSB < LSB of bit range: "<<nodep->lsbConst()<<":"<<nodep->msbConst());
}
}
@@ -804,6 +805,28 @@ private:
pushDeletep(nodep); nodep=NULL;
//if (debug()) newp->dumpTree(cout," CastOut: ");
}
virtual void visit(AstCastSize* nodep, AstNUser* vup) {
if (!nodep->rhsp()->castConst()) nodep->v3fatalSrc("Unsupported: Non-const cast of size");
//if (debug()) nodep->dumpTree(cout," CastPre: ");
int width = nodep->rhsp()->castConst()->toSInt();
if (width < 1) { nodep->v3error("Size-changing cast to zero or negative size"); width=1; }
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
AstBasicDType* underDtp = nodep->lhsp()->dtypep()->castBasicDType();
if (!underDtp) {
nodep->v3error("Unsupported: Size-changing cast on non-basic data type");
underDtp = nodep->findLogicBoolDType()->castBasicDType();
}
AstNodeDType* newDtp = (underDtp->keyword().isFourstate()
? nodep->findLogicDType(width, width, underDtp->numeric())
: nodep->findBitDType(width, width, underDtp->numeric()));
nodep->dtypep(newDtp);
AstNode* underp = nodep->lhsp()->unlinkFrBack();
nodep->replaceWith(underp);
if (underp->width()!=width) {
fixWidthExtend(underp, newDtp);
}
pushDeletep(nodep); nodep=NULL;
}
virtual void visit(AstVar* nodep, AstNUser* vup) {
//if (debug()) nodep->dumpTree(cout," InitPre: ");
// Must have deterministic constant width
@@ -970,6 +993,7 @@ private:
virtual void visit(AstEnumItem* nodep, AstNUser* vup) {
UINFO(5," ENUMITEM "<<nodep<<endl);
AstNodeDType* vdtypep = vup->c()->dtypep();
if (!vdtypep) nodep->v3fatalSrc("ENUMITEM not under ENUM");
nodep->dtypep(vdtypep);
if (nodep->valuep()) { // else the value will be assigned sequentially
int width = vdtypep->width(); // Always from parent type
@@ -1111,7 +1135,7 @@ private:
} else {
AstSel* newp = new AstSel(nodep->fileline(), nodep->fromp()->unlinkFrBack(),
memberp->lsb(), memberp->width());
newp->dtypep(memberp);
newp->dtypep(memberp->skipRefp()); // Must skip over the member to find the union; as the member may disappear later
newp->didWidth(true); // Don't replace dtype with basic type
UINFO(9," MEMBERSEL -> "<<newp<<endl);
nodep->replaceWith(newp);
@@ -1128,12 +1152,17 @@ private:
virtual void visit(AstPattern* nodep, AstNUser* vup) {
if (nodep->didWidthAndSet()) return;
UINFO(9,"PATTERN "<<nodep<<endl);
AstNodeDType* oldAssDTypep = m_assDTypep;
if (nodep->childDTypep()) nodep->dtypep(moveChildDTypeEdit(nodep)); // data_type '{ pattern }
if (!nodep->dtypep() && vup->c()->dtypep()) { // Get it from parent assignment/pin/etc
nodep->dtypep(vup->c()->dtypep());
}
AstNodeDType* vdtypep = nodep->dtypep();
if (!vdtypep) nodep->v3error("Unsupported/Illegal: Assignment pattern member not underneath a supported construct: "<<nodep->backp()->prettyTypeName());
{
if (!m_assDTypep) nodep->v3error("Unsupported/Illegal: Assignment pattern not underneath an assignment");
m_assDTypep = m_assDTypep->skipRefp();
UINFO(9," adtypep "<<m_assDTypep<<endl);
nodep->dtypep(m_assDTypep);
vdtypep = vdtypep->skipRefp();
nodep->dtypep(vdtypep);
UINFO(9," adtypep "<<vdtypep<<endl);
nodep->dtypep(vdtypep);
for (AstPatMember* patp = nodep->itemsp()->castPatMember(); patp; patp = patp->nextp()->castPatMember()) {
// Determine replication count, and replicate initial value as widths need to be individually determined
int times = visitPatMemberRep(patp);
@@ -1151,7 +1180,10 @@ private:
patp->unlinkFrBack();
}
}
if (AstNodeClassDType* classp = m_assDTypep->castNodeClassDType()) {
while (AstConstDType* classp = vdtypep->castConstDType()) {
vdtypep = classp->subDTypep()->skipRefp();
}
if (AstNodeClassDType* classp = vdtypep->castNodeClassDType()) {
// Due to "default" and tagged patterns, we need to determine
// which member each AstPatMember corresponds to before we can
// determine the dtypep for that PatMember's value, and then
@@ -1205,9 +1237,9 @@ private:
patp = it->second;
}
// Determine initial values
m_assDTypep = memp;
vdtypep = memp;
patp->dtypep(memp);
patp->accept(*this,WidthVP(patp->width(),patp->width(),BOTH).p());
patp->accept(*this,WidthVP(memp,BOTH).p());
// Convert to concat for now
if (!newp) newp = patp->lhsp()->unlinkFrBack();
else {
@@ -1223,16 +1255,16 @@ private:
else nodep->v3error("Assignment pattern with no members");
pushDeletep(nodep); nodep = NULL; // Deletes defaultp also, if present
} else {
nodep->v3error("Unsupported: Assignment pattern applies against non struct/union: "<<m_assDTypep->prettyTypeName());
nodep->v3error("Unsupported: Assignment pattern applies against non struct/union: "<<vdtypep->prettyTypeName());
}
}
m_assDTypep = oldAssDTypep;
}
virtual void visit(AstPatMember* nodep, AstNUser* vup) {
if (!nodep->dtypep()) nodep->v3fatalSrc("Pattern member type not assigned by AstPattern visitor");
if (!m_assDTypep) nodep->v3error("Unsupported/Illegal: Assignment pattern member not underneath an assignment");
AstNodeDType* vdtypep = vup->c()->dtypep();
if (!vdtypep) nodep->v3fatalSrc("Pattern member type not assigned by AstPattern visitor");
nodep->dtypep(vdtypep);
nodep->lhsp()->dtypeFrom(nodep);
nodep->iterateChildren(*this,WidthVP(nodep->dtypep()->width(),nodep->dtypep()->width(),BOTH).p());
nodep->iterateChildren(*this,WidthVP(nodep->dtypep(),BOTH).p());
widthCheck(nodep,"LHS",nodep->lhsp(),nodep->width(),nodep->width());
}
int visitPatMemberRep(AstPatMember* nodep) {
@@ -1329,14 +1361,12 @@ private:
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
// TOP LEVEL NODE
//if (debug()) nodep->dumpTree(cout," AssignPre: ");
AstNodeDType* oldAssDTypep = m_assDTypep;
{
//if (debug()) nodep->dumpTree(cout,"- assin: ");
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
if (!nodep->lhsp()->dtypep()) nodep->v3fatalSrc("How can LHS be untyped?");
if (!nodep->lhsp()->dtypep()->widthSized()) nodep->v3fatalSrc("How can LHS be unsized?");
m_assDTypep = nodep->lhsp()->dtypep();
nodep->rhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
nodep->rhsp()->iterateAndNext(*this,WidthVP(nodep->lhsp()->dtypep(),ANYSIZE,0,PRELIM).p());
//if (debug()) nodep->dumpTree(cout,"- assign: ");
if (!nodep->lhsp()->isDouble() && nodep->rhsp()->isDouble()) {
spliceCvtS(nodep->rhsp(), false); // Round RHS
@@ -1347,7 +1377,7 @@ private:
if (awidth==0) {
awidth = nodep->rhsp()->width(); // Parameters can propagate by unsized assignment
}
nodep->rhsp()->iterateAndNext(*this,WidthVP(awidth,awidth,FINAL).p());
nodep->rhsp()->iterateAndNext(*this,WidthVP(nodep->lhsp()->dtypep(),awidth,awidth,FINAL).p());
nodep->dtypeFrom(nodep->lhsp());
nodep->dtypeChgWidth(awidth,awidth); // We know the assign will truncate, so rather
// than using "width" and have the optimizer truncate the result, we do
@@ -1356,7 +1386,6 @@ private:
widthCheck(nodep,"Assign RHS",nodep->rhsp(),awidth,awidth);
//if (debug()) nodep->dumpTree(cout," AssignOut: ");
}
m_assDTypep = oldAssDTypep;
}
virtual void visit(AstSFormatF* nodep, AstNUser*) {
// Excludes NodeDisplay, see below
@@ -1681,7 +1710,7 @@ private:
handle.relink(newp);
pinp = newp;
}
pinp->accept(*this,WidthVP(portp->width(),portp->widthMin(),PRELIM).p()); pinp=NULL;
pinp->accept(*this,WidthVP(portp->dtypep(),PRELIM).p()); pinp=NULL;
} else if (accept_mode==1) {
// Change data types based on above accept completion
if (portp->isDouble()) {
@@ -1689,7 +1718,7 @@ private:
}
} else if (accept_mode==2) {
// Do PRELIM again, because above accept may have exited early due to node replacement
pinp->accept(*this,WidthVP(portp->width(),portp->widthMin(),BOTH).p());
pinp->accept(*this,WidthVP(portp->dtypep(),BOTH).p());
if ((portp->isOutput() || portp->isInout())
&& pinp->width() != portp->width()) {
pinp->v3error("Unsupported: Function output argument '"<<portp->prettyName()<<"'"
@@ -2585,7 +2614,6 @@ public:
m_funcp = NULL;
m_initialp = NULL;
m_attrp = NULL;
m_assDTypep = NULL;
m_doGenerate = doGenerate;
m_dtTables = 0;
}
+1 -1
View File
@@ -217,7 +217,7 @@ private:
fromp,
new AstMul(nodep->fileline(),
new AstConst(nodep->fileline(),AstConst::Unsized32(),elwidth),
newSubLsbOf(rhsp, fromRange)),
subp),
new AstConst (nodep->fileline(),AstConst::Unsized32(),elwidth));
newp->declRange(fromRange);
newp->declElWidth(elwidth);
+33 -23
View File
@@ -32,7 +32,7 @@
extern void yyerror(const char*);
extern void yyerrorf(const char* format, ...);
#define STATE_VERILOG_RECENT S09 // State name for most recent Verilog Version
#define STATE_VERILOG_RECENT S12 // State name for most recent Verilog Version
#define PARSEP V3ParseImp::parsep()
#define SYMP PARSEP->symp()
@@ -135,7 +135,7 @@ void yyerrorf(const char* format, ...) {
%a 15000
%o 25000
%s V95 V01 V05 S05 S09
%s V95 V01 V05 S05 S09 S12
%s STRING ATTRMODE TABLE
%s VA5 SA9 PSL VLT
%s SYSCHDR SYSCINT SYSCIMP SYSCIMPH SYSCCTOR SYSCDTOR
@@ -171,7 +171,7 @@ word [a-zA-Z0-9_]+
/************************************************************************/
/* Verilog 1995 */
<V95,V01,V05,VA5,S05,S09,SA9,PSL>{
<V95,V01,V05,VA5,S05,S09,S12,SA9,PSL>{
{ws} { } /* otherwise ignore white-space */
{crnl} { NEXTLINE(); } /* Count line numbers */
/* Extensions to Verilog set, some specified by PSL */
@@ -344,7 +344,7 @@ word [a-zA-Z0-9_]+
}
/* Verilog 2001 */
<V01,V05,VA5,S05,S09,SA9,PSL>{
<V01,V05,VA5,S05,S09,S12,SA9,PSL>{
/* System Tasks */
"$signed" { FL; return yD_SIGNED; }
"$unsigned" { FL; return yD_UNSIGNED; }
@@ -375,13 +375,13 @@ word [a-zA-Z0-9_]+
}
/* Verilog 2005 */
<V05,S05,S09,SA9,PSL>{
<V05,S05,S09,S12,SA9,PSL>{
/* Keywords */
"uwire" { FL; return yWIRE; }
}
/* System Verilog 2005 */
<S05,S09,PSL>{
<S05,S09,S12,PSL>{
/* System Tasks */
"$bits" { FL; return yD_BITS; }
"$clog2" { FL; return yD_CLOG2; }
@@ -403,9 +403,9 @@ word [a-zA-Z0-9_]+
"$warning" { FL; return yD_WARNING; }
/* SV2005 Keywords */
"$unit" { FL; return yD_UNIT; } /* Yes, a keyword, not task */
"always_comb" { FL; return yALWAYS; }
"always_ff" { FL; return yALWAYS; }
"always_latch" { FL; return yALWAYS; }
"always_comb" { FL; return yALWAYS_COMB; }
"always_ff" { FL; return yALWAYS_FF; }
"always_latch" { FL; return yALWAYS_LATCH; }
"bind" { FL; return yBIND; }
"bit" { FL; return yBIT; }
"break" { FL; return yBREAK; }
@@ -498,7 +498,7 @@ word [a-zA-Z0-9_]+
}
/* SystemVerilog 2005 ONLY not PSL; different rules for PSL as specified below */
<S05,S09>{
<S05,S09,S12>{
/* Keywords */
"assert" { FL; return yASSERT; }
"const" { FL; return yCONST__LEX; }
@@ -513,7 +513,7 @@ word [a-zA-Z0-9_]+
}
/* SystemVerilog 2009 */
<S09,PSL>{
<S09,S12,PSL>{
/* Keywords */
"global" { FL; return yGLOBAL__LEX; }
"unique0" { FL; return yUNIQUE0; }
@@ -541,8 +541,17 @@ word [a-zA-Z0-9_]+
"weak" { yyerrorf("Unsupported: SystemVerilog 2009 reserved word not implemented: %s",yytext); }
}
/* System Verilog 2012 */
<S12,PSL>{
/* Keywords */
"implements" { yyerrorf("Unsupported: SystemVerilog 2012 reserved word not implemented: %s",yytext); }
"interconnect" { yyerrorf("Unsupported: SystemVerilog 2012 reserved word not implemented: %s",yytext); }
"nettype" { yyerrorf("Unsupported: SystemVerilog 2012 reserved word not implemented: %s",yytext); }
"soft" { yyerrorf("Unsupported: SystemVerilog 2012 reserved word not implemented: %s",yytext); }
}
/* Default PLI rule */
<V95,V01,V05,VA5,S05,S09,SA9,PSL>{
<V95,V01,V05,VA5,S05,S09,S12,SA9,PSL>{
"$"[a-zA-Z_$][a-zA-Z0-9_$]* { string str (yytext,yyleng);
yylval.strp = PARSEP->newString(AstNode::encodeName(str));
// Lookup unencoded name including the $, to avoid hitting normal signals
@@ -649,7 +658,7 @@ word [a-zA-Z0-9_]+
/* PSL */
/*Entry into PSL; mode change */
<V95,V01,V05,VA5,S05,S09,SA9>{
<V95,V01,V05,VA5,S05,S09,S12,SA9>{
"psl" { yy_push_state(PSL); FL; return yPSL; }
}
@@ -738,7 +747,7 @@ word [a-zA-Z0-9_]+
/* Meta comments */
/* Converted from //{cmt}verilator ...{cmt} by preprocessor */
<V95,V01,V05,VA5,S05,S09,SA9,PSL>{
<V95,V01,V05,VA5,S05,S09,S12,SA9,PSL>{
"/*verilator"{ws}*"*/" {} /* Ignore empty comments, may be `endif // verilator */
"/*verilator clock_enable*/" { FL; return yVL_CLOCK_ENABLE; }
"/*verilator coverage_block_off*/" { FL; return yVL_COVERAGE_BLOCK_OFF; }
@@ -773,11 +782,11 @@ word [a-zA-Z0-9_]+
/************************************************************************/
/* Single character operator thingies */
<V95,V01,V05,VA5,S05,S09,SA9>{
<V95,V01,V05,VA5,S05,S09,S12,SA9>{
"{" { FL; return yytext[0]; }
"}" { FL; return yytext[0]; }
}
<V95,V01,V05,VA5,S05,S09,SA9,PSL>{
<V95,V01,V05,VA5,S05,S09,S12,SA9,PSL>{
"!" { FL; return yytext[0]; }
"#" { FL; return yytext[0]; }
"$" { FL; return yytext[0]; }
@@ -809,7 +818,7 @@ word [a-zA-Z0-9_]+
/* Operators and multi-character symbols */
/* Verilog 1995 Operators */
<V95,V01,V05,VA5,S05,S09,SA9,PSL>{
<V95,V01,V05,VA5,S05,S09,S12,SA9,PSL>{
"&&" { FL; return yP_ANDAND; }
"||" { FL; return yP_OROR; }
"<=" { FL; return yP_LTE; }
@@ -831,7 +840,7 @@ word [a-zA-Z0-9_]+
}
/* Verilog 2001 Operators */
<V01,V05,VA5,S05,S09,SA9,PSL>{
<V01,V05,VA5,S05,S09,S12,SA9,PSL>{
"<<<" { FL; return yP_SLEFT; }
">>>" { FL; return yP_SSRIGHT; }
"**" { FL; return yP_POW; }
@@ -841,7 +850,7 @@ word [a-zA-Z0-9_]+
}
/* SystemVerilog Operators */
<S05,S09>{
<S05,S09,S12>{
"'" { FL; return yP_TICK; }
"'{" { FL; return yP_TICKBRA; }
"==?" { FL; return yP_WILDEQUAL; }
@@ -890,7 +899,7 @@ word [a-zA-Z0-9_]+
}
/* Identifiers and numbers */
<V95,V01,V05,VA5,S05,S09,SA9,PSL,VLT>{
<V95,V01,V05,VA5,S05,S09,S12,SA9,PSL,VLT>{
{escid} { FL; yylval.strp = PARSEP->newString
(AstNode::encodeName(string(yytext+1))); // +1 to skip the backslash
return yaID__LEX;
@@ -966,7 +975,7 @@ word [a-zA-Z0-9_]+
/************************************************************************/
/* Attributes */
/* Note simulators vary in support for "(* /_*something*_/ foo*)" where _ doesn't exist */
<V95,V01,V05,VA5,S05,S09,SA9>{
<V95,V01,V05,VA5,S05,S09,S12,SA9>{
"(*"({ws}|{crnl})*({id}|{escid}) { yymore(); yy_push_state(ATTRMODE); } // Doesn't match (*), but (* attr_spec
}
@@ -983,7 +992,7 @@ word [a-zA-Z0-9_]+
/* Preprocessor */
/* Common for all SYSC header states */
/* OPTIMIZE: we return one per line, make it one for the entire block */
<V95,V01,V05,VA5,S05,S09,SA9,PSL,VLT,SYSCHDR,SYSCINT,SYSCIMP,SYSCIMPH,SYSCCTOR,SYSCDTOR,IGNORE>{
<V95,V01,V05,VA5,S05,S09,S12,SA9,PSL,VLT,SYSCHDR,SYSCINT,SYSCIMP,SYSCIMPH,SYSCCTOR,SYSCDTOR,IGNORE>{
"`accelerate" { } // Verilog-XL compatibility
"`autoexpand_vectornets" { } // Verilog-XL compatibility
"`celldefine" { PARSEP->inCellDefine(true); }
@@ -1027,6 +1036,7 @@ word [a-zA-Z0-9_]+
"`begin_keywords"[ \t]*\"VAMS[-0-9.]*\" { yy_push_state(VA5); PARSEP->pushBeginKeywords(YY_START); }
"`begin_keywords"[ \t]*\"1800-2005\" { yy_push_state(S05); PARSEP->pushBeginKeywords(YY_START); }
"`begin_keywords"[ \t]*\"1800-2009\" { yy_push_state(S09); PARSEP->pushBeginKeywords(YY_START); }
"`begin_keywords"[ \t]*\"1800-2012\" { yy_push_state(S12); PARSEP->pushBeginKeywords(YY_START); }
"`begin_keywords"[ \t]*\"1800+VAMS\" { yy_push_state(SA9); PARSEP->pushBeginKeywords(YY_START); }
"`end_keywords" { yy_pop_state(); if (!PARSEP->popBeginKeywords()) yyerrorf("`end_keywords when not inside `begin_keywords block"); }
@@ -1058,7 +1068,7 @@ word [a-zA-Z0-9_]+
/************************************************************************/
/* Default rules - leave last */
<V95,V01,V05,VA5,S05,S09,SA9,PSL,VLT>{
<V95,V01,V05,VA5,S05,S09,S12,SA9,PSL,VLT>{
"`"[a-zA-Z_0-9]+ { FL; yyerrorf("Define or directive not defined: %s",yytext); }
"//"[^\n]* { } /* throw away single line comments */
. { FL; return yytext[0]; } /* return single char ops. */
+16 -8
View File
@@ -273,6 +273,9 @@ class AstSenTree;
// Double underscores "yX__Y" means token X followed by Y,
// and "yX__ETC" means X folled by everything but Y(s).
%token<fl> yALWAYS "always"
%token<fl> yALWAYS_FF "always_ff"
%token<fl> yALWAYS_COMB "always_comb"
%token<fl> yALWAYS_LATCH "always_latch"
%token<fl> yAND "and"
%token<fl> yASSERT "assert"
%token<fl> yASSIGN "assign"
@@ -651,7 +654,7 @@ description: // ==IEEE: description
| program_declaration { }
| package_declaration { }
| package_item { if ($1) GRAMMARP->unitPackage($1->fileline())->addStmtp($1); }
//UNSUP bind_directive { }
| bind_directive { if ($1) GRAMMARP->unitPackage($1->fileline())->addStmtp($1); }
// unsupported // IEEE: config_declaration
// // Verilator only
| vltItem { }
@@ -1549,7 +1552,10 @@ module_common_item<nodep>: // ==IEEE: module_common_item
| final_construct { $$ = $1; }
// // IEEE: always_construct
// // Verilator only - event_control attached to always
| yALWAYS event_controlE stmtBlock { $$ = new AstAlways($1,$2,$3); }
| yALWAYS event_controlE stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS, $2,$3); }
| yALWAYS_FF event_controlE stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_FF, $2,$3); }
| yALWAYS_COMB event_controlE stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_COMB, $2,$3); }
| yALWAYS_LATCH event_controlE stmtBlock { $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_LATCH, $2,$3); }
| loop_generate_construct { $$ = $1; }
| conditional_generate_construct { $$ = $1; }
// // Verilator only
@@ -2184,6 +2190,7 @@ statementVerilatorPragmas<nodep>:
foperator_assignment<nodep>: // IEEE: operator_assignment (for first part of expression)
fexprLvalue '=' delayE expr { $$ = new AstAssign($2,$1,$4); }
| fexprLvalue '=' yD_FOPEN '(' expr ')' { $$ = NULL; $3->v3error("Unsupported: $fopen with multichannel descriptor. Add ,\"w\" as second argument to open a file descriptor."); }
| fexprLvalue '=' yD_FOPEN '(' expr ',' expr ')' { $$ = new AstFOpen($3,$1,$5,$7); }
//
//UNSUP ~f~exprLvalue '=' delay_or_event_controlE expr { UNSUP }
@@ -2203,10 +2210,10 @@ foperator_assignment<nodep>: // IEEE: operator_assignment (for first part of exp
finc_or_dec_expression<nodep>: // ==IEEE: inc_or_dec_expression
//UNSUP: Generic scopes in incrementes
varRefBase yP_PLUSPLUS { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true),new AstConst($2,V3Number($2,"'b1")))); }
| varRefBase yP_MINUSMINUS { $$ = new AstAssign($2,$1,new AstSub ($2,$1->cloneTree(true),new AstConst($2,V3Number($2,"'b1")))); }
| yP_PLUSPLUS varRefBase { $$ = new AstAssign($1,$2,new AstAdd ($1,$2->cloneTree(true),new AstConst($1,V3Number($1,"'b1")))); }
| yP_MINUSMINUS varRefBase { $$ = new AstAssign($1,$2,new AstSub ($1,$2->cloneTree(true),new AstConst($1,V3Number($1,"'b1")))); }
fexprLvalue yP_PLUSPLUS { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true),new AstConst($2,V3Number($2,"'b1")))); }
| fexprLvalue yP_MINUSMINUS { $$ = new AstAssign($2,$1,new AstSub ($2,$1->cloneTree(true),new AstConst($2,V3Number($2,"'b1")))); }
| yP_PLUSPLUS fexprLvalue { $$ = new AstAssign($1,$2,new AstAdd ($1,$2->cloneTree(true),new AstConst($1,V3Number($1,"'b1")))); }
| yP_MINUSMINUS fexprLvalue { $$ = new AstAssign($1,$2,new AstSub ($1,$2->cloneTree(true),new AstConst($1,V3Number($1,"'b1")))); }
;
//************************************************
@@ -2313,7 +2320,7 @@ patternKey<nodep>: // IEEE: merge structure_pattern_key, array_pattern_key, ass
| yaID__ETC { $$ = new AstText($<fl>1,*$1); }
;
assignment_pattern<nodep>: // ==IEEE: assignment_pattern
assignment_pattern<patternp>: // ==IEEE: assignment_pattern
// This doesn't match the text of the spec. I think a : is missing, or example code needed
// yP_TICKBRA constExpr exprList '}' { $$="'{"+$2+" "+$3"}"; }
// // "'{ const_expression }" is same as patternList with one entry
@@ -2824,6 +2831,7 @@ expr<nodep>: // IEEE: part of expression/constant_expression/primary
// // Spec only allows primary with addition of a type reference
// // We'll be more general, and later assert LHS was a type.
//UNSUP ~l~expr yP_TICK '(' expr ')' { UNSUP }
| yaINTNUM yP_TICK '(' expr ')' { $$ = new AstCastSize($2,$4,new AstConst($1->fileline(),*$1)); }
//
// // IEEE: assignment_pattern_expression
// // IEEE: streaming_concatenation
@@ -2875,7 +2883,7 @@ exprOkLvalue<nodep>: // expression that's also OK to use as a variable_lvalue
// // IEEE: [ assignment_pattern_expression_type ] == [ ps_type_id /ps_paremeter_id/data_type]
// // We allow more here than the spec requires
//UNSUP ~l~exprScope assignment_pattern { UNSUP }
//UNSUP data_type assignment_pattern { UNSUP }
| data_type assignment_pattern { $$ = $2; $2->childDTypep($1); }
| assignment_pattern { $$ = $1; }
//
//UNSUP streaming_concatenation { UNSUP }
+2
View File
@@ -365,6 +365,7 @@ sub new {
'v3' => 0,
verilator_flags => ["-cc",
"-Mdir $self->{obj_dir}",
"-OD", # As currently disabled unless -O3
"--debug-check"],
verilator_flags2 => [],
verilator_make_gcc => 1,
@@ -1503,6 +1504,7 @@ sub sig_child {}
sub kill_tree_all {}
sub wait_all {}
sub ready {}
sub running {}
#######################################################################
1;
+1 -1
View File
@@ -14,9 +14,9 @@ use Cwd qw(chdir);
my @args = @ARGV;
chdir("$FindBin::Bin/..");
$ENV{PWD} = Cwd::getcwd(); # Else chdir leaves the .. which confuses later commands
@args = map { s!.*test_regress/!!; $_; } @args;
print "cd $ENV{PWD} && $FindBin::Bin/bootstrap.pl ",join(' ',@args),"\n";
exec("./driver.pl", @args);
die;
+25 -5
View File
@@ -3,7 +3,14 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2012 by Wilson Snyder.
module t;
bit a_finished;
bit b_finished;
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
wire [31:0] o;
wire si = 1'b0;
@@ -18,6 +25,13 @@ module t;
// Inputs
.si (si));
always @ (posedge clk) begin
if (!a_finished) $stop;
if (!b_finished) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
module InstModule (
@@ -28,10 +42,7 @@ module InstModule (
endmodule
program Prog (input si);
initial begin
$write("*-* All Finished *-*\n");
$finish;
end
initial a_finished = 1'b1;
endprogram
module ExampInst (o,i);
@@ -55,3 +66,12 @@ module ExampInst (o,i);
endmodule
// Check bind at top level
bind InstModule Prog2 instProg2
(/*AUTOBIND*/
.si (si));
// Check program declared after bind
program Prog2 (input si);
initial b_finished = 1'b1;
endprogram
+3
View File
@@ -10,11 +10,14 @@ module t;
mc_t o;
logic [15:0] allones = 16'hffff;
initial begin
if (4'shf > 4'sh0) $stop;
if (signed'(4'hf) > 4'sh0) $stop;
if (4'hf < 4'h0) $stop;
if (unsigned'(4'shf) < 4'h0) $stop;
if (4'(allones) !== 4'hf) $stop;
o = tocast_t'(4'b1);
if (o != 4'b1) $stop;
-1
View File
@@ -17,7 +17,6 @@ compile (
%Warning-CDCRSTLOGIC: See details in obj_dir/t_cdc_async_bad/Vt_cdc_async_bad__cdc.txt
%Warning-CDCRSTLOGIC: t/t_cdc_async_bad.v:\d+: Logic in path that feeds async reset, via signal: v.rst6a_bad_n
%Warning-CDCRSTLOGIC: t/t_cdc_async_bad.v:\d+: Logic in path that feeds async reset, via signal: v.rst6b_bad_n
%Warning-CDCRSTLOGIC: t/t_cdc_async_bad.v:\d+: Logic in path that feeds async reset, via signal: v.rst3_bad_n
%Error: Exiting due to.*',
);
+5 -2
View File
@@ -21,9 +21,8 @@ double sc_time_stamp () {
VM_PREFIX* topp = NULL;
void clockit(int clk1, int clk0) {
#ifdef T_CLK_2IN_VEC
topp->clks = clk1<<1 | clk0;
#else
#ifndef T_CLK_2IN_VEC
topp->c1 = clk1;
topp->c0 = clk0;
#endif
@@ -38,6 +37,7 @@ int main (int argc, char *argv[]) {
topp = new VM_PREFIX;
topp->check = 0;
clockit(0,0);
main_time+=10;
Verilated::debug(0);
@@ -49,6 +49,9 @@ int main (int argc, char *argv[]) {
clockit(1, 1);
clockit(1, 0);
clockit(0, 0);
clockit(0, 1);
clockit(1, 0);
clockit(0, 0);
}
topp->check = 1;
clockit(0,0);
+7 -9
View File
@@ -7,18 +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.
$Self->{vlt} or $Self->skip("Verilator only test");
compile (
make_top_shell => 0,
make_main => 0,
v_flags2 => ["$Self->{t_dir}/$Self->{name}.cpp"],
verilator_flags2 => ["--exe"],
);
make_top_shell => 0,
make_main => 0,
verilator_flags2 => ["--exe","$Self->{t_dir}/$Self->{name}.cpp"],
vcs_flags2 => ['-assert'],
);
execute (
check_finished=>1,
);
check_finished=>1,
);
ok(1);
1;
+111 -19
View File
@@ -3,19 +3,75 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2010 by Wilson Snyder.
module t (
`ifdef T_CLK_2IN_VEC
input [1:0] clks,
`ifndef VERILATOR
module t;
/*AUTOREGINPUT*/
// Beginning of automatic reg inputs (for undeclared instantiated-module inputs)
reg c0; // To t2 of t2.v
reg c1; // To t2 of t2.v
reg check; // To t2 of t2.v
reg [1:0] clks; // To t2 of t2.v
// End of automatics
t2 t2 (/*AUTOINST*/
// Inputs
.clks (clks[1:0]),
.c0 (c0),
.c1 (c1),
.check (check));
task clockit (input v1, v0);
c1 = v1;
c0 = v0;
clks[1] = v1;
clks[0] = v0;
`ifdef TEST_VERBOSE $write("[%0t] c1=%x c0=%x\n", $time,v0,v1); `endif
#1;
endtask
initial begin
check = '0;
c0 = '0;
c1 = '0;
clks = '0;
#1
t2.clear();
#10;
for (int i=0; i<2; i++) begin
clockit(0, 0);
clockit(0, 0);
clockit(0, 1);
clockit(1, 1);
clockit(0, 0);
clockit(1, 1);
clockit(1, 0);
clockit(0, 0);
clockit(1, 0);
clockit(0, 1);
clockit(0, 0);
end
check = 1;
clockit(0, 0);
end
endmodule
`endif
`ifdef VERILATOR
`define t2 t
`else
`define t2 t2
`endif
module `t2 (
input [1:0] clks,
input c0,
input c1,
`endif
input check
);
`ifdef T_CLK_2IN_VEC
wire c0 = clks[0];
wire c1 = clks[1];
wire clk0 = clks[0];
wire clk1 = clks[1];
`else
wire clk0 = c0;
wire clk1 = c1;
`endif
integer p0 = 0;
@@ -24,46 +80,82 @@ module t (
integer n0 = 0;
integer n1 = 0;
integer n01 = 0;
integer vp = 0;
integer vn = 0;
integer vpn = 0;
task clear;
`ifdef TEST_VERBOSE $display("[%0t] clear\n",$time); `endif
p0 = 0;
p1 = 0;
p01 = 0;
n0 = 0;
n1 = 0;
n01 = 0;
vp = 0;
vn = 0;
vpn = 0;
endtask
`define display_counts(text) begin \
$write("[%0t] ",$time); \
`ifdef T_CLK_2IN_VEC $write(" 2v "); `endif \
$write(text); \
$write(": %0d %0d %0d %0d %0d %0d\n", p0, p1, p01, n0, n1, n01); \
$write(": %0d %0d %0d %0d %0d %0d %0d %0d %0d\n", p0, p1, p01, n0, n1, n01, vp, vn, vpn); \
end
always @ (posedge c0) begin
always @ (posedge clk0) begin
p0 = p0 + 1; // Want blocking, so don't miss clock counts
`ifdef TEST_VERBOSE `display_counts("posedge 0"); `endif
end
always @ (posedge c1) begin
always @ (posedge clk1) begin
p1 = p1 + 1;
`ifdef TEST_VERBOSE `display_counts("posedge 1"); `endif
end
always @ (posedge c0 or posedge c1) begin
always @ (posedge clk0 or posedge clk1) begin
p01 = p01 + 1;
`ifdef TEST_VERBOSE `display_counts("posedge *"); `endif
end
always @ (negedge c0) begin
always @ (negedge clk0) begin
n0 = n0 + 1;
`ifdef TEST_VERBOSE `display_counts("negedge 0"); `endif
end
always @ (negedge c1) begin
always @ (negedge clk1) begin
n1 = n1 + 1;
`ifdef TEST_VERBOSE `display_counts("negedge 1"); `endif
end
always @ (negedge c0 or negedge c1) begin
always @ (negedge clk0 or negedge clk1) begin
n01 = n01 + 1;
`ifdef TEST_VERBOSE `display_counts("negedge *"); `endif
end
`ifndef VERILATOR
always @ (posedge clks) begin
vp = vp + 1;
`ifdef TEST_VERBOSE `display_counts("pos vec"); `endif
end
always @ (negedge clks) begin
vn = vn + 1;
`ifdef TEST_VERBOSE `display_counts("neg vec"); `endif
end
always @ (posedge clks or negedge clks) begin
vpn = vpn + 1;
`ifdef TEST_VERBOSE `display_counts("or vec"); `endif
end
`endif
always @ (posedge check) begin
if (p0!=4) $stop;
if (p1!=4) $stop;
if (p01!=6) $stop;
if (n0!=4) $stop;
if (n1!=4) $stop;
if (n01!=6) $stop;
if (p0!=6) $stop;
if (p1!=6) $stop;
if (p01!=10) $stop;
if (n0!=6) $stop;
if (n1!=6) $stop;
if (n01!=10) $stop;
`ifndef VERILATOR
if (vp!=6) $stop;
if (vn!=6) $stop;
if (vpn!=12) $stop;
`endif
$write("*-* All Finished *-*\n");
end
+2 -4
View File
@@ -9,13 +9,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
top_filename("t/t_clk_2in.v");
$Self->{vlt} or $Self->skip("Verilator only test");
compile (
make_top_shell => 0,
make_main => 0,
v_flags2 => ["+define+T_CLK_2IN_VEC=1 $Self->{t_dir}/t_clk_2in.cpp"],
verilator_flags2 => ["--exe"],
v_flags2 => ["+define+T_CLK_2IN_VEC=1"],
verilator_flags2 => ["--exe $Self->{t_dir}/t_clk_2in.cpp"],
);
execute (
+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 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 => ["--stats"],
);
if ($Self->{vlt}) {
file_grep ($Self->{stats}, qr/Optimizations, Gate sigs deduped\s+(\d+)/i, 4);
}
ok(1);
1;
+61
View File
@@ -0,0 +1,61 @@
// DESCRIPTION: Verilator: Dedupe optimization test.
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
// Contributed 2012 by Varun Koyyalagunta, Centaur Technology.
module t(res,d,clk,en);
output res;
input d,en,clk;
wire q0,q1,q2,q3;
flop_gated_latch f0(q0,d,clk,en);
flop_gated_latch f1(q1,d,clk,en);
flop_gated_flop f2(q2,d,clk,en);
flop_gated_flop f3(q3,d,clk,en);
assign res = (q0 + q1) * (q2 - q3);
endmodule
module flop_gated_latch(q,d,clk,en);
input d, clk, en;
output q;
wire gated_clock;
clock_gate_latch clock_gate(gated_clock, clk, en);
always @(posedge gated_clock) begin
q <= d;
end
endmodule
module flop_gated_flop(q,d,clk,en);
input d, clk, en;
output q;
wire gated_clock;
clock_gate_flop clock_gate(gated_clock, clk, en);
always @(posedge gated_clock) begin
q <= d;
end
endmodule
module clock_gate_latch (gated_clk, clk, clken);
output gated_clk;
input clk, clken;
reg clken_latched /*verilator clock_enable*/;
assign gated_clk = clk & clken_latched ;
wire clkb = ~clk;
always @(clkb or clken)
if(clkb) clken_latched = clken;
endmodule
module clock_gate_flop (gated_clk, clk, clken);
output gated_clk;
input clk, clken;
reg clken_r /*verilator clock_enable*/;
assign gated_clk = clk & clken_r ;
always @(negedge clk)
clken_r <= clken;
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 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 (
verilator_flags2 => ["--stats"],
);
if ($Self->{vlt}) {
file_grep ($Self->{stats}, qr/Optimizations, Gate sigs deduped\s+(\d+)/i, 6);
}
ok(1);
1;
+123
View File
@@ -0,0 +1,123 @@
// DESCRIPTION: Verilator: Dedupe optimization test.
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
// Contributed 2012 by Varun Koyyalagunta, Centaur Technology.
//
// Test consists of the follow logic tree, which has many obvious
// places for dedupe:
/*
output
+
--------------/ \--------------
/ \
+ +
----/ \----- ----/ \----
/ + / +
+ / \ + / \
-/ \- a b -/ \- a b
/ \ / \
+ + + +
/ \ / \ / \ / \
a b c d a b c d
*/
module t(sum,a,b,c,d,clk);
output sum;
input a,b,c,d,clk;
wire left,right;
add add(sum,left,right,clk);
l l(left,a,b,c,d,clk);
r r(right,a,b,c,d,clk);
endmodule
module l(sum,a,b,c,d,clk);
output sum;
input a,b,c,d,clk;
wire left, right;
add add(sum,left,right,clk);
ll ll(left,a,b,c,d,clk);
lr lr(right,a,b,c,d,clk);
endmodule
module ll(sum,a,b,c,d,clk);
output sum;
input a,b,c,d,clk;
wire left, right;
add add(sum,left,right,clk);
lll lll(left,a,b,c,d,clk);
llr llr(right,a,b,c,d,clk);
endmodule
module lll(sum,a,b,c,d,clk);
output sum;
input a,b,c,d,clk;
add add(sum,a,b,clk);
endmodule
module llr(sum,a,b,c,d,clk);
output sum;
input a,b,c,d,clk;
add add(sum,c,d,clk);
endmodule
module lr(sum,a,b,c,d,clk);
output sum;
input a,b,c,d,clk;
add add(sum,a,b,clk);
endmodule
module r(sum,a,b,c,d,clk);
output sum;
input a,b,c,d,clk;
wire left, right;
add add(sum,left,right,clk);
rl rl(left,a,b,c,d,clk);
rr rr(right,a,b,c,d,clk);
endmodule
module rr(sum,a,b,c,d,clk);
output sum;
input a,b,c,d,clk;
add add(sum,a,b,clk);
endmodule
module rl(sum,a,b,c,d,clk);
output sum;
input a,b,c,d,clk;
wire left, right;
add add(sum,left,right,clk);
rll rll(left,a,b,c,d,clk);
rlr rlr(right,a,b,c,d,clk);
endmodule
module rll(sum,a,b,c,d,clk);
output sum;
input a,b,c,d,clk;
add2 add(sum,a,b,clk);
endmodule
module rlr(sum,a,b,c,d,clk);
output sum;
input a,b,c,d,clk;
add2 add(sum,c,d,clk);
endmodule
module add(sum,x,y,clk);
output sum;
input x,y,clk;
reg t1,t2;
always @(posedge clk) begin
sum <= x + y;
end
endmodule
module add2(sum,x,y,clk);
output sum;
input x,y,clk;
reg t1,t2;
always @(posedge clk) begin
sum <= x + y;
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 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 (
verilator_flags2 => ["-Wno-UNOPTFLAT"]
);
execute (
check_finished=>1,
);
ok(1);
1;
+41
View File
@@ -0,0 +1,41 @@
// DESCRIPTION: Verilator: Simple test of unoptflat
//
// Trigger the DETECTARRAY error.
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Jeremy Bennett.
localparam ID_MSB = 1;
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
typedef struct packed {
logic [ID_MSB:0] id;
} context_t;
context_t tsb;
assign tsb.id = {tsb.id[0], clk};
initial begin
tsb.id = 0;
end
always @(posedge clk or negedge clk) begin
`ifdef TEST_VERBOSE
$write("tsb.id = %x\n", tsb.id);
`endif
if (tsb.id[1] != 0) begin
$write("*-* All Finished *-*\n");
$finish;
end
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 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 (
verilator_flags2 => ["-Wno-UNOPTFLAT"]
);
execute (
check_finished=>1,
);
ok(1);
1;
+43
View File
@@ -0,0 +1,43 @@
// DESCRIPTION: Verilator: Simple test of unoptflat
//
// This should trigger the DETECTARRAY error like t_detectarray_1.v, but in
// fact it casuses a broken link error. The only difference is that the struct
// is defined using a constant rather than a localparam.
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Jeremy Bennett.
localparam ID_MSB = 1;
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
typedef struct packed {
logic [1:0] id;
} context_t;
context_t tsb;
assign tsb.id = {tsb.id[0], clk};
initial begin
tsb.id = 0;
end
always @(posedge clk or negedge clk) begin
`ifdef TEST_VERBOSE
$write("tsb.id = %x\n", tsb.id);
`endif
if (tsb.id[1] != 0) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
+4 -1
View File
@@ -54,9 +54,12 @@ sub printfll {
my %names;
foreach my $line (split /\n/, $grep) {
next if $line !~ /%[a-z0-9]*ll/;
next if $line !~ /\blong\S+long\b/; # Assume a cast
print "$line\n";
if ($line =~ /^([^:]+)/) {
$names{$1} = 1;
print "$line\n";
} else {
$names{UNKNOWN} = 1;
}
}
if (keys %names) {
+1 -1
View File
@@ -99,7 +99,7 @@ int dpix_run_tests() {
static int didDump = 0;
if (didDump++ == 0) {
# ifdef TEST_VERBOSE
Verilated::scopesDump();
Verilated::internalsDump();
# endif
}
#endif
+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, 2013 by Wilson Snyder.
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 [3:0] datai = crc[3:0];
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
logic [3:0] datao; // From test of Test.v
// End of automatics
Test test (/*AUTOINST*/
// Outputs
.datao (datao[3:0]),
// Inputs
.clk (clk),
.datai (datai[3:0]));
// Aggregate outputs into a single result vector
wire [63:0] result = {60'h0, datao};
// Test loop
always @ (posedge clk) begin
`ifdef TEST_VERBOSE
$write("[%0t] cyc==%0d crc=%x result=%x\n",$time, cyc, crc, result);
`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 <= 64'h0;
end
else if (cyc<10) begin
sum <= 64'h0;
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'h3db7bc8bfe61f983
if (sum !== `EXPECTED_SUM) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module Test
(
input logic clk,
input logic [3:0] datai,
output logic [3:0] datao
);
genvar i;
parameter SIZE = 4;
logic [SIZE:1][3:0] delay;
always_ff @(posedge clk) begin
delay[1][3:0] <= datai;
end
generate
for (i = 2; i < (SIZE+1); i++) begin
always_ff @(posedge clk) begin
delay[i][3:0] <= delay[i-1][3:0];
end
end
endgenerate
always_comb datao = delay[SIZE][3:0];
endmodule
+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, 2013 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
`ifdef INLINE_A //verilator inline_module
`else //verilator no_inline_module
`endif
bmod bsub3 (.clk, .n(3));
bmod bsub2 (.clk, .n(2));
bmod bsub1 (.clk, .n(1));
bmod bsub0 (.clk, .n(0));
endmodule
module bmod
(input clk,
input [31:0] n);
`ifdef INLINE_B //verilator inline_module
`else //verilator no_inline_module
`endif
cmod csub (.clk, .n);
endmodule
module cmod
(input clk, input [31:0] n);
`ifdef INLINE_C //verilator inline_module
`else //verilator no_inline_module
`endif
reg [31:0] clocal;
always @ (posedge clk) clocal <= n;
dmod dsub (.clk, .n);
endmodule
module dmod (input clk, input [31:0] n);
`ifdef INLINE_D //verilator inline_module
`else //verilator no_inline_module
`endif
reg [31:0] dlocal;
always @ (posedge clk) dlocal <= n;
int cyc;
always @(posedge clk) begin
cyc <= cyc+1;
end
always @(posedge clk) begin
if (cyc>10) begin
`ifdef TEST_VERBOSE $display("%m: csub.clocal=%0d dlocal=%0d", csub.clocal, dlocal); `endif
if (csub.clocal !== n) $stop;
if (dlocal !== n) $stop;
end
if (cyc==99) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
top_filename("t/t_inst_dtree.v");
compile (
v_flags2 => ['+define+INLINE_A'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
top_filename("t/t_inst_dtree.v");
compile (
v_flags2 => ['+define+INLINE_A +define+INLINE_B'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
top_filename("t/t_inst_dtree.v");
compile (
v_flags2 => ['+define+INLINE_A +define+INLINE_C'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
top_filename("t/t_inst_dtree.v");
compile (
v_flags2 => ['+define+INLINE_A +define+INLINE_D'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
top_filename("t/t_inst_dtree.v");
compile (
v_flags2 => ['+define+INLINE_B'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
top_filename("t/t_inst_dtree.v");
compile (
v_flags2 => ['+define+INLINE_B +define+INLINE_C'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
top_filename("t/t_inst_dtree.v");
compile (
v_flags2 => ['+define+INLINE_B +define+INLINE_D'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
top_filename("t/t_inst_dtree.v");
compile (
v_flags2 => ['+define+INLINE_C'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
top_filename("t/t_inst_dtree.v");
compile (
v_flags2 => ['+define+INLINE_C +define+INLINE_D'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
top_filename("t/t_inst_dtree.v");
compile (
v_flags2 => ['+define+INLINE_D'],
verilator_flags2 => ['-trace'],
);
execute (
check_finished=>1,
);
ok(1);
1;
+4 -3
View File
@@ -18,16 +18,17 @@ module t (/*AUTOARG*/
reg ionewire;
`ifdef never_just_for_verilog_mode
wire oonewire; // From sub of t_inst_v2k_sub.v
wire oonewire; // From sub of t_inst_v2k__sub.v
`endif
wire [7:0] osizedreg; // From sub of t_inst_v2k_sub.v
wire [7:0] osizedreg; // From sub of t_inst_v2k__sub.v
wire [1:0] tied;
wire [3:0] tied_also;
hello hsub (.tied_also);
t_inst_v2k_sub sub
// Double underscore tests bug631
t_inst_v2k__sub sub
(
// Outputs
.osizedreg (osizedreg[7:0]),
@@ -5,7 +5,7 @@
// without warranty, 2003 by Wilson Snyder.
// This file is named .vi to test +libext+ flags.
module t_inst_v2k_sub
module t_inst_v2k__sub
(
output reg [7:0] osizedreg,
output wire oonewire /*verilator public*/,
+14 -1
View File
@@ -22,7 +22,7 @@ module t (/*AUTOARG*/
counter c1 (.clkm(clk),
.c_data(c1_data),
.i_value(4'h1));
counter c2 (.clkm(clk),
counter2 c2 (.clkm(clk),
.c_data(c2_data),
.i_value(4'h2));
@@ -66,3 +66,16 @@ module counter
c_data.value <= c_data.value + 1;
end
endmodule : counter
module counter2(clkm, c_data, i_value);
input clkm;
counter_io c_data;
input logic [3:0] i_value;
always @ (posedge clkm) begin
if (c_data.reset)
c_data.value <= i_value;
else
c_data.value <= c_data.value + 1;
end
endmodule : counter2
+1 -1
View File
@@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug102");
compile (
v_flags => ["--lint-only"]
verilator_flags2 => ["--lint-only"]
);
ok(1);
+3 -4
View File
@@ -10,13 +10,12 @@ interface counter_io;
modport core_side (output reset, input value);
endinterface
module t (/*AUTOARG*/
// Inputs
clk,
module t
(// Inputs
input clk,
counter_io.counter_side c_data
);
input clk;
integer cyc=1;
endmodule
+22
View File
@@ -0,0 +1,22 @@
#!/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 (
verilator_flags2 => ["--lint-only"],
verilator_make_gcc => 0,
make_top_shell => 0,
make_main => 0,
fails => 1,
expect=>
'%Warning-ALWCOMBORDER: t/t_lint_always_comb_bad.v:\d+: Always_comb variable driven after use: mid
.*%Error: Exiting due to.*',
);
ok(1);
1;
+48
View File
@@ -0,0 +1,48 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Wilson Snyder.
module t (/*AUTOARG*/
// Outputs
mid, o3,
// Inputs
clk, i3
);
input clk;
output logic mid;
input i3;
output logic o3;
wire [15:0] temp1;
wire [15:0] temp1_d1r;
logic setbefore;
always_comb begin
setbefore = 1'b1;
if (setbefore) setbefore = 1'b0; // fine
end
always_comb begin
if (mid)
temp1 = 'h0;
else
temp1 = (temp1_d1r - 'h1);
mid = (temp1_d1r == 'h0); // BAD
end
always_comb begin
o3 = 'h0;
case (i3)
1'b1: begin
o3 = i3;
end
default: ;
endcase
end
always_ff @ (posedge clk) begin
temp1_d1r <= temp1;
end
endmodule
+16
View File
@@ -12,6 +12,7 @@ module t (/*AUTOARG*/
reg [39:0] con1,con2, con3;
reg [31:0] w32;
reg [31:0] v32 [2];
// surefire lint_off UDDSCN
reg [200:0] conw3, conw4;
@@ -105,6 +106,21 @@ module t (/*AUTOARG*/
w32 = 12; w32 ^= 15; if (w32 != 3) $stop;
w32 = 12; w32 >>= 1; if (w32 != 6) $stop;
w32 = 12; w32 <<= 1; if (w32 != 24) $stop;
// Increments
v32[2] = 12; v32[2]++; if (v32[2] != 13) $stop;
v32[2] = 12; ++v32[2]; if (v32[2] != 13) $stop;
v32[2] = 12; v32[2]--; if (v32[2] != 11) $stop;
v32[2] = 12; --v32[2]; if (v32[2] != 11) $stop;
v32[2] = 12; v32[2] += 2; if (v32[2] != 14) $stop;
v32[2] = 12; v32[2] -= 2; if (v32[2] != 10) $stop;
v32[2] = 12; v32[2] *= 2; if (v32[2] != 24) $stop;
v32[2] = 12; v32[2] /= 2; if (v32[2] != 6) $stop;
v32[2] = 12; v32[2] &= 6; if (v32[2] != 4) $stop;
v32[2] = 12; v32[2] |= 15; if (v32[2] != 15) $stop;
v32[2] = 12; v32[2] ^= 15; if (v32[2] != 3) $stop;
v32[2] = 12; v32[2] >>= 1; if (v32[2] != 6) $stop;
v32[2] = 12; v32[2] <<= 1; if (v32[2] != 24) $stop;
end
if (cyc==2) begin
win <= 32'h123123;
+56
View File
@@ -0,0 +1,56 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Ted Campbell.
#include "Vt_order_multidriven.h"
#include "verilated.h"
#include "verilated_vcd_c.h"
Vt_order_multidriven * vcore;
VerilatedVcdC * vcd;
vluint64_t vtime;
#define PHASE_90
static void half_cycle( int clk ) {
if ( clk & 1 ) vcore->i_clk_wr = !vcore->i_clk_wr;
if ( clk & 2 ) vcore->i_clk_rd = !vcore->i_clk_rd;
vtime += 10 / 2;
vcore->eval();
vcore->eval();
vcd->dump( vtime );
}
static void cycle() {
#ifdef PHASE_90
half_cycle( 1 );
half_cycle( 2 );
half_cycle( 1 );
half_cycle( 2 );
#else
half_cycle( 3 );
half_cycle( 3 );
#endif
}
int main() {
Verilated::traceEverOn( true );
vcore = new Vt_order_multidriven;
vcd = new VerilatedVcdC;
vcore->trace( vcd, 99 );
vcd->open( "obj_dir/t_order_multidriven/sim.vcd" );
vcore->i_clk_wr = 0;
vcore->i_clk_rd = 0;
for ( int i = 0; i < 256; ++i )
cycle( );
vcd->close( );
printf("*-* All Finished *-*\n");
}
+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.
$Self->{vlt} or $Self->skip("Verilator only test");
compile (
make_top_shell => 0,
make_main => 0,
v_flags2 => ["--trace --exe $Self->{t_dir}/t_order_multidriven.cpp"],
);
execute (
check_finished=>1,
);
ok(1);
1;
+192
View File
@@ -0,0 +1,192 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Ted Campbell.
//With MULTI_CLK defined shows bug, without it is hidden
`define MULTI_CLK
//bug634
module t (
input i_clk_wr,
input i_clk_rd
);
wire wr$wen;
wire [7:0] wr$addr;
wire [7:0] wr$wdata;
wire [7:0] wr$rdata;
wire rd$wen;
wire [7:0] rd$addr;
wire [7:0] rd$wdata;
wire [7:0] rd$rdata;
wire clk_wr;
wire clk_rd;
`ifdef MULTI_CLK
assign clk_wr = i_clk_wr;
assign clk_rd = i_clk_rd;
`else
assign clk_wr = i_clk_wr;
assign clk_rd = i_clk_wr;
`endif
FooWr u_wr (
.i_clk ( clk_wr ),
.o_wen ( wr$wen ),
.o_addr ( wr$addr ),
.o_wdata ( wr$wdata ),
.i_rdata ( wr$rdata )
);
FooRd u_rd (
.i_clk ( clk_rd ),
.o_wen ( rd$wen ),
.o_addr ( rd$addr ),
.o_wdata ( rd$wdata ),
.i_rdata ( rd$rdata )
);
FooMem u_mem (
.iv_clk ( {clk_wr, clk_rd } ),
.iv_wen ( {wr$wen, rd$wen } ),
.iv_addr ( {wr$addr, rd$addr } ),
.iv_wdata ( {wr$wdata,rd$wdata} ),
.ov_rdata ( {wr$rdata,rd$rdata} )
);
endmodule
// Memory Writer
module FooWr(
input i_clk,
output o_wen,
output [7:0] o_addr,
output [7:0] o_wdata,
input [7:0] i_rdata
);
reg [7:0] cnt = 0;
// Count [0,200]
always @( posedge i_clk )
if ( cnt < 8'd50 )
cnt <= cnt + 8'd1;
// Write addr in (10,30) if even
assign o_wen = ( cnt > 8'd10 ) && ( cnt < 8'd30 ) && ( cnt[0] == 1'b0 );
assign o_addr = cnt;
assign o_wdata = cnt;
endmodule
// Memory Reader
module FooRd(
input i_clk,
output o_wen,
output [7:0] o_addr,
output [7:0] o_wdata,
input [7:0] i_rdata
);
reg [7:0] cnt = 0;
reg [7:0] addr_r;
reg en_r;
// Count [0,200]
always @( posedge i_clk )
if ( cnt < 8'd200 )
cnt <= cnt + 8'd1;
// Read data
assign o_wen = 0;
assign o_addr = cnt - 8'd100;
// Track issued read
always @( posedge i_clk )
begin
addr_r <= o_addr;
en_r <= ( cnt > 8'd110 ) && ( cnt < 8'd130 ) && ( cnt[0] == 1'b0 );
end
// Display to console 100 cycles after writer
always @( negedge i_clk )
if ( en_r ) begin
`ifdef TEST_VERBOSE
$display( "MEM[%x] == %x", addr_r, i_rdata );
`endif
if (addr_r != i_rdata) $stop;
end
endmodule
// Multi-port memory abstraction
module FooMem(
input [2 -1:0] iv_clk,
input [2 -1:0] iv_wen,
input [2*8-1:0] iv_addr,
input [2*8-1:0] iv_wdata,
output [2*8-1:0] ov_rdata
);
FooMemImpl u_impl (
.a_clk ( iv_clk [0*1+:1] ),
.a_wen ( iv_wen [0*1+:1] ),
.a_addr ( iv_addr [0*8+:8] ),
.a_wdata ( iv_wdata[0*8+:8] ),
.a_rdata ( ov_rdata[0*8+:8] ),
.b_clk ( iv_clk [1*1+:1] ),
.b_wen ( iv_wen [1*1+:1] ),
.b_addr ( iv_addr [1*8+:8] ),
.b_wdata ( iv_wdata[1*8+:8] ),
.b_rdata ( ov_rdata[1*8+:8] )
);
endmodule
// Dual-Port L1 Memory Implementation
module FooMemImpl(
input a_clk,
input a_wen,
input [7:0] a_addr,
input [7:0] a_wdata,
output [7:0] a_rdata,
input b_clk,
input b_wen,
input [7:0] b_addr,
input [7:0] b_wdata,
output [7:0] b_rdata
);
/* verilator lint_off MULTIDRIVEN */
reg [7:0] mem[0:255];
/* verilator lint_on MULTIDRIVEN */
always @( posedge a_clk )
if ( a_wen )
mem[a_addr] <= a_wdata;
always @( posedge b_clk )
if ( b_wen )
mem[b_addr] <= b_wdata;
always @( posedge a_clk )
a_rdata <= mem[a_addr];
always @( posedge b_clk )
b_rdata <= mem[b_addr];
endmodule
+4
View File
@@ -40,6 +40,10 @@ module m1;
localparam PAR1DUP = PAR1+2; // Check we propagate parameters properly
parameter PAR1 = 0;
m2 #(PAR1MINUS1) m2 ();
// Packed arrays
localparam [1:0][3:0] PACKED_PARAM = { 4'h3, 4'h6 };
initial if (PACKED_PARAM != 8'h36) $stop;
endmodule
module m2;
+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;
+38
View File
@@ -0,0 +1,38 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2012 by Wilson Snyder.
//bug505
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
a #(1) a1 ();
b #(2) b2 ();
initial begin
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
module a;
parameter ONE /*verilator public*/ = 22;
initial if (ONE != 1) $stop;
`ifdef VERILATOR
initial if ($c32("ONE") != 1) $stop;
`endif
endmodule
module b #(
parameter TWO /*verilator public*/ = 22
);
initial if (TWO != 2) $stop;
`ifdef VERILATOR
initial if ($c32("TWO") != 2) $stop;
`endif
endmodule
+19 -12
View File
@@ -9,12 +9,13 @@ module t (/*AUTOARG*/
);
input clk;
s1 s1 ();
s2 s2 ();
s3 s3 ();
s4 s4 ();
s5 s5 ();
s6 s6 ();
v95 v95 ();
v01 v01 ();
v05 v05 ();
s05 s05 ();
s09 s09 ();
a23 a23 ();
s12 s12 ();
initial begin
$finish;
@@ -22,31 +23,37 @@ module t (/*AUTOARG*/
endmodule
`begin_keywords "1364-1995"
module s1;
module v95;
integer signed; initial signed = 1;
endmodule
`end_keywords
`begin_keywords "1364-2001"
module s2;
module v01;
integer bit; initial bit = 1;
endmodule
`end_keywords
`begin_keywords "1364-2005"
module s3;
module v05;
integer final; initial final = 1;
endmodule
`end_keywords
`begin_keywords "1800-2005"
module s4;
module s05;
integer global; initial global = 1;
endmodule
`end_keywords
`begin_keywords "1800-2009"
module s5;
module s09;
integer soft; initial soft = 1;
endmodule
`end_keywords
`begin_keywords "1800-2012"
module s12;
final begin
$write("*-* All Finished *-*\n");
end
@@ -54,7 +61,7 @@ endmodule
`end_keywords
`begin_keywords "VAMS-2.3"
module s6;
module a23;
real foo; initial foo = sqrt(2.0);
endmodule
`end_keywords
+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;
+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, 2009 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
// No endian warning here
wire [7:0] pack [3:0];
initial begin
pack[0] = 8'h78;
pack[1] = 8'h88;
pack[2] = 8'h98;
pack[3] = 8'hA8;
if (pack[0] !== 8'h78) $stop;
if (pack[1] !== 8'h88) $stop;
if (pack[2] !== 8'h98) $stop;
if (pack[3] !== 8'hA8) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+19
View File
@@ -39,6 +39,14 @@ module t;
// bit vec2d[2][3];
} pack3_t;
const b4_t b4_const_a = '{1'b1, 1'b0, 1'b0, 1'b1};
// Cast to a pattern - note bits are tagged out of order
const b4_t b4_const_b = b4_t'{ b1 : 1'b0, b0 : 1'b1, b3 : 1'b1, b2 : 1'b0 };
wire b4_t b4_wire;
assign b4_wire = '{1'b1, 1'b0, 1'b1, 1'b0};
pack2_t arr[2];
initial begin
@@ -94,8 +102,19 @@ module t;
if (q != 4'b1011) $stop;
end
if (b4_const_a != 4'b1001) $stop;
if (b4_const_b != 4'b1001) $stop;
if (b4_wire != 4'b1010) $stop;
if (pat(4'b1100, 4'b1100)) $stop;
if (pat('{1'b1, 1'b0, 1'b1, 1'b1}, 4'b1011)) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
function pat(b4_t in, logic [3:0] cmp);
if (in !== cmp) $stop;
pat = 1'b0;
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 (
v_flags2 => ["--lint-only"],
verilator_make_gcc => 0,
make_top_shell => 0,
make_main => 0,
);
ok(1);
1;
+45
View File
@@ -0,0 +1,45 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Wilson Snyder.
typedef struct packed {
logic [1:0] b1;
logic [1:0] b2;
logic [1:0] b3;
logic [1:0] b4;
} t__aa_bbbbbbb_ccccc_dddddd_eee;
typedef struct packed {
logic [31:0] a;
union packed {
logic [7:0] fbyte;
t__aa_bbbbbbb_ccccc_dddddd_eee pairs;
} b1;
logic [23:0] b2;
logic [7:0] c1;
logic [23:0] c2;
logic [31:0] d;
} t__aa_bbbbbbb_ccccc_dddddd;
typedef struct packed {
logic [31:0] a;
logic [31:0] b;
logic [31:0] c;
logic [31:0] d;
} t__aa_bbbbbbb_ccccc_eee;
typedef union packed {
t__aa_bbbbbbb_ccccc_dddddd dddddd;
t__aa_bbbbbbb_ccccc_eee eee;
} t__aa_bbbbbbb_ccccc;
module t (
input t__aa_bbbbbbb_ccccc xxxxxxx_yyyyy_zzzz,
output logic [15:0] datao_pre
);
always_comb datao_pre = { xxxxxxx_yyyyy_zzzz.dddddd.b1.fbyte, xxxxxxx_yyyyy_zzzz.dddddd.c1 };
endmodule

Some files were not shown because too many files have changed in this diff Show More